Spring高级49讲-第二讲:容器实现

第二讲:容器实现

目录

学习目标

一、BeanFactory实现

         1.BeanFactory后处理器 --解决一些bean的定义

2.Bean后处理器 --针对bean的声明周期各个阶段提供扩展  例如@Autowired @Resource注解

3.初始化单例对象

4.bean后处理器的排序的逻辑

二、ApplicationContext的实现

 2.1 ClassPathXmlApplicationContext 基于classpath下的xml格式的配置文件

 2.2 FileSystemXmlApplicationContext  基于磁盘路径下的xml格式的配置文件

 2.3 AnnotationConfigApplicationContext  注解配置的容器

2.4 AnnotationConfigServletWebServerApplicationContext  web容器

总结



学习目标

1.BeanFactory的实现特点

2.ApplicationContext的常见实现和用法

3.内嵌容器、注册DispatcherServlet

一、BeanFactory实现

package com.itheima.a02;

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 TestBeanFactory {
    public static void main(String[] args) {
        //BeanFactory的实现  ---默认Bean工厂单子  核心容器beanFactory
        DefaultListableBeanFactory beanFactory =new DefaultListableBeanFactory();
        //因为beanFactory刚才是创建的时候是没有bean的,因此我要定义好bean 在容器中
        //bean的定义  class scope  初始化方法  销毁方法 等等  --类似于配置文件中配置bean
         // BeanDefinitionBuilder ---bean定义的构建者   genericBeanDefinition--通用的Bean定义
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
        //将bean的 bean的定义模板对象   注册到beanFactory容器中
        beanFactory.registerBeanDefinition("config",beanDefinition);
        //将beanFactory容器中的 bean定义名字进行遍历
        for (String s : beanFactory.getBeanDefinitionNames()) {
            System.out.println(s);
        }


    }

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

结果为:  

我们发现config类中 设置了@Bean 为什么没有的   ---因为现在beanFactory是没有解析 @Configuration和@Bean注解的能力的

1.BeanFactory后处理器 --解决一些bean的定义

加入这段代码后

  //AnnotationConfigUtils 注解配置工具类
        //registerAnnotationConfigProcessors  注册注解配置处理器
        //---给beanFactory  添加一些常用的后处理器
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

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

出现的结果是

但是我们发现  加入这些后处理器,结果并没有出现  @Bean注解下的类  

这是因为  上面这段代码只是将 后处理器加入到BeanFactory中  并没有进行运行

加入这段代码  将后处理器运行在容器中

//通过 BeanFactory后处理器类的类型来获取全部的后处理器 然后遍历 将这些后处理器运行在beanFactory容器中
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().stream().
                forEach(beanFactoryPostProcessor ->beanFactoryPostProcessor.postProcessBeanFactory(beanFactory));

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

得到结果

 加入这段代码后

//获取bean1  然后调用bean1的getBean2() 方法
System.out.println(beanFactory.getBean(Bean1.class).getBean2());

得到结果

我们发现获取到的bean2是null  ---这代表@Autowired这个依赖注入的注解没有实现 

2.Bean后处理器 --针对bean的声明周期各个阶段提供扩展  例如@Autowired @Resource注解

添加代码

beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
                .forEach(beanPostProcessor -> beanFactory.addBeanPostProcessor(beanPostProcessor));

得到结果   说明bean后处理器生效了

3.初始化单例对象

我么只需要加入一行代码 
beanFactory.preInstantiateSingletons();  //提前准备好所有的单例

4.bean后处理器的排序的逻辑

 当同时添加@Autowired 和@Resource的时候  会先执行 @Autowired

我们发现是Autowired在前  因此是指向的是@Autowired 

这里我们可以设置来改变后处理器的顺序

基本原理是

beanFactory学到了什么

  1.不会主动调用BeanFactory的后处理器 来解析@Configuration和@Bean等注解

  2.不会主动添加Bean的后处理    来解析@Autowired注解

 3.不会主动初始化单例的对象

 4.不会解析beanFactory中的${}和#{}  

 5.bean后处理器有一个排序的逻辑 

二、ApplicationContext的实现

 2.1 ClassPathXmlApplicationContext 基于classpath下的xml格式的配置文件

 2.2 FileSystemXmlApplicationContext  基于磁盘路径下的xml格式的配置文件

下面演示ClassPathXmlApplicationContext(ApplicationContext接口的实现)比BeanFactory多出功能的实现

 public static void main(String[] args) {
//    testClassPathXmlApplicationContext();
//       testFileSystemXmlApplicationContext();
        //默认beanFactory表单
        DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory();
        //读取前
        for (String s : beanFactory.getBeanDefinitionNames()) {
            System.out.println(s);
        }
        //xml文件bean定义的读取者 --存入到哪里
        XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(beanFactory);
        //将xml文件信息加载进入
        reader.loadBeanDefinitions(new ClassPathResource("b01.xml"));
        System.out.println("----------");
        //读取后
        for (String s : beanFactory.getBeanDefinitionNames()) {
            System.out.println(s);
        }
    }

结果:

 2.3 AnnotationConfigApplicationContext  注解配置的容器

先要创建一个注解类 进行配置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;
        }
    }

我们有注意到,上面的ClassPathXmlApplicationContext 并没有自动加入  

未进行配置时:

 配置后:

如果要加入只需要在xml配置文件中加入 

2.4 AnnotationConfigServletWebServerApplicationContext  web容器

 // ⬇️较为经典的容器, 基于 java 配置类来创建, 用于 web 环境
    private static void testAnnotationConfigServletWebServerApplicationContext() {
    AnnotationConfigServletWebServerApplicationContext context=
            new AnnotationConfigServletWebServerApplicationContext(webConfig.class);

    }
  @Configuration
    static  class webConfig{
        @Bean
        //web服务器工厂控制器
      public  ServletWebServerFactory servletWebServerFactory (){
            return  new TomcatServletWebServerFactory();
        }
        @Bean  //前端控制器
      public  DispatcherServlet dispatcherServlet(){
            return  new DispatcherServlet();
        }
        @Bean   //将DispathcherServlet注册到tomcat中
      public  DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet){
            return  new DispatcherServletRegistrationBean(dispatcherServlet,"/");
        }
      //控制器
      @Bean("/hello")
      public  Controller controller(){
            return  new Controller() {
                @Override
                public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
                    response.getWriter().write("hello");
                    return null;
                }
            };
      }
    }

这个其实就是内嵌了web服务器     是springboot的web服务器的本质


总结

ClassPathXmlApplicationContext 基于classpath下的xml格式的配置文件

FileSystemXmlApplicationContext  基于磁盘路径下的xml格式的配置文件

AnnotationConfigApplicationContext  注解配置的容器

AnnotationConfigServletWebServerApplicationContext  web容器

前两种是具有xml配置文件的容器  ---现在已经不常用了

后两种比较常用    一个是非web环境的容器    一个是web环境的容器

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值