BeanFactory 的實現以及常見 ApplicationContext 實現
BeanFactory實現
DefaultListableBeanFactory
DefaultListableBeanFactory,是 BeanFactory 最重要的實現,像控制反轉和依賴注入功能,都是它來實現
下面我們試著自己實現一下Bean的注入
public class TeastBeanFactory1 { public static void main(String[] args) { // 首先我們定義一個DefaultListableBeanFactory DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // bean 的定義(class, scope, 初始化, 銷燬) AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition(); // 註冊 beanFactory.registerBeanDefinition("config", beanDefinition); for (String name : beanFactory.getBeanDefinitionNames()) { System.out.println(name); } } @Configuration static class Config { @Bean public Bean1 bean1() { return new Bean1(); } @Bean public Bean2 bean2() { return new Bean2(); } } static class Bean1 { private static final Logger log = LoggerFactory.getLogger(Bean1.class); public Bean1() { log.debug("構造 Bean1()"); } @Autowired private Bean2 bean2; public Bean2 getBean2() { return bean2; } } static class Bean2 { private static final Logger log = LoggerFactory.getLogger(Bean2.class); public Bean2() { log.debug("構造 Bean2()"); } } }
此時執行列印結果只有一個bean的名字 config
但是因為我們的程式碼中也有寫@Configuration註解,然後配置類中也進行了bean注入,為什麼沒有其他的bean呢?
這就說明我們的註解沒有被解析!!也就是說DefaultListableBeanFactory沒有解析註解的能力!
那麼怎麼能讓它的功能變得完整呢?答案就是給 BeanFactory 新增一些常用的後處理器
後處理器入門
public class TeastBeanFactory1 { public static void main(String[] args) { // 首先我們定義一個DefaultListableBeanFactory DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // bean 的定義(class, scope, 初始化, 銷燬) AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition(); // 註冊 beanFactory.registerBeanDefinition("config", beanDefinition); // 給 BeanFactory 新增一些常用的後處理器 AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory); for (String name : beanFactory.getBeanDefinitionNames()) { System.out.println(name); } } @Configuration static class Config { @Bean public Bean1 bean1() { return new Bean1(); } @Bean public Bean2 bean2() { return new Bean2(); } } static class Bean1 { private static final Logger log = LoggerFactory.getLogger(Bean1.class); public Bean1() { log.debug("構造 Bean1()"); } @Autowired private Bean2 bean2; public Bean2 getBean2() { return bean2; } } static class Bean2 { private static final Logger log = LoggerFactory.getLogger(Bean2.class); public Bean2() { log.debug("構造 Bean2()"); } } }
注意此時只是加入了後處理器,還並沒有對註解進行處理
此時的輸出只是多了幾個後處理器的bean
下面新增執行後處理器的程式碼
public class TeastBeanFactory1 { public static void main(String[] args) { // 首先我們定義一個DefaultListableBeanFactory DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // bean 的定義(class, scope, 初始化, 銷燬) AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition(); // 註冊 beanFactory.registerBeanDefinition("config", beanDefinition); // 給 BeanFactory 新增一些常用的後處理器 AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory); // BeanFactory 後處理器主要功能,補充了一些 bean 定義 // BeanFactoryPostProcessor是internalConfigurationAnnotationProcessor後處理器的型別 // 這裡就是執行這些後處理器 beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> { beanFactoryPostProcessor.postProcessBeanFactory(beanFactory); }); for (String name : beanFactory.getBeanDefinitionNames()) { System.out.println(name); } } @Configuration static class Config { @Bean public Bean1 bean1() { return new Bean1(); } @Bean public Bean2 bean2() { return new Bean2(); } } static class Bean1 { private static final Logger log = LoggerFactory.getLogger(Bean1.class); public Bean1() { log.debug("構造 Bean1()"); } @Autowired private Bean2 bean2; public Bean2 getBean2() { return bean2; } } static class Bean2 { private static final Logger log = LoggerFactory.getLogger(Bean2.class); public Bean2() { log.debug("構造 Bean2()"); } } }
輸出
現在我們將bean1和bean2都注入到了我們的beanfactory了,那我們再來試一試能否獲得到我注入到bean1中的bean2呢?
我添加了如上程式碼
執行結果
我們看到了bean1的初始化,可是bean2是null,這說明我們的Autowired註解沒有生效
我又又 運行了bean後處理器
執行結果
bean2成功獲取到
單例物件的建立時機
我們在程式碼中新增一條分割線,觀察輸出
我們看到beanfactory中注入的物件都是懶載入的
我們想讓他在呼叫之前就建立,效果如下
bean後處理器的順序
我們從程式碼的這一行的方法進去
看到了新增bean後處理器的方法
我想知道@Resource和@Autowired的執行順序
public class TeastBeanFactory1 {
public static void main(String[] args) {
// 首先我們定義一個DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// bean 的定義(class, scope, 初始化, 銷燬)
AbstractBeanDefinition beanDefinition =
BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
// 註冊
beanFactory.registerBeanDefinition("config", beanDefinition);
// 給 BeanFactory 新增一些常用的後處理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
// BeanFactory 後處理器主要功能,補充了一些 bean 定義
// BeanFactoryPostProcessor是internalConfigurationAnnotationProcessor後處理器的型別
// 這裡就是執行這些後處理器
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
// Bean 後處理器, 針對 bean 的生命週期的各個階段提供擴充套件, 例如 @Autowired @Resource ...
beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
beanFactory.preInstantiateSingletons();// 準備好所有的單例
System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
//System.out.println(beanFactory.getBean(Bean1.class).getBean2());
System.out.println(beanFactory.getBean(Bean1.class).getInter());
}
@Configuration
static class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
@Bean
public Bean3 bean3() {
return new Bean3();
}
@Bean
public Bean4 bean4() {
return new Bean4();
}
}
interface Inter {
}
static class Bean3 implements Inter {
}
static class Bean4 implements Inter {
}
static class Bean1 {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
public Bean1() {
log.debug("構造 Bean1()");
}
@Autowired
private Bean2 bean2;
public Bean2 getBean2() {
return bean2;
}
@Autowired
@Resource(name = "bean4")
private Inter bean3;
public Inter getInter() {
return bean3;
}
}
static class Bean2 {
private static final Logger log = LoggerFactory.getLogger(Bean2.class);
public Bean2() {
log.debug("構造 Bean2()");
}
}
}
我新增了兩個bean,bean3和bean4
然後向bean1中用兩種方式注入bean3和bean4,通過bean1.getInter()方法來測試優先順序
結果如下:
@Autowired優先
我又又改了一下bean後處理器的執行方法,輸出了一下後處理器
再次證明!
另外這個順序也是可以改的,通過
這樣改完順序就會改變
原因是兩個後處理器都實現了Order介面,都有一個決定優先順序的order,呼叫這個方法後就根據order重新排序了。
常見 ApplicationContext 實現
ClassPathXmlApplicationContext
類的定義
結果
FileSystemXmlApplicationContext
如何使用BeanFactory實現上述兩種ApplicationContext
AnnotationConfigApplicationContext
我們可以看到,相比較前兩種ApplicatContext,AnnotationConfigApplicationContext的bean容器中多了後處理器和config物件
正是這些後處理器幫忙識別被註解的類和方法,實現的bean注入
那麼,ClassPathXmlApplicationContext如何載入這些後處理器呢?
只需要在xml檔案中加入一行<context:annotation-config/>
AnnotationConfigServletWebServerApplicationContext
執行結果
訪問
學到了什麼
a. 常見的 ApplicationContext 容器實現
b. 內嵌容器、DispatcherServlet 的建立方法、作用