SpringBoot代碼集

一、獲取Spring容器對(duì)象

1.1 實(shí)現(xiàn)BeanFactoryAware接口

實(shí)現(xiàn)BeanFactoryAware接口,然后重寫setBeanFactory方法,就能從該方法中獲取到Spring容器對(duì)象。

@Service
public class PersonService implements BeanFactoryAware {

    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    public void add() {
        Person person = (Person) beanFactory.getBean("person");
    }
}
1.2 實(shí)現(xiàn)ApplicationContextAware接口

實(shí)現(xiàn)ApplicationContextAware接口,然后重寫setApplicationContext方法,也能從該方法中獲取到Spring容器對(duì)象。

@Service
public class PersonService2 implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public void add() {
        Person person = (Person) applicationContext.getBean("person");
    }
}
1.3 實(shí)現(xiàn)ApplicationListener接口

實(shí)現(xiàn)ApplicationListener接口,需要注意的是該接口接收的泛型是ContextRefreshedEvent類,然后重寫onApplicationEvent方法,也能從該方法中獲取到Spring容器對(duì)象。

@Service
public class PersonService3 implements ApplicationListener<ContextRefreshedEvent> {

    private ApplicationContext applicationContext;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        applicationContext = event.getApplicationContext();
    }

    public void add() {
        Person person = (Person) applicationContext.getBean("person");
    }
}

二、初始化bean

Spring中支持3種初始化bean的方法:

  • xml中指定init-method方法

  • 使用@PostConstruct注解

  • 實(shí)現(xiàn)InitializingBean接口

第一種方法太古老了,現(xiàn)在用的人不多,具體用法就不介紹了。

2.1 使用@PostConstruct注解

在需要初始化的方法上增加@PostConstruct注解,這樣就有初始化的能力。

@Service
public class AService {

    @PostConstruct
    public void init() {
        System.out.println("===初始化===");
    }
}
@Component
public class AlipayUtils {

    @Resource
    private AlipayConfigIOS configIOS;

    @Resource
    private AlipayConfigAndroid configAndroid;

    public AlipayClient alipayClientIOS;

    public AlipayClient alipayClientAndroid;

    @PostConstruct
    public void init(){
       System.out.println("===初始化===");

        //構(gòu)建IOS
        alipayClientIOS = new DefaultAlipayClient(
                configIOS.getGateWay(),
                configIOS.getAppId(),
                configIOS.getAppPrivateKey(),
                configIOS.getFormat(),
                configIOS.getCharset(),
                configIOS.getAliPayPublicKey(),
                configIOS.getSignType());

        //構(gòu)建Android
        alipayClientAndroid = new DefaultAlipayClient(
                configAndroid.getGateWay(),
                configAndroid.getAppId(),
                configAndroid.getAppPrivateKey(),
                configAndroid.getFormat(),
                configAndroid.getCharset(),
                configAndroid.getAliPayPublicKey(),
                configAndroid.getSignType());
    }
}
2.2 實(shí)現(xiàn)InitializingBean接口

實(shí)現(xiàn)InitializingBean接口,重寫afterPropertiesSet方法,該方法中可以完成初始化功能。

@Service
public class BService implements InitializingBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("===初始化===");
    }
}

三、自定義自己的Scope

我們都知道Spring默認(rèn)支持的Scope只有兩種:

  • singleton 單例,每次從spring容器中獲取到的bean都是同一個(gè)對(duì)象。
  • prototype 多例,每次從spring容器中獲取到的bean都是不同的對(duì)象。

Spring web又對(duì)Scope進(jìn)行了擴(kuò)展,增加了:

  • RequestScope 同一次請(qǐng)求從spring容器中獲取到的bean都是同一個(gè)對(duì)象。
  • SessionScope 同一個(gè)會(huì)話從spring容器中獲取到的bean都是同一個(gè)對(duì)象。

即便如此,有些場景還是無法滿足我們的要求。比如,我們想在同一個(gè)線程中從spring容器獲取到的bean都是同一個(gè)對(duì)象,該怎么辦?這就需要自定義Scope了。

3.1 第一步實(shí)現(xiàn)Scope接口
public class ThreadLocalScope implements Scope {

    private static final ThreadLocal THREAD_LOCAL_SCOPE = new ThreadLocal();

    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Object value = THREAD_LOCAL_SCOPE.get();
        if (value != null) {
            return value;
        }

        Object object = objectFactory.getObject();
        THREAD_LOCAL_SCOPE.set(object);
        return object;
    }

    @Override
    public Object remove(String name) {
        THREAD_LOCAL_SCOPE.remove();
        return null;
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {

    }

    @Override
    public Object resolveContextualObject(String key) {
        return null;
    }

    @Override
    public String getConversationId() {
        return null;
    }
}
3.2 第二步將新定義的Scope注入到Spring容器中
@Component
public class ThreadLocalBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        beanFactory.registerScope("threadLocalScope", new ThreadLocalScope());
    }
}
3.3 第三步使用新定義的Scope
@Scope("threadLocalScope")
@Service
public class CService {

    public void add() {
    }
}

四、自定義類型轉(zhuǎn)換

Spring目前支持3種類型轉(zhuǎn)換器:

  • Converter<S,T>:將 S 類型對(duì)象轉(zhuǎn)為 T 類型對(duì)象

  • ConverterFactory<S, R>:將 S 類型對(duì)象轉(zhuǎn)為 R 類型及子類對(duì)象

  • GenericConverter:它支持多個(gè)source和目標(biāo)類型的轉(zhuǎn)化,同時(shí)還提供了source和目標(biāo)類型的上下文,這個(gè)上下文能讓你實(shí)現(xiàn)基于屬性上的注解或信息來進(jìn)行類型轉(zhuǎn)換。

這3種類型轉(zhuǎn)換器使用的場景不一樣,我們以Converter<S,T>為例。假如:接口中接收參數(shù)的實(shí)體對(duì)象中,有個(gè)字段的類型是Date,但是實(shí)際傳參的是字符串類型:2021-01-03 10:20:15,要如何處理呢?

4.1 第一步,定義一個(gè)實(shí)體User
@Data
public class User {
    private Long id;

    private String name;

    private Date registerDate;
}
4.2 第二步,實(shí)現(xiàn)Converter接口
public class DateConverter implements Converter<String, Date> {

  private static final String dateFormat = "yyyy-MM-dd HH:mm:ss";

  private static final String shortDateFormat = "yyyy-MM-dd";

    @Override
    public Date convert(String source) {
      if(StringUtils.isEmpty(value)) {
          return null;
      }

      value = value.trim();

      try {
          if(value.contains("-")) {
              SimpleDateFormat formatter;
              if(value.contains(":")) {
                  formatter = new SimpleDateFormat(dateFormat);
              }else {
                  formatter = new SimpleDateFormat(shortDateFormat);
              }

              Date dtDate = formatter.parse(value);
              return dtDate;              
          }else if(value.matches("^\\d+$")) {
              Long lDate = new Long(value);
              return new Date(lDate);
          }
      } catch (Exception e) {
          throw new RuntimeException(String.format("parser %s to Date fail", value));
      }

      throw new RuntimeException(String.format("parser %s to Date fail", value));
    }
}
4.3 第三步,將新定義的類型轉(zhuǎn)換器注入到Spring容器中
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new DateConverter());
    }
}
4.4 第四步,調(diào)用接口
@RequestMapping("/user")
@RestController
public class UserController {

    @RequestMapping("/save")
    public String save(@RequestBody User user) {
        return "success";
    }
}

請(qǐng)求接口時(shí)User對(duì)象中registerDate字段會(huì)被自動(dòng)轉(zhuǎn)換成Date類型。

五、Enable開關(guān)

不知道你有沒有用過Enable開頭的注解,比如:EnableAsyncEnableCaching、EnableAspectJAutoProxy等,這類注解就像開關(guān)一樣,只要在@Configuration定義的配置類上加上這類注解,就能開啟相關(guān)的功能,讓我們一起實(shí)現(xiàn)一個(gè)自己的開關(guān)。

5.1 第一步,定義一個(gè)LogFilter
public class LogFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("記錄請(qǐng)求日志");
        chain.doFilter(request, response);
        System.out.println("記錄響應(yīng)日志");
    }

    @Override
    public void destroy() {

    }
}
5.2 第二步,注冊(cè)LogFilter
@ConditionalOnWebApplication
public class LogFilterWebConfig {

    @Bean
    public LogFilter timeFilter() {
        return new LogFilter();
    }
}

注意,這里用了@ConditionalOnWebApplication注解,沒有直接使用@Configuration注解。

5.3 第三步,定義開關(guān)@EnableLog注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(LogFilterWebConfig.class)
public @interface EnableLog {

}
5.4 第四步,啟動(dòng)類加上@EnableLog注解

只需在Springboot啟動(dòng)類加上@EnableLog注解即可開啟LogFilter記錄請(qǐng)求和響應(yīng)日志的功能。

轉(zhuǎn)載自:Spring 那些讓你愛不釋手的代碼技巧

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容