Spring5学习笔记02--BeanFactory 与 ApplicationContext 容器实现

内容概要:

  • BeanFactory 实现的特点
  • ApplicationContext 的常见实现和用法
  • 内嵌容器、注册DispatcherServlet

BeanFactory 实现

  • DefaultListableBeanFactory 是 BeanFactory 最重要的实现
    • 新创建的BeanFactory里面什么也没有,需要手动进行后续的操作(如注册bean的定义)
  • BeanFactory 是根据bean的定义BeanDefinition 通过控制反转来创建bean
    • 想要BeanFactory容器添加某个Bean,就需要先BeanFactory中添加这个Bean的定义
    • BeanFactory并不会主动初始化Bean对象,通过BeanFactory获取Bean对象时,才会初始化
  • Bean的定义 BeanDefinition包括(class、Scope 单例/多例、初始化方法、销毁方法)
    • 通过BeanDefinitionBuilder创建bean的定义,设置Bean相关信息
    • 向BeanFactory中注册过Bean的定义,同时设置bean的名称
  • 向beanFactory注册一个@Configuration组件,并不会自动将里面@Bean标示的其他Bean自动注册到BeanFactory,需要一些后处理器来补充这些Bean的定义
  • BeanFactory后处理器BeanFactoryPostProcessor
    • BeanFactory后处理器BeanFactoryPostProcessor的主要功能: 补充一些Bean的定义到BeanFactory, 例如 @Bean 注解
    • 向BeanFactory中添加一些常用的后处理器BeanFactoryPostProcessor(Bean的定义),才会将@Bean等信息的Bean的定义注册到BeanFactory
  • Bean后处理器BeanPostProcessor
    • Bean后处理器BeanPostProcessor的主要功能: 针对bean的生命周期的各个阶段提供扩展,例如 @Autowired @Resurece…
@Slf4j
public class MainController {

    public static void main(String[] args) {
        // 1)创建BeanFactory,新创建的BeanFactory里面什么也没有
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        // 2)创建Bean的定义(class,scope,初始化,销毁),并向BeanFactory中注册bean的定义
        //BeanFactory是根据bean的定义`BeanDefinition`,通过控制反转来创建bean,想要BeanFactory容器添加某个Bean,就需要BeanFactory中添加Bean的定义(此时并不会主动初始化bean对象)
        BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope(BeanDefinition.SCOPE_SINGLETON).getBeanDefinition();
        beanFactory.registerBeanDefinition("config", beanDefinition);

        /*
        // 2.1)向beanFactory注册一个@Configuration组件,并不会自动将里面@Bean标示的其他Bean自动注册到BeanFactory
        for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
            // 输出只有config
            System.out.println(beanDefinitionName);
        }
        System.out.println("2.1>>>>>>>>>>>>>>>>>");
         */

        // 3)向BeanFactory中添加一些常用的后处理器(Bean的定义)
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

        // 3.1)打印后处理器Bean的定义
        for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
            // 输出多了5个后处理器
            System.out.println(beanDefinitionName + "--->" + beanFactory.getBeanDefinition(beanDefinitionName));
        }
        System.out.println("3.1>>>>>>>>>>>>>>>>>");

        // 4)BeanFactory后处理器的主要功能: 补充一些Bean的定义到BeanFactory, 例如 @Bean..
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor-> {
            System.out.println(beanFactoryPostProcessor);
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });
        System.out.println("4>>>>>>>>>>>>>>>>>");

        /*
        // 4.1)BeanFactory后处理器,将Bean1和Bean2的Bean的定义添加到BeanFactory
        for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
            // 输出多了 bean1 bean2
            System.out.println(beanDefinitionName);
        }
        System.out.println("4.1>>>>>>>>>>>>>>>>>");
        */

        /*
        // 4.2)BeanFactory并不会主动初始化Bean对象,通过BeanFactory获取Bean对象时,才会初始化
        // 获取Bean1对象,此时Bean1对象中通过@Autowired注入的Bean2对象并没有初始化
        System.out.println("bean1.getBean2():" + beanFactory.getBean(Bean1.class).getBean2()); // 打印bean1 create, 输出bean2为null
        System.out.println("4.2>>>>>>>>>>>>>>>>>");
        */

        // 5)Bean后处理器的主要功能: 针对bean的生命周期的各个阶段提供扩展,例如 @Autowired @Resurece..
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanPostProcessor -> {
            System.out.println(beanPostProcessor);
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        });
        System.out.println("5>>>>>>>>>>>>>>>>>");
//        beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor); // 使用方法引用代替lambda表达式

        // 5.1)Bean后处理器,将Bean1对象中的Bean2对象初始化注入进去
        System.out.println("bean1.getBean2():" + beanFactory.getBean(Bean1.class).getBean2());// 打印bean1 create, bean2 create,
        System.out.println("5.2>>>>>>>>>>>>>>>>>");
      
        // 6) 在使用Bean之前,先初始化单例对象
        beanFactory.preInstantiateSingletons();
    }

    @Configuration
    static class Config {

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


    @Slf4j
    static class Bean1 {

        @Autowired
        private Bean2 bean2;

        public Bean1() {
            log.info("Bean1() create");
        }

        public Bean2 getBean2() {
            return bean2;
        }
    }

    @Slf4j
    static class Bean2 {

        public Bean2() {
            log.info("Bean2() create");
        }
    }
}

Bean后处理器排序

  • @Autowired 注入规则:先根据class类型匹配,当class类型存在多个,再根据成员变量的名字匹配bean的名字

  • @Resource 注入规则:先根据class类型匹配,当class类型存在多个,如果注解中的变量name存在,则根据name匹配bean的名字,若不存在,则根据成员变量的名字匹配bean的名字

  • @Autowired 优先级低于 @Resource,当注入bean时同时加上了这两个注解,优先匹配 @Resource

  • 查看Bean后处理器优先级源码 AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);方法

    • AutowiredAnnotationBeanPostProcessor 后处理器作用:解析@Autowired注解,将注入的bean定义加入到BeanFactory
    • CommonAnnotationBeanPostProcessor后处理器作用:解析@Resource 注解,将注入的bean定义加入到BeanFactory
    • Bean后处理器的优先级是根据order排序的,值越小优先级越高
    // AutowiredAnnotationBeanPostProcessor 成员变量
    private int order = Ordered.LOWEST_PRECEDENCE - 2;
    
    // CommonAnnotationBeanPostProcessor 构造器
    public CommonAnnotationBeanPostProcessor() {
    		setOrder(Ordered.LOWEST_PRECEDENCE - 3);
        // ...
    }
    

示例:

interface Inter {}

class Bean1 implements Inter {}

class Bean2 implements Inter {}

@Configuration
class Config {
    @Bean
    public Inter bean3() {
        return new Bean3();
    }

    @Bean
    public Inter bean4() {
        return new Bean4();
    }
}

class TestComponent {
  	@Autowired
  	private Inter inter; // 找不到bean, 注入失败 (Could not autowire. There is more than one bean of 'Inter' type. Beans: bean1、bean2)
  
    @Autowired
    private Inter bean3; // 注入bean3, 根据成员变量的名字匹配


    @Resource
    private Inter bean3; // 注入bean3, 根据成员变量的名字匹配


    @Resource(name = "bean4")
    private Inter bean3; // 注入bean4, 根据name匹配


    @Autowired
    @Resource(name = "bean4")
    private Inter bean3; // 注入bean4, @Autowired 优先级低于 @Resource
}

总结:

  • BeanFactory 不会做的事
    • 不会主动调用BeanFactory后处理器(用于解析@Bean)
    • 不会主动调用Bean后处理器(用于解析@Autowired、@Resource…)
    • 不会主动初始化单例
    • 不会解析 beanFactory, 还不会解析 ${}#{}

ApplicationContext 实现

ClassPathXmlApplicationContext

  • ClassPathXmlApplicationContext: 基于类路径(classpath)下读取 Spring 的 xml 配置文件创建ApplicationContext
private static void testClassPathXmlApplicationContext() {
  ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean01.xml");

  // 注入了两个Bean, bean5 和 bean6
  for (String beanDefinitionName : context.getBeanDefinitionNames()) {
    System.out.println(beanDefinitionName);
  }

  // bean6中的bean5也自动注入成功
  System.out.println(context.getBean(Bean6.class).getBean5());
}
<bean id="bean5" class="com.xxx.xxx.entity.Bean5" />

<bean id="bean6" class="com.xxx.xxx.entity.Bean6">
	<property name="bean5" ref="bean5" />
</bean>
static class Bean5 {
  // 必须要有空构造方法
  public Bean5() {
  }
}

static class Bean6 {
  // 必须要有空构造方法
  public Bean6() {
  }

  private Bean5 bean5;

  public Bean5 getBean5() {
    return bean5;
  }

  public void setBean5(Bean5 bean5) {
    this.bean5 = bean5;
  }
}

FileSystemXmlApplicationContext

  • FileSystemXmlApplicationContext: 基于磁盘路径下读取 Spring 的 xml 配置文件创建ApplicationContext
    • 支持绝对路径,也支持传入从项目根目录开始的相对路径
private static void testFileSystemXmlApplicationContext() {
  // 支持绝对路径,也支持传入从项目根目录开始的相对路径
//  FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("/Users/wangli/idea-workspace/study-spring/src/main/resources/bean01.xml");
  FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src/main/resources/bean01.xml");

  // 注入了两个Bean, bean5 和 bean6
  for (String beanDefinitionName : context.getBeanDefinitionNames()) {
    System.out.println(beanDefinitionName);
  }

  // bean6中的bean5也自动注入成功
  System.out.println(context.getBean(Bean6.class).getBean5());
}
  • 基于 xml 配置文件初始化 ApplicationContext 容器的原理
    • ApplicationContext 内部依赖 BeanFactory (也就是 DefaultListableBeanFactory) 来进行 Bean 的管理
    • xml 配置文件是通过 XmlBeanDefinitionReader 读取的,xml 文件中配置的其实就是bean的定义
    • XmlBeanDefinitionReader 将读取到的内容转换成 BeanDefinition 注册到 BeanFactory 里
private static void testXmlApplicationContext() {
  DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

  // 新创建的BeanFactory 什么也没有
  System.out.println("before read..");
  for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
    System.out.println(beanDefinitionName);
  }

  // 初始化XmlBeanDefinitionReader, 设置将读取到的BeanDefinition注册到beanFactory
  XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
  // 设置读取xml文件资源
  reader.loadBeanDefinitions(new ClassPathResource("bean01.xml"));
//   reader.loadBeanDefinitions(new FileSystemResource("src/main/resources/bean01.xml"));

  // 读取到两个bean, bean5 和 bean6
  System.out.println("after read..");
  for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
    System.out.println(beanDefinitionName);
  }
}
  • 基于 xml 初始化 ApplicationContext 如何将BeanFactory注册的5个后处理器添加进去:使用下面这个标签
<context:annotion-config />

AnnotationConfigApplicationContext

  • AnnotationConfigApplicationContext: 基于 Java 配置类来创建ApplicationContext
    • 会自动将5个BeanFactory注册的后处理器也注册到 BeanFactory 里
private static void testAnnotationConfigApplicationContext() {
  AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);

  // 读取到了8个bean, 除了 bean5 和 bean6 外,还有 Config 和 5个BeanFactory注册的后处理器
  for (String beanDefinitionName : context.getBeanDefinitionNames()) {
    System.out.println(beanDefinitionName);
  }

  // bean6中的bean5也自动注入成功
  System.out.println(context.getBean(Bean6.class).getBean5());
}
@Configuration
static class Config {
  @Bean
  public Bean5 bean5() {
    return new Bean5();
  }

  @Bean
  public Bean6 bean6(Bean5 bean5) {
    Bean6 bean6 = new Bean6();
    bean6.setBean5(bean5);
    return bean6;
  }
}

AnnotationConfigServletWebServerApplicationContext

  • AnnotationConfigServletWebServerApplicationContext: 基于 java 配置类来创建,用于 web 环境
  • 读取配置类,该配置类中需要注册三个特有的bean
    • ServletWebServerFactory: 提供ServletWebServer的工厂类,用于创建ServletWebServer
      • ServletWebServer是内嵌了一个基于servlet技术的web容器
      • 常见的内嵌容器:Tomcat内嵌容器
    • DispatcherServlet: 前控制器,作用是将请求分发到对应到控制器
    • DispatcherServletRegistrationBean: 用于注册DispatcherServlet到web容器
    • 另外提供一个控制器,来处理web请求,Controller 控制器,web请求入口点,由DispatcherServlet分发指定请求路径为的请求到这个控制器进行处理
private static void testAnnotationInitApplicationContext() {
  AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
  
  // 读取到了10个bean, 5个BeanFactory注册的后处理器 + WebConfig + servletWebServerFactory + dispatcherServlet + registrationBean + /hi
  for (String beanDefinitionName : context.getBeanDefinitionNames()) {
    System.out.println(beanDefinitionName);
  }
}


    @Configuration
    static class WebConfig {

        /**
         * ServletWebServer:内嵌了一个基于servlet技术的web容器,常见的内嵌容器:Tomcat内嵌容器
         * ServletWebServerFactory:提供ServletWebServer的工厂类,用于创建ServletWebServer
         * @return
         */
        @Bean
        public ServletWebServerFactory servletWebServerFactory() {
            return new TomcatServletWebServerFactory();
        }

        /**
         * DispatcherServlet:前控制器,作用是将请求分发到对应到控制器
         * @return
         */
        @Bean
        public DispatcherServlet dispatcherServlet() {
            return new DispatcherServlet();
        }

        /**
         * DispatcherServletRegistrationBean:用于注册DispatcherServlet到web容器
         * @param dispatcherServlet
         * @return
         */
        @Bean
        public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
            return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
        }

        /**
         * Controller: 控制器web请求入口点,由DispatcherServlet分发请求路径为 "/hi" 的请求到这个控制器进行处理
         * @return
         */
        @Bean("/hi")
        public Controller controller1() {
            return new Controller() {
                @Override
                public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
                    response.getWriter().write("hi");
                    return null;
                }
            };
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值