容器与Bean(一)

简介: 容器与Bean

容器接口

  • BeanFactory 接口,典型功能有:
  • getBean
  • ApplicationContext 接口,是 BeanFactory 的子接口。它扩展了 BeanFactory 接口的功能,如:
  • 国际化
  • 通配符方式获取一组 Resource 资源
  • 整合 Environment 环境(能通过它获取各种来源的配置信息)
  • 事件发布与监听,实现组件之间的解耦

BeanFactory与Application的区别

  1. 到底什么是 BeanFactory
  • 它是 ApplicationContext 的父接口
  • 它才是 Spring 的核心容器, 主要的 ApplicationContext 实现都【组合】了它的功能,【组合】是指 ApplicationContext 的一个重要成员变量就是 BeanFactory
  1. BeanFactory 能干点啥
  • 表面上只有 getBean
  • 实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能,都由它的实现类提供
  • 通过反射查看了它的成员变量 singletonObjects,内部包含了所有的单例 bean
  1. ApplicationContext 比 BeanFactory 多点啥
  • ApplicationContext 组合并扩展了 BeanFactory 的功能
  • 国际化、通配符方式获取一组 Resource 资源、整合 Environment 环境、事件发布与监听

容器实现

具体实现类:

  • DefaultListableBeanFactory,是 BeanFactory 最重要的实现,像控制反转依赖注入功能,都是它来实现
  • ClassPathXmlApplicationContext,从类路径查找 XML 配置文件,创建容器(旧)
  • FileSystemXmlApplicationContext,从磁盘路径查找 XML 配置文件,创建容器(旧)
  • XmlWebApplicationContext,传统 SSM 整合时,基于 XML 配置文件的容器(旧)
  • AnnotationConfigWebApplicationContext,传统 SSM 整合时,基于 java 配置类的容器(旧)
  • AnnotationConfigApplicationContext,Spring boot 中非 web 环境容器(新)
  • AnnotationConfigServletWebServerApplicationContext,Spring boot 中 servlet web 环境容器(新)
  • AnnotationConfigReactiveWebServerApplicationContext,Spring boot 中 reactive web 环境容器*(新)

带有 ApplicationContext 的类都是 ApplicationContext 接口的实现,但它们是组合了 DefaultListableBeanFactory 的功能,并非继承而来。

DefaultListableBeanFactory

  • 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 后处理的添加顺序会对解析结果有影响
  • beanFactory 需要手动调用方法来初始化单例
  • beanFactory 需要额外设置才能解析 ${} 与 #{}

ApplicationContext实现类

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

Bean 的生命周期

一个受 Spring 管理的 bean,生命周期主要阶段有

  1. 创建:根据 bean 的构造方法或者工厂方法来创建 bean 实例对象
  2. 依赖注入:根据 @Autowired,@Value 或其它一些手段,为 bean 的成员变量填充值、建立关系
  3. 初始化:回调各种 Aware 接口,调用对象的各种初始化方法
  4. 销毁:在容器关闭时,会销毁所有单例对象(即调用它们的销毁方法)
  • prototype 对象也能够销毁,不过需要容器这边主动调用

生命周期中还有一类 bean 后置处理器,会在上述生命周期的前后,提供一些扩展逻辑。

bean后置处理器

注意:以下都是方法

创建前后的增强

  • postProcessBeforeInstantiation (Instantiation:实例化)
  • 这里返回的对象若不为 null 会替换掉原本的 bean,并且仅会走 postProcessAfterInitialization 流程
  • postProcessAfterInstantiation
  • 这里如果返回 false 会跳过依赖注入阶段

依赖注入前的增强

  • postProcessProperties
  • 如 @Autowired、@Value、@Resource

初始化前后的增强

  • postProcessBeforeInitialization (Initialization:初始化)
  • 这里返回的对象会替换掉原本的 bean
  • 如 @PostConstruct、@ConfigurationProperties
  • postProcessAfterInitialization
  • 这里返回的对象会替换掉原本的 bean
  • 如代理增强

销毁之前的增强

  • postProcessBeforeDestruction
  • @PreDestroy

模板方法模式

Bean的生命周期中通过bean的后置处理器作扩展,使用的是模板方法模式

代码演示:

public class TestMethodTemplate {
    public static void main(String[] args) {
        MyBeanFactory beanFactory = new MyBeanFactory();
        //定义不同的子类
        beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Autowired"));
        beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Resource"));
        beanFactory.getBean();
    }
    // 模板方法  Template Method Pattern
    static class MyBeanFactory {
        public Object getBean() {
            Object bean = new Object();
            System.out.println("构造 " + bean);
            System.out.println("依赖注入 " + bean); // @Autowired, @Resource
            for (BeanPostProcessor processor : processors) {
                processor.inject(bean);
            }
            System.out.println("初始化 " + bean);
            return bean;
        }
        private List<BeanPostProcessor> processors = new ArrayList<>();
        public void addBeanPostProcessor(BeanPostProcessor processor) {
            processors.add(processor);
        }
    }
    static interface BeanPostProcessor {
        public void inject(Object bean); // 对依赖注入阶段的扩展
    }
}

bean 后处理器排序

对于各种后处理器的执行顺序,有这样的规则:

  1. 实现了 PriorityOrdered 接口的优先级最高
  2. 实现了 Ordered 接口与加了 @Order 注解的平级, 按数字升序
  3. 其它的排在最后

代码演示:

/*
    bean 后处理的的排序
 */
public class TestProcessOrder {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
        List<BeanPostProcessor> list = new ArrayList<>(List.of(new P1(), new P2(), new P3(), new P4(), new P5()));
        list.sort(beanFactory.getDependencyComparator());
        list.forEach(processor->{
            processor.postProcessBeforeInitialization(new Object(), "");
        });
        /*
            学到了什么
                1. 实现了 PriorityOrdered 接口的优先级最高
                2. 实现了 Ordered 接口与加了 @Order 注解的平级, 按数字升序
                3. 其它的排在最后
         */
    }
    @Order(1)
    static class P1 implements BeanPostProcessor {
        private static final Logger log = LoggerFactory.getLogger(P1.class);
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            log.debug("postProcessBeforeInitialization @Order(1)");
            return bean;
        }
    }
    @Order(2)
    static class P2 implements BeanPostProcessor {
        private static final Logger log = LoggerFactory.getLogger(P2.class);
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            log.debug("postProcessBeforeInitialization @Order(2)");
            return bean;
        }
    }
    static class P3 implements BeanPostProcessor, PriorityOrdered {
        private static final Logger log = LoggerFactory.getLogger(P3.class);
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            log.debug("postProcessBeforeInitialization PriorityOrdered");
            return bean;
        }
        @Override
        public int getOrder() {
            return 100;
        }
    }
    static class P4 implements BeanPostProcessor, Ordered {
        private static final Logger log = LoggerFactory.getLogger(P4.class);
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            log.debug("postProcessBeforeInitialization Ordered");
            return bean;
        }
        @Override
        public int getOrder() {
            return 0;
        }
    }
    static class P5 implements BeanPostProcessor {
        private static final Logger log = LoggerFactory.getLogger(P5.class);
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            log.debug("postProcessBeforeInitialization");
            return bean;
        }
    }
}

控制台输出样例:

[DEBUG] 22:13:30.104 [main] com.itheima.a03.TestProcessOrder$P3 - postProcessBeforeInitialization PriorityOrdered 
[DEBUG] 22:13:30.108 [main] com.itheima.a03.TestProcessOrder$P4 - postProcessBeforeInitialization Ordered 
[DEBUG] 22:13:30.108 [main] com.itheima.a03.TestProcessOrder$P1 - postProcessBeforeInitialization @Order(1) 
[DEBUG] 22:13:30.108 [main] com.itheima.a03.TestProcessOrder$P2 - postProcessBeforeInitialization @Order(2) 
[DEBUG] 22:13:30.108 [main] com.itheima.a03.TestProcessOrder$P5 - postProcessBeforeInitialization

Bean 后处理器

后处理器作用

  1. @Autowired 等注解的解析属于 bean 生命周期阶段(依赖注入, 初始化)的扩展功能,这些扩展功能由 bean 后处理器来完成
  2. 每个后处理器各自增强什么功能
  • AutowiredAnnotationBeanPostProcessor 解析 @Autowired  与 @Value  
  • CommonAnnotationBeanPostProcessor 解析 @Resource、@PostConstruct、@PreDestroy  
  • ConfigurationPropertiesBindingPostProcessor 解析 @ConfigurationProperties
  1. 另外 ContextAnnotationAutowireCandidateResolver 负责获取 @Value  的值,解析 @Qualifier、泛型、@Lazy  等

@Autowired bean 后处理器运行分析

  1. AutowiredAnnotationBeanPostProcessor.findAutowiringMetadata 用来获取某个 bean 上加了 @Value @Autowired 的成员变量,方法参数的信息,表示为 InjectionMetadata
  2. InjectionMetadata 可以完成依赖注入
  3. InjectionMetadata 内部根据成员变量,方法参数封装为 DependencyDescriptor 类型
  4. 有了 DependencyDescriptor,就可以利用 beanFactory.doResolveDependency 方法进行基于类型的查找


容器与Bean(二)https://developer.aliyun.com/article/1469471

目录
相关文章
|
6天前
|
XML Java 数据格式
掌握 Spring IoC 容器与 Bean 作用域:详解 singleton 与 prototype 的使用与配置
在您的应用程序中,由 Spring IoC 容器管理的形成其核心的对象被称为 "bean"。一个 bean 是由 Spring IoC 容器实例化、组装和管理的对象
51 0
|
6天前
|
Java 数据库连接 Spring
|
6天前
|
XML Java 数据格式
Spring 的奇幻起源:从 IoC 容器到 Bean 的魔法世界 (下)
Spring 的奇幻起源:从 IoC 容器到 Bean 的魔法世界
|
6天前
|
XML Java 数据格式
Spring 的奇幻起源:从 IoC 容器到 Bean 的魔法世界 (上)
Spring 的奇幻起源:从 IoC 容器到 Bean 的魔法世界 (上)
|
8月前
|
XML Java 数据格式
【Spring】全面讲解IOC、AOP、注入方式、bean的生命周期、aop通知应用 spring与web容器整合
Spring是一个开源的轻量级Java应用开发框架,它提供了一种简单、高效、灵活的方式来构建企业级应用程序。Spring框架的核心特点是依赖注入(Dependency Injection)和面向切面编程(Aspect-Oriented Programming),它通过一组模块化的组件提供全面的支持,使开发人员能够快速搭建可扩展、可维护的应用。
|
6天前
|
XML Java 数据格式
如何在Filter中使用Spring容器中的Bean?
如何在Filter中使用Spring容器中的Bean?
65 0
|
5月前
|
容器
IOC容器初始化过程中单例Bean的预实例化
IOC容器初始化过程中单例Bean的预实例化
29 0
|
机器学习/深度学习 存储 缓存
《Spring核心技术》第4章:深度解析从IOC容器中获取Bean的过程
沉淀,成长,突破,帮助他人,成就自我。
162 0
《Spring核心技术》第4章:深度解析从IOC容器中获取Bean的过程
|
11月前
|
XML druid Java
Spring | 数据源对象 properties文件 创建容器和获取bean 容器总结
Spring | 数据源对象 properties文件 创建容器和获取bean 容器总结
138 0
|
12月前
|
Java Spring 容器
如何在非Spring容器管理的类中注入/获取 Spring容器中的 Bean?
如何在非Spring容器管理的类中注入/获取 Spring容器中的 Bean?
166 0

热门文章

最新文章