@Configuration與@Bean註解的原理

@Configuration與@Bean結合使用。@Configuration可理解爲用spring的時候xml裏面的<beans>標籤,@Bean可理解爲用spring的時候xml裏面的<bean>標籤。Spring Boot不是spring的加強版,所以@Configuration和@Bean同樣可以用在普通的spring項目中,而不是Spring Boot特有的,只是在spring用的時候,注意加上掃包配置。

  1. Bean註解的作用之一就是能夠管理第三方jar包內的類到容器中。 現在我們引入一個第三方的jar包,這其中的某個類,StringUtil需要注入到我們的IndexService類中,因爲我們沒有源碼,不能再StringUtil中增加@Component或者@Service註解。這時候我們可以通過使用@Bean的方式,把這個類交到Spring容器進行管理,最終就能夠被注入到IndexService實例中。
  2. 在@Configuration中被@Bean標記的方法,會被Spring進行CGLIB代理,從而進行增強。來看一下Spring中的相關源代碼實現。

@SpringBootApplication註解相當於使用@Configuration、@EnableAutoConfiguration和@ComponentScan的默認屬性@ComponentScan默認爲當前包與其子包。SpringBoot中的Spring容器在啓動的時候,會掃描當前包與子包中所有實現@Component註解或者其子類如@Configuration(找個本質上還是@Component)標記的類,認爲這些類是bean, 並且把這些bean對應的beanDefinition放到容器中進行管理。BeanDefinition是對bean的描述,裏邊存有bean的名稱,Class等基本信息。

在獲取到所有的bean defenition之後,Spring會有一些post process執行,其中一個就是ConfigurationClassPostProcessor, 在這裏,Spring會遍歷所有的bean definition, 如果發現其中有標記了@Configuration註解的,會對這個類進行CGLIB代碼,生成一個代理的類,並且把這個類設置到BeanDefenition的Class屬性中。當需要拿到這個bean的實例的時候,會從這個class屬性中拿到的Class對象進行反射,那麼最終反射出來的是代理增強後的類。

代理中對方法進行了增強?在哪方面進行了增強?對於@Bean標記的方法,返回的都是一個bean,在增強的方法中,Spring會先去容器中查看一下是否有這個bean的實例了,如果有了的話,就返回已有對象,沒有的話就創建一個,然後放到容器中。以下邊的代碼爲例。

在執行getBean(IndexService.class)對應的bean的時候,會調用indexService()方法,而因爲現在我們是在CGLIB增強的類中,indexService()方法已經被增強,Spring會先查看Spring容器中有沒有實例,此時還沒有,就new一個IndexService實例放到容器中。

在執行getBean(OrderService.class)的時候,會調用orderService()方法,這裏會調用indexService()方法,因爲現在是在增強的類中,所以此處調用的也是增強的indexService()方法,會先去容器中查看有沒有實例。現在已經有實例了,就會直接返回這個實例,不再新創建。

@Bean註解可以對第三方的某些託管給Spring容器的工具類進行定製化。在傳統配置文件方式的時候,我們需要定製某個bean的屬性,我們會使用

這些bean,既可以是我們的實體類,也可以是某些工具類的配置文件對應的類。比如說RestTemplate.在我們獲取RestTemplate對應的實例的時候,初始化這個實例的時候,會在容器中尋找配置文件對應的類,如果有的話則注入到這個類中。那麼RestTemplate實例對應的各種參數,比如說timeout時間長度等,就全部定製好了。使用@Bean註解,同樣也是達到這種目的。不過這個是在掃描的時候把bean放入到容器中,而不是讀取配置文件。前提是RestTemplate內部定義了這種兼容性的設計,即內部有地方接收這些注入的參數,並且把這些參數合理轉化到相應的屬性中。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章