spring底层实现-1-BeanFactory与applicationContext的功能与实现

spring容器的常见接口与功能

BeanFactory与ApplicationContext的关系

BeanFactory是 ApplicationContext 的父接口,它才是 Spring 的核心容器, 主要的 ApplicationContext 实现都【组合】了它的功能

 另一方面,BeanFactory是ApplicationContext一个成员变量

BeanFactory的功能

 

 表面上只有 getBean,实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能, 都由它的实现类提供

ApplicationContext 比 BeanFactory 多点啥

applicationContext对beanfactory的功能拓展主要体现在四个扩展接口:MessageSource(国际化)、ResourcePatternResolver(通配符方式获取一组 Resource 资源 )、ApplicationEventPublisher(事件发布与监听,实现组件之间的解耦 )、EnvironmentCapable上(整合 Environment 环境(能通过它获取各种来源的配置信息))

MessageSource(国际化)

System.out.println(context.getMessage("hi", null, Locale.CHINA));
System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
System.out.println(context.getMessage("hi", null, Locale.JAPANESE));

可以通过浏览器的请求头获取这个信息 ,根据用户的使用需求返回规定的语言

ResourcePatternResolver

通过通配符获取一系列资源。 

    Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
        for (Resource resource : resources) {
            System.out.println(resource);
        }

EnvironmentCapable

获取来自环境变量或者properties配置文件的配置信息。

        System.out.println(context.getEnvironment().getProperty("java_home"));
        System.out.println(context.getEnvironment().getProperty("server.port"));

ApplicationEventPublisher

 用于发布或者监听事件,spring中任何一个组件都可以作为监听器

//发布事件
context.publishEvent(new UserRegisteredEvent(context));


//监听事件
@EventListener
    public void aaa(UserRegisteredEvent event) {
        log.debug("{}", event);
        log.debug("发送短信");
    }

事件可以用于解耦功能,比如,对于一个注册功能,在注册成功之后可能需要发送短信、可能需要返回信息,可能两者都需要,不同的业务或者使用场景会有不一样的使用要求,这时候就不能在一个方法里面吧注册功能写死了,可以发事件:先获取事件发布器,然后发布事件

@Autowired
    private ApplicationEventPublisher context;

    public void register() {
        log.debug("用户注册");
        context.publishEvent(new UserRegisteredEvent(this));
    }

接着另一个业务监听到事件之后就去执行相应的业务,做到注册功能和后续功能的解耦合。

@EventListener
    public void aaa(UserRegisteredEvent event) {
        log.debug("{}", event);
        log.debug("发送短信");
    }

spring容器的实现

BeanFactory的实现

BeanFactory的实现之一:DefaultListableBeanFactory,这个实现获得的对象是一个bean容器,先创建一个实例对象得到spring核心容器

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

 一开始创建好里面是没有任何的bean的,所以需要给这个BeanFactory添加一些bean的定义,不是直接添加对象,因为对象是BeanFactory帮你创建的,所以你需要告诉的是bean的信息,bean 的定义(class, scope, 初始化, 销毁),再有BeanFactory根据定义创建对象。

例如,我们有如下的类和类的依赖引用关系

 @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()");
        }
    }
}
AbstractBeanDefinition beanDefinition =
                BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
        beanFactory.registerBeanDefinition("config", beanDefinition);

这一段代码是创建了一个config类的bean,并且把这个bean放到了bean容器beanFactory中,通过打印bean容器发现此时容器里只有一个config对象的信息,并没有把bean1和bean2的信息加入到容器中,即没有解析config类中的注解,是因为解析注解并不是有BeanDefinition完成,需要另外一个工具类——BeanFactory后处理器,后处理器可以扩展beanfactory功能,例如解析注解

先把常用的后处理器放入bean工厂,让bean工厂有这么些个bean,但是如果要用到这些后处理器还需要建立这些处理器与beanFactory的联系并执行。

// 给 BeanFactory 添加一些常用的后处理器
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

添加后处理器之后需要运行该后处理器:因为处理器是beanfactory对象,所以要先把这些对象获取了,然后再去执行

        // BeanFactory 后处理器主要功能,补充了一些 bean 定义
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });

此时去打印beanFactory中的bean就可以发现里面是把bean1和bean2的信息也创建并加入进容器了。

这时候根据getBean(Bean1.class).getBean2()会发现返回值是一个null,即Bean1类中的@Autowired注解失效 ,没有创建出bean2对象这个依赖注解还需要Bean后处理器来解决。

 

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

因为beanFactory一开始只是在容器中存放各个bean的信息,只有当getBean的时候才会去创建bean对象,而有时候我们为了性能考虑会像提前把bean对象创建好,这时候就可以用到下面这个方法

beanFactory.preInstantiateSingletons(); // 准备好所有单例

 总结:beanFactory 不会做的事

1. 不会主动调用 BeanFactory 后处理器

2. 不会主动添加 Bean 后处理器

3. 不会主动初始化单例

4. 不会解析beanFactory 还不会解析 ${ } 与 #{ }

ApplicationContext的实现

 四个比较经典的实现类:

ClassPathXmlApplicationContext

到类路径下读取配置文件 

    // ⬇️较为经典的容器, 基于 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());
    }

 

FileSystemXmlApplicationContext

// ⬇️基于磁盘路径下 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());
    }

 上面这两个类的实现原理是借助了DefaultListableBeanFactory,读取xml文件,把读取到的bean信息形成bean放入bean工厂里面

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        System.out.println("读取之前...");
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println("读取之后...");
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        reader.loadBeanDefinitions(new FileSystemResource("src\\main\\resources\\a02.xml"));
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }

AnnotationConfigApplicationContext

基于注解配置的实现

    private static void testAnnotationConfigServletWebServerApplicationContext() {
        AnnotationConfigServletWebServerApplicationContext context =
                new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }


     @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;
        }
    }

AnnotationConfigServletWebServerApplicationContext

较为经典的容器, 基于 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;
            };
        }
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值