1. 程式人生 > 其它 >BeanFactory 的實現以及常見 ApplicationContext 實現

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 的建立方法、作用