SpringBoot代碼集

一、獲取Spring容器對象

1.1 實現(xiàn)BeanFactoryAware接口

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

@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 實現(xiàn)ApplicationContextAware接口

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

@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 實現(xiàn)ApplicationListener接口

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

@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注解

  • 實現(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 實現(xiàn)InitializingBean接口

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

@Service
public class BService implements InitializingBean {

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

三溢谤、自定義自己的Scope

我們都知道Spring默認支持的Scope只有兩種:

  • singleton 單例,每次從spring容器中獲取到的bean都是同一個對象憨攒。
  • prototype 多例世杀,每次從spring容器中獲取到的bean都是不同的對象。

Spring web又對Scope進行了擴展肝集,增加了:

  • RequestScope 同一次請求從spring容器中獲取到的bean都是同一個對象瞻坝。
  • SessionScope 同一個會話從spring容器中獲取到的bean都是同一個對象。

即便如此杏瞻,有些場景還是無法滿足我們的要求所刀。比如,我們想在同一個線程中從spring容器獲取到的bean都是同一個對象伐憾,該怎么辦勉痴?這就需要自定義Scope了。

3.1 第一步實現(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 類型對象轉(zhuǎn)為 T 類型對象

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

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

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

4.1 第一步绑青,定義一個實體User
@Data
public class User {
    private Long id;

    private String name;

    private Date registerDate;
}
4.2 第二步诬像,實現(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";
    }
}

請求接口時User對象中registerDate字段會被自動轉(zhuǎn)換成Date類型坏挠。

五、Enable開關(guān)

不知道你有沒有用過Enable開頭的注解邪乍,比如:EnableAsync降狠、EnableCachingEnableAspectJAutoProxy等庇楞,這類注解就像開關(guān)一樣榜配,只要在@Configuration定義的配置類上加上這類注解,就能開啟相關(guān)的功能吕晌,讓我們一起實現(xiàn)一個自己的開關(guān)蛋褥。

5.1 第一步,定義一個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("記錄請求日志");
        chain.doFilter(request, response);
        System.out.println("記錄響應(yīng)日志");
    }

    @Override
    public void destroy() {

    }
}
5.2 第二步聂使,注冊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 第四步溃论,啟動類加上@EnableLog注解

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

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市钥勋,隨后出現(xiàn)的幾起案子炬转,更是在濱河造成了極大的恐慌,老刑警劉巖算灸,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扼劈,死亡現(xiàn)場離奇詭異,居然都是意外死亡菲驴,警方通過查閱死者的電腦和手機荐吵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人先煎,你說我怎么就攤上這事贼涩。” “怎么了薯蝎?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵遥倦,是天一觀的道長。 經(jīng)常有香客問我占锯,道長袒哥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任消略,我火速辦了婚禮统诺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘疑俭。我一直安慰自己粮呢,他們只是感情好,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布钞艇。 她就那樣靜靜地躺著啄寡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪哩照。 梳的紋絲不亂的頭發(fā)上挺物,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機與錄音飘弧,去河邊找鬼识藤。 笑死,一個胖子當著我的面吹牛次伶,可吹牛的內(nèi)容都是我干的痴昧。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼冠王,長吁一口氣:“原來是場噩夢啊……” “哼赶撰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起柱彻,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤豪娜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后哟楷,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瘤载,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年卖擅,在試婚紗的時候發(fā)現(xiàn)自己被綠了鸣奔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片墨技。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖溃蔫,靈堂內(nèi)的尸體忽然破棺而出健提,到底是詐尸還是另有隱情,我是刑警寧澤伟叛,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布私痹,位于F島的核電站,受9級特大地震影響统刮,放射性物質(zhì)發(fā)生泄漏紊遵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一侥蒙、第九天 我趴在偏房一處隱蔽的房頂上張望暗膜。 院中可真熱鬧,春花似錦鞭衩、人聲如沸学搜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瑞佩。三九已至,卻和暖如春坯台,著一層夾襖步出監(jiān)牢的瞬間炬丸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工蜒蕾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留稠炬,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓咪啡,卻偏偏與公主長得像首启,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子瑟匆,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容