關於@Configuration的作用說明
一、問題描述
在項目中,通常都會配置一個或者多個加瞭@Configuration註解的配置類,那麼@Configuration這個註解到底有神馬作用勒?
@ComponentScan("com") public class AppConfig { @Bean public TestDao testDao() { return new TestDao(); } }
public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext acc = new AnnotationConfigApplicationContext(AppConfig.class); } }
public class TestDao { public TestDao(){ System.out.println("testDao"); } }
執行上面的代碼,我們會發現當我們不加@Configuration這個註解的時候我們的TestDao 這個類還是還是會被實例化,也會打印testDao。我們的spring環境也可以正常運行。
那麼我們的@Configuration註解是來解決什麼問題的勒?
我們來看一下下面這段代碼。當我們在AppConfig中有2個方法,而且第二個方法調用瞭第一個方法。
@ComponentScan("com") public class AppConfig { @Bean public TestDao testDao() { return new TestDao(); } @Bean public TestDao1 testDao1() { testDao(); return new TestDao1(); } }
public class TestDao1 { public TestDao1(){ System.out.println("testDao1"); } }
不加@Configuration的打印結果:
加上@Configuration的打印結果:
二、分析
從表面來看,當我們不加@Configuration註解的時候,我們的TestDao會被實例化兩次,這違背瞭我們spring默認單例的設計原則,當加上我們的@Configuration註解的時候,TestDao隻被實例化瞭一次。
那麼其底層到底做瞭什麼,讓我們來深追一下spring源碼吧。
當我們解析beanAppcofig的時候,會給它的一個屬性標識為Full,表明它是一個全註解類。
然後在我們調用ConfigurationClassPostProcessor.postProcessBeanFactory()方法的時候會去判斷我們的bean工廠當中是否有bean需要進行cglib代理。
然後遍歷configBeanDefs這個map
cglib代理主要是對我們的方法進行攔截增強;當我們執行AppConfig中的方法的時候會去執行cglib代理類中的代理方法,主要就是callBacks中的方法。
isCurrentlyInvokedFactoryMethod(beanMethod))
會判斷我們的執行方法和我們的調用方法是否是同一個;如果是同一個就調用父類的方法進行new;如果不是就調用$$beanFactory.getBean()獲取。
三、總結
加上@Configuration註解主要是給我們的類加上瞭cglib代理。
在執行我們的配置類的方法時,會執行cglib代理類中的方法,其中有一個非常重要的判斷,當我們的執行方法和我們的調用方法是同一個方法時,會執行父類的方法new(cglib代理基於繼承);當執行方法和調用方法不是同一個方法時會調用beanFactory.getBean獲取。
推薦閱讀:
- Spring容器中添加bean的5種方式
- 詳解Java如何使用註解來配置Spring容器
- 關於spring中單例Bean引用原型Bean產生的問題及解決
- @Autowired自動裝配,@Bean註入@Primary,@Qualifier優先級講解
- spring的13個經典面試題