1. 程式人生 > 其它 >Spring原始碼(2)注入

Spring原始碼(2)注入

Spring採用IoC的思想,實現IoC思想的關鍵在於採用了注入的方式進行控制反轉,在Spring中,注入有很多形式,這裡只說明依賴注入方法注入自動注入三種。

1 依賴注入

根據官網介紹,依賴注入主要分為兩種方式

  1. 建構函式注入
  2. Setter方法注入

1.1 建構函式注入

@Component
public class OneDao {

    public OneDao() {
        System.out.println("Dao無參建構函式已經呼叫");
    }

}
@Component
public class OneService {
    private OneDao oneDao;


    public OneService() {
        System.out.println("OneService無參建構函式已經被呼叫");
    }

    public OneService(OneDao oneDao) {
        System.out.println("OneService正在使用建構函式注入oneDao");
        this.oneDao = oneDao;
        System.out.println("OneService有參建構函式已經被呼叫");
    }

    public void test(){
        System.out.println(oneDao);
    }
}
@Configuration
public class Config {

    @Bean
    public OneDao oneDao(){
        OneDao oneDao = new OneDao();
        return oneDao;
    }

    @Bean
    public OneService oneService(){
        OneService oneService = new OneService(oneDao());
        return oneService;
    }
}
public class ComponentMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
        OneService oneService = (OneService) applicationContext.getBean("oneService");
        System.out.println(oneService);
    }
}

1.2 setter注入

@Component
public class OneDao {

    public OneDao() {
        System.out.println("Dao無參建構函式已經呼叫");
    }

}
@Component
public class OneService {
    private OneDao oneDao;


    public OneService() {
        System.out.println("OneService無參建構函式已經被呼叫");
    }

    public void test(){
        System.out.println(oneDao);
    }

    @Autowired   //一定要加@Autowired ,否則預設不進行set注入
    public void setOneDao(OneDao oneDao) {
        System.out.println("正在使用setter進行注入OneDao");
        this.oneDao = oneDao;
    }
}
@Configuration
public class Config {

    @Bean
    public OneDao oneDao(){
        OneDao oneDao = new OneDao();
        return oneDao;
    }

    @Bean
    public OneService oneService(){
        OneService oneService = new OneService();
        return oneService;
    }
}
public class ComponentMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
        OneService oneService = (OneService) applicationContext.getBean("oneService");
        System.out.println(oneService);
    }
}

tips:

@Autowired直接加到欄位上跟加到set方法上有什麼區別?為什麼我們驗證的時候需要將其新增到setter方法上?

  • 直接新增@Autowired註解到欄位上,不需要提供setter方法也能完成注入。

1.3 同時採用構造注入加setter注入

構造注入在bean例項化階段完成了,而後會呼叫setter注入,會對前面的構造注入進行覆蓋。

2 方法注入

方法注入,是為了解決原型失效的問題。不管是setter注入還是建構函式注入,已經完成了該bean的依賴注入,後續不能進行依賴的修改。在使用該bean的時候,獲得的還是依賴屬性的單例,這樣就失去了原型的作用。為了解決這個問題,出現了方法注入,在方法中對原型的bean進行重新獲取和注入。

問題:

@Component
@Scope("prototype")
public class OneDao {

    public OneDao() {
        System.out.println("Dao無參建構函式已經呼叫");
    }

    int i;
    public void addAndPrint(int a){
        i = i + a;
        System.out.println(i);
    }

}
@Component
public class OneService {
    @Autowired
    private OneDao oneDao;


    public OneService() {
        System.out.println("OneService無參建構函式已經被呼叫");
    }

    public void test(int a){
        oneDao.addAndPrint(a);
    }

}
@Configuration
public class Config {

    @Bean
    public OneDao oneDao(){
        OneDao oneDao = new OneDao();
        return oneDao;
    }

    @Bean
    public OneService oneService(){
        OneService oneService = new OneService();
        return oneService;
    }
}
public class ComponentMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
        OneService oneService = (OneService) applicationContext.getBean("oneService");
        oneService.test(1);
        oneService.test(2);
        oneService.test(3);
    }
}

問題:本來定義了OneDao類是一個原型的類,那麼在OneService中應該獲取的都是最新的OneDao物件,然後再呼叫其中的方法,預期結果應該是1,2,3,但是真是結果是1,3,6,這因為在OneService中已經完成OneDao的依賴注入,在測試的時候使用的始終是一個OneDao物件。

​ 解決這個問題,就可以通過方法注入的方式,每次都獲取最新的OneDao物件即可。

  1. 通過注入applicationContext物件

    @Component
    public class OneService{
        @Autowired
        private ApplicationContext applicationContext;
    
        public OneService() {
            System.out.println("OneService無參建構函式已經被呼叫");
        }
    
        public void test(int a){
            OneDao oneDao = ((OneDao) applicationContext.getBean("oneDao"));
            oneDao.addAndPrint(a);
        }
    
    }
    
  2. 通過@LookUp的方式

@Component
public class OneService{
    public OneService() {
        System.out.println("OneService無參建構函式已經被呼叫");
    }

    public void test(int a){
        OneDao oneDao = lookUp();
        oneDao.addAndPrint(a);
    }

    @Lookup
    public OneDao lookUp(){
        return null;
    }
}

3 自動注入

自動注入和精確注入:所謂精確注入就是指通過建構函式或者setter方法指定了我們物件之間的依賴,也就是依賴注入,然後Spring根據我們指定的依賴關係,精確的給我們完成了注入。

​ 那麼自動注入就是spring根據型別或者beanName自動幫我們進行注入。

注入模型:

官網給我們介紹了自動注入的四種模型,如圖:

4 總結