美文网首页@IT·互联网
BeanFactory和ApplicationContext

BeanFactory和ApplicationContext

作者: 我可能是个假开发 | 来源:发表于2023-12-18 09:16 被阅读0次

一、类图

@SpringBootApplication
public class SpringDemoApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringDemoApplication.class, args);
    }
}
image.png
image.png
BeanFactory 接口
  • 典型功能有:getBean

ApplicationContext 接口
是 BeanFactory 的子接口。它扩展了 BeanFactory 接口的功能,如:

  • 国际化
  • 通配符方式获取一组 Resource 资源
  • 整合 Environment 环境(能通过它获取各种来源的配置信息)
  • 事件发布与监听,实现组件之间的解耦

二、ApplicationContext

DefaultSingletonBeanRegistry:管理所有的单例对象

@SpringBootApplication
public class SpringDemoApplication {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringDemoApplication.class, args);
       /*
         BeanFactory:
         - 表面上只有 getBean
         - 实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能, 都由它的实现类提供
         */
        Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
        singletonObjects.setAccessible(true);
        ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
        Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
        map.entrySet().forEach(e -> System.out.println(e.getKey() + "=" + e.getValue()));
    }
}

1.国际化

public class TestMessageSource {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();

        context.registerBean("messageSource", MessageSource.class, () -> {
            ResourceBundleMessageSource ms = new ResourceBundleMessageSource();
            ms.setDefaultEncoding("utf-8");
            ms.setBasename("messages");
            return ms;
        });

        context.refresh();

        System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
        System.out.println(context.getMessage("hi", null, Locale.CHINESE));
        System.out.println(context.getMessage("hi", null, Locale.JAPANESE));
    }
}
  • ApplicationContext 中 MessageSource bean 的名字固定为 messageSource
  • 使用 SpringBoot 时,国际化文件名固定为 messages
  • 空的 messages.properties 也必须存在
  • 国际化文件均在 src/resources 目录下

2.通配符方式获取一组 Resource 资源

@SpringBootApplication
public class SpringDemoApplication {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringDemoApplication.class, args);
        Resource[] resources = applicationContext.getResources("classpath*:META-INF/spring.factories");
        for (Resource resource : resources) {
            System.out.println(resource);
        }
    }
}
URL [jar:file:/Users/hongcaixia/Documents/work/repository/org/springframework/boot/spring-boot/2.5.6/spring-boot-2.5.6.jar!/META-INF/spring.factories]
URL [jar:file:/Users/hongcaixia/Documents/work/repository/org/springframework/spring-beans/5.3.12/spring-beans-5.3.12.jar!/META-INF/spring.factories]
URL [jar:file:/Users/hongcaixia/Documents/work/repository/org/springframework/boot/spring-boot-autoconfigure/2.5.6/spring-boot-autoconfigure-2.5.6.jar!/META-INF/spring.factories]

3.EnvironmentCapable:获取配置信息

@SpringBootApplication
public class SpringDemoApplication {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringDemoApplication.class, args);
        System.out.println(applicationContext.getEnvironment().getProperty("JAVA_HOME"));
        System.out.println(applicationContext.getEnvironment().getProperty("server.port"));
    }
}

4.发布事件:ApplicationEventPublisher

发布者:

@SpringBootApplication
public class SpringDemoApplication {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringDemoApplication.class, args);
        applicationContext.publishEvent(new UserRegisteredEvent(applicationContext));
    }
}
public class UserRegisteredEvent extends ApplicationEvent {
    public UserRegisteredEvent(Object source) {
        super(source);
    }
}

订阅者:

@Component
public class SubComponent {
    private static final Logger log = LoggerFactory.getLogger(SubComponent.class);
    @EventListener
    public void sub(UserRegisteredEvent event) {
        log.debug("订阅:{}", event);
    }
}
2023-12-11 10:43:03.772  INFO 89813 --- [           main] com.hcx.springdemo.SubComponent          : 订阅:com.hcx.springdemo.UserRegisteredEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@477b4cdf, started on Mon Dec 11 10:43:03 CST 2023]

三、BeanFactory的实现

DefaultListableBeanFactory:

package com.hcx.springdemo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;

import javax.annotation.Resource;

public class BeanFactoryTest {

    public static void main(String[] args) {
        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 定义
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
            //执行bean工厂的后置处理器
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });

        // Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
                .sorted(beanFactory.getDependencyComparator())
                .forEach(beanPostProcessor -> {
            System.out.println(">>>>" + beanPostProcessor);
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        });

        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        // 提前创建好所有的单例bean
        beanFactory.preInstantiateSingletons();
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
//        System.out.println(beanFactory.getBean(Bean1.class).getBean2());
        System.out.println(beanFactory.getBean(Bean1.class).getInter());
        /*
            beanFactory 不会做的事
                   1. 不会主动调用 BeanFactory 后处理器
                   2. 不会主动添加 Bean 后处理器
                   3. 不会主动初始化单例
                   4. 不会解析beanFactory 还不会解析 ${ } 与 #{ }
            bean 后处理器会有排序的逻辑
         */

        System.out.println("Common:" + (Ordered.LOWEST_PRECEDENCE - 3));
        System.out.println("Autowired:" + (Ordered.LOWEST_PRECEDENCE - 2));
    }

    @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()");
        }
    }
}

  • beanFactory 可以通过 registerBeanDefinition 注册一个 bean definition 对象
    配置类、xml、组件扫描等方式都是生成 bean definition 对象注册到 beanFactory 当中
    bean definition 描述了这个 bean 的创建蓝图:scope 是什么、用构造还是工厂创建、初始化销毁方法是什么,等等
  • beanFactory 需要手动调用 beanFactory 后处理器对它做增强
    通过解析 @Bean、@ComponentScan 等注解,来补充一些 bean definition
  • beanFactory 需要手动添加 bean 后处理器,以便对后续 bean 的创建过程提供增强
    @Autowired,@Resource 等注解的解析都是 bean 后处理器完成的
    bean 后处理的添加顺序会对解析结果有影响,@Autowired,@Resource 等
  • beanFactory 需要手动调用方法来初始化单例
  • beanFactory 需要额外设置才能解析 ${} 与 #{}

四、ApplicationContext 实现

  • ClassPathXmlApplicationContext:基于classpath下 xml 格式的配置文件来创建
  • FileSystemXmlApplicationContext:基于磁盘路径下 xml 格式的配置文件来创建
  • AnnotationConfigApplicationContext:基于 java 配置类来创建
  • AnnotationConfigServletWebServerApplicationContext: 基于 java 配置类来创建, 用于 web 环境
package com.hcx.springdemo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.FileSystemResource;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.mvc.Controller;

/*
    常见 ApplicationContext 实现
 */
public class ApplicationContextTest {
    private static final Logger log = LoggerFactory.getLogger(ApplicationContextTest.class);

    public static void main(String[] args) {
        // 1.基于 classpath 下 xml 格式的配置文件来创建
        testClassPathXmlApplicationContext();
        // 2..基于磁盘路径下 xml 格式的配置文件来创建
        testFileSystemXmlApplicationContext();

        //ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext 相当于:在beanFactory上进行的如下增强
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        System.out.println("读取之前...");
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println("读取之后...");
        // 把bean标签转换成bean定义,将读取结果放入beanFactory
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        // 读取
        reader.loadBeanDefinitions(new FileSystemResource("src\\main\\resources\\a02.xml"));
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }


        // 3.基于 java 配置类来创建
        testAnnotationConfigApplicationContext();
        // 4.基于 java 配置类来创建, 用于 web 环境
        testAnnotationConfigServletWebServerApplicationContext();

    }

    // 1.️较为经典的容器, 基于 classpath 下 xml 格式的配置文件来创建
    private static void testClassPathXmlApplicationContext() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("a02.xml");

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        System.out.println(context.getBean(Bean2.class).getBean1());
    }

    // 2.基于磁盘路径下 xml 格式的配置文件来创建
    private static void testFileSystemXmlApplicationContext() {
        // 绝对路径或者相对路径
        FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src\\main\\resources\\a02.xml");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        System.out.println(context.getBean(Bean2.class).getBean1());
    }

    // 3.较为经典的容器, 基于 java 配置类来创建;已经加好了对应的后置处理器
    private static void testAnnotationConfigApplicationContext() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        System.out.println(context.getBean(Bean2.class).getBean1());
    }


    // 4.️较为经典的容器, 基于 java 配置类来创建, 用于 web 环境
    private static void testAnnotationConfigServletWebServerApplicationContext() {
        AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }

    @Configuration
    static class WebConfig {
        @Bean
        public ServletWebServerFactory servletWebServerFactory(){
            return new TomcatServletWebServerFactory();
        }
        @Bean
        public DispatcherServlet dispatcherServlet() {
            return new DispatcherServlet();
        }
        @Bean
        public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
            return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
        }
        @Bean("/hello")
        public Controller controller1() {
            return (request, response) -> {
                response.getWriter().print("hello");
                return null;
            };
        }
    }

    /**
     * 配置类也是一个bean
     */
    @Configuration
    static class Config {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2(Bean1 bean1) {
            Bean2 bean2 = new Bean2();
            bean2.setBean1(bean1);
            return bean2;
        }
    }

    static class Bean1 {
    }

    static class Bean2 {

        private Bean1 bean1;

        public void setBean1(Bean1 bean1) {
            this.bean1 = bean1;
        }

        public Bean1 getBean1() {
            return bean1;
        }
    }
}

相关文章

网友评论

    本文标题:BeanFactory和ApplicationContext

    本文链接:https://www.haomeiwen.com/subject/tunugdtx.html