spring中@Lookup的作用


情景分析

  在Spring的諸多應用場景中bean都是單例形式,當一個單利bean需要和一個非單利bean組合使用或者一個非單利bean和另一個非單利bean組合使用時,我們通常都是將依賴以屬性的方式放到bean中來引用,然后以@Autowired來標記需要注入的屬性。但是這種方式在bean的生命周期不同時將會出現很明顯的問題,假設單利bean A需要一個非單利bean B(原型),我們在A中注入bean B,每次調用bean A中的方法時都會用到bean B,我們知道Spring Ioc容器只在容器初始化時執行一次,也就是bean A中的依賴bean B只有一次注入的機會,但是實際上bean B我們需要的是每次調用方法時都獲取一個新的對象(原型)所以問題明顯就是:我們需要bean B是一個原型bean,而事實上bean B的依賴只注入了一次變成了事實上的單利bean。

  

代碼示例:

@Component
@Scope("prototype")
public class PrototypeBean {
    private static final Logger logger= LoggerFactory.getLogger(PrototypeBean.class);
    
    public void say() {
        logger.info("say something...");
    }
}
@Component
public class SingletonBean {
    private static final Logger logger = LoggerFactory.getLogger(SingletonBean.class);
    
    @Autowired
    private PrototypeBean bean;
    
    public void print() {
        logger.info("Bean SingletonBean's HashCode : {}",bean.hashCode());
        bean.say();
    }
}
@SpringBootApplication
public class SampleApplication {
    private static final Logger logger = LoggerFactory.getLogger(SampleApplication.class);
    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }

    @Bean 
public CommandLineRunner test(final SingletonBean bean) { return (args)-> { logger.info("測試單例bean和原型bean的調用"); int i =0; while(i<3) { i++; bean.print(); } }; } }

結果

2018-12-06 15:04:29,721 INFO :-- [main .. ] o.s.SampleApplication 測試單例bean和原型bean的調用 
2018-12-06 15:04:29,723 INFO :-- [main .. ] o.s.a.SingletonBean Bean SingletonBean's HashCode : 1713129148 
2018-12-06 15:04:29,723 INFO :-- [main .. ] o.s.a.PrototypeBean say something... 
2018-12-06 15:04:29,723 INFO :-- [main .. ] o.s.a.SingletonBean Bean SingletonBean's HashCode : 1713129148 
2018-12-06 15:04:29,724 INFO :-- [main .. ] o.s.a.PrototypeBean say something... 
2018-12-06 15:04:29,724 INFO :-- [main .. ] o.s.a.SingletonBean Bean SingletonBean's HashCode : 1713129148 
2018-12-06 15:04:29,724 INFO :-- [main .. ] o.s.a.PrototypeBean say something...

  我們看到每次輸出PrototypeBean的HashCode都是一樣的,證明我們實際上並沒有達到使用原型bean的目的。

 

解決方案

  1. 在bean A中引入ApplicationContext每次調用方法時用上下文的getBean(name,class)方法去重新獲取bean B的實例。
  2. 使用@Lookup注解。
    這兩種解決方案都能解決我們遇到的問題,但是第二種相對而言更簡單。以下給出兩種解決方案的代碼示例。

   通過應用上下文ApplicationContext獲取獲取

    

@Component
public class SingletonBean {
    private static final Logger logger = LoggerFactory.getLogger(SingletonBean.class);
    
    @Autowired
    private ApplicationContext context;
    
    public void print() {
        //每次都從ApplicatonContext中獲取新的bean引用
        PrototypeBean bean = this.context.getBean("prototypeBean",PrototypeBean.class);
        logger.info("Bean SingletonBean's HashCode : {}",bean.hashCode());
        bean.say();
    }
}    

  結果

2018-12-06 15:10:01,485 INFO :-- [main .. ] o.s.SampleApplication 測試單例bean和原型bean的調用 
2018-12-06 15:10:01,487 INFO :-- [main .. ] o.s.a.SingletonBean Bean SingletonBean's HashCode : 376601041 
2018-12-06 15:10:01,487 INFO :-- [main .. ] o.s.a.PrototypeBean say something... 
2018-12-06 15:10:01,487 INFO :-- [main .. ] o.s.a.SingletonBean Bean SingletonBean's HashCode : 2056499811 
2018-12-06 15:10:01,487 INFO :-- [main .. ] o.s.a.PrototypeBean say something... 
2018-12-06 15:10:01,488 INFO :-- [main .. ] o.s.a.SingletonBean Bean SingletonBean's HashCode : 890733699 
2018-12-06 15:10:01,488 INFO :-- [main .. ] o.s.a.PrototypeBean say something... 

  

  通過@Lookup注解實現方法注入

  使用方法注入的方法需要滿足以下語法要求

<public|protected> [abstract] <return-type> theMethodName(no-arguments);

  public|protected要求方法必須是可以被子類重寫和調用的
  abstract可選,如果是抽象方法,CGLIB的動態代理類就會實現這個方法,如果不是抽象方法,就會覆蓋這個方法
  return-type是非單例的類型
  no-arguments不允許有參數

 

@Component
public class SingletonBean {
    private static final Logger logger = LoggerFactory.getLogger(SingletonBean.class);
    
    public void print() {
        PrototypeBean bean = getPrototypeBean().printClass();
        logger.info("Bean SingletonBean's HashCode : {}",bean.hashCode());
        bean.say();
    }
    // 也可以寫成 @Lookup("prototypeBean") 來指定需要注入的bean
    @Lookup
    public PrototypeBean getPrototypeBean(){
      reutrn null;
    }
}

  結果:

  

2018-12-06 15:18:50,105 INFO :-- [main .. ] o.s.SampleApplication 測試單例bean和原型bean的調用 
2018-12-06 15:18:50,108 INFO :-- [main .. ] o.s.a.SingletonBean Bean SingletonBean's HashCode : 1349373781 
2018-12-06 15:18:50,108 INFO :-- [main .. ] o.s.a.PrototypeBean say something... 
2018-12-06 15:18:50,108 INFO :-- [main .. ] o.s.a.SingletonBean Bean SingletonBean's HashCode : 1046820071 
2018-12-06 15:18:50,109 INFO :-- [main .. ] o.s.a.PrototypeBean say something... 
2018-12-06 15:18:50,109 INFO :-- [main .. ] o.s.a.SingletonBean Bean SingletonBean's HashCode : 1722645488 
2018-12-06 15:18:50,110 INFO :-- [main .. ] o.s.a.PrototypeBean say something... 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM