Spring原理学习

Spring原理学习

容器与Bean

BeanFactory和ApplicationContext

BeanFactory

001-第一讲-BeanFactory与ApplicationContext哔哩哔哩bilibili

  • 它是 ApplicationContext 的父接口 (见下图)

  • 它才是 Spring 的核心容器, 主要的 ApplicationContext 实现都【组合】了它的功能,【组合】是指 ApplicationContext 的一个重要成员变量就是 BeanFactory

  • getBean()是BeanFactory最主要的功能

  • 表面上只有 getBean

  • 实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能,都由它的实现类(DefaultListableBeanFactory)提供

ApplicationContext

003-第一讲-ApplicationContext功能1哔哩哔哩bilibili

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

    • 国际化

      csharp 复制代码
      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));
          }
      }

      国际化文件均在 src/resources 目录下

      messages.properties(空)

      messages_en.properties

      ini 复制代码
      hi=Hello

      messages_ja.properties

      ini 复制代码
      hi=こんにちは

      messages_zh.properties

      ini 复制代码
      hi=你好

      注意

      • ApplicationContext 中 MessageSource bean 的名字固定为 messageSource
      • 使用 SpringBoot 时,国际化文件名固定为 messages
      • 空的 messages.properties 也必须存在
    • 通配符方式获取一组 Resource

    • 资源整合 Environment 环境(能通过它获取各种来源的配置信息)

    • 事件发布与监听,实现组件之间的解耦

事件驱动

概述

事件通常由事件源(Event Source)触发,并且可以被其他组件或对象监听和处理。事件源可以是用户的交互操作、传感器的检测、系统的状态变化等等。当事件源触发一个事件时,它会通知所有监听该事件的对象,以便它们可以执行相应的操作或逻辑。

假设有一个用户注册功能,当用户注册成功后需要发送一封欢迎邮件和一条短信。如果不使用事件驱动的方式,代码可能会像这样:

java 复制代码
public class UserService {
    public void register(User user) {
        // 注册用户
        //...
​
        // 发送欢迎邮件
        EmailService emailService = new EmailService();
        emailService.sendWelcomeEmail(user.getEmail());
​
        // 发送短信
        SmsService smsService = new SmsService();
        smsService.sendSms(user.getMobile(), "欢迎注册");
    }
}

在上面的代码中,UserService 类负责注册用户,并在注册成功后直接调用 EmailService 和 SmsService 发送邮件和短信。这样就形成了直接的依赖关系,UserService 类需要知道有哪些服务类需要被调用,并且需要知道这些服务类的具体实现。这样会导致代码的可维护性和灵活性变差。

如果使用事件驱动的方式,代码可能会像这样:

typescript 复制代码
public class UserService {
    @Autowired
    private ApplicationEventPublisher eventPublisher;
​
    public void register(User user) {
        // 注册用户
        //...
​
        // 发布用户注册事件
        eventPublisher.publishEvent(new UserRegisteredEvent(this, user));
    }
}
​
public class EmailService {
    @EventListener
    public void sendWelcomeEmail(UserRegisteredEvent event) {
        User user = event.getUser();
        // 发送欢迎邮件
        //...
    }
}
​
public class SmsService {
    @EventListener
    public void sendSms(UserRegisteredEvent event) {
        User user = event.getUser();
        // 发送短信
        //...
    }
}

在上面的代码中,UserService 类负责注册用户,并使用 ApplicationEventPublisher 接口发布了 UserRegisteredEvent 事件。EmailService 和 SmsService 类使用 @EventListener 注解监听了 UserRegisteredEvent 事件,并在事件发生时发送邮件和短信。这样,UserService 类和 EmailService、SmsService 类之间就形成了松耦合的关系,UserService 类只需要负责发布事件,而其他组件则只需要监听事件并做出相应的处理,不需要知道彼此之间的具体实现。

应用

在实际开发中,您可以使用 Spring 框架提供的事件驱动机制来实现事件驱动编程。下面是一个简单的步骤,可以帮助您在 Spring 中使用事件驱动编程:

  1. 创建事件类。事件类应该继承自 ApplicationEvent 类,并且包含一些与事件相关的属性和方法。
scala 复制代码
public class UserRegisteredEvent extends ApplicationEvent {
    private User user;
​
    public UserRegisteredEvent(Object source, User user) {
        super(source);
        this.user = user;
    }
​
    public User getUser() {
        return user;
    }
}
  1. 在发布事件的组件中注入 ApplicationEventPublisher 对象,并使用 publishEvent() 方法发布事件。
typescript 复制代码
@Component
public class UserService {
    @Autowired
    private ApplicationEventPublisher eventPublisher;
​
    public void register(User user) {
        // 注册用户
        //...
​
        // 发布用户注册事件
        eventPublisher.publishEvent(new UserRegisteredEvent(this, user));
    }
}
  1. 在监听事件的组件中使用 @EventListener 注解来监听事件,并在事件发生时执行相应的处理逻辑。
java 复制代码
@Component
public class EmailService {
    @EventListener
    public void sendWelcomeEmail(UserRegisteredEvent event) {
        User user = event.getUser();
        // 发送欢迎邮件
        //...
    }
}
​
@Component
public class SmsService {
    @EventListener
    public void sendSms(UserRegisteredEvent event) {
        User user = event.getUser();
        // 发送短信
        //...
    }
}

在上面的代码中,UserService 组件使用 ApplicationEventPublisher 对象发布了 UserRegisteredEvent 事件,而 EmailService 和 SmsService 组件使用 @EventListener 注解监听了这个事件,并在事件发生时执行相应的处理逻辑。

*(不生效再考虑) *需要注意的是,为了让 Spring 能够自动识别和处理事件,需要在 Spring 配置文件中添加以下配置:

arduino 复制代码
<context:annotation-config />

这样,Spring 就会自动扫描组件中的 @EventListener 注解,并将它们注册为事件监听器。

总的来说,使用 Spring 的事件驱动机制可以实现组件之间的解耦,提高系统的灵活性和可维护性。同时,事件驱动编程还可以让代码变得更加清晰、简洁和易于维护。

容器实现

Spring 的发展历史较为悠久,因此很多资料还在讲解它较旧的实现,这里出于怀旧的原因,把它们都列出来,供大家参考

  • 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实现

007-第二讲-BeanFactory实现哔哩哔哩bilibili

scss 复制代码
public class TestBeanFactory {
​
    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);
​
        //输出的只是bean定义
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
​
        System.out.println("=====================================");
​
        // 给 BeanFactory 添加一些常用的后处理器
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
​
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
​
        System.out.println("=====================================");
​
        // BeanFactory 后处理器主要功能,补充了一些 bean 定义
        Collection<BeanFactoryPostProcessor> beanFactoryPostProcessors
                = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values();
        //internalConfigurationAnnotationProcessor
        //internalEventListenerProcessor
beanFactoryPostProcessors.forEach(beanFactoryPostProcessor -> beanFactoryPostProcessor.postProcessBeanFactory(beanFactory));
​
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
​
        System.out.println("=====================================");
​
        // Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
        //将bean后处理器加入到bean后处理器链中后,bean后处理器才会发挥作用
        Collection<BeanPostProcessor> beanPostProcessors
                = beanFactory.getBeansOfType(BeanPostProcessor.class).values();
        //internalAutowiredAnnotationProcessor
        //internalCommonAnnotationProcessor
        beanPostProcessors.stream()
                //给bean后处理器排序
                .sorted(beanFactory.getDependencyComparator())
                //将bean后处理器加入到bean后处理器链中后,bean后处理器才会发挥作用
                .forEach(beanFactory::addBeanPostProcessor);
​
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
​
        System.out.println("=====================================");
​
        beanFactory.preInstantiateSingletons(); // 准备好所有单例,在调用此方法之前bean没有被创建
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
        System.out.println(beanFactory.getBean(Bean1.class).getBean2());
        System.out.println(beanFactory.getBean(Bean1.class).getInter());
        /*
            学到了什么:
            a. beanFactory 不会做的事
                   1. 不会主动调用 BeanFactory 后处理器
                   2. 不会主动添加 Bean 后处理器
                   3. 不会主动初始化单例
                   4. 不会解析beanFactory 还不会解析 ${ } 与 #{ }
            b. 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实现

010-第二讲-ApplicationContext实现1,2哔哩哔哩bilibili

typescript 复制代码
/*
    常见 ApplicationContext 实现
 */
public class A02 {
    private static final Logger log = LoggerFactory.getLogger(A02.class);
​
    public static void main(String[] args) {
//        testClassPathXmlApplicationContext();
//        testFileSystemXmlApplicationContext();
        testAnnotationConfigApplicationContext();
//        testAnnotationConfigServletWebServerApplicationContext();
​
      /*  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);
        }*/
​
        /*
            学到了什么
                a. 常见的 ApplicationContext 容器实现
                b. 内嵌容器、DispatcherServlet 的创建方法、作用
         */
    }
​
    // ⬇️较为经典的容器, 基于 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;
        }
    }
}
  • 前面两个为xml方式注册

  • 第三个为配置类注册,会自动为我们添加常用的bean处理器

  • 第四个配置方式就体现了springboot和springMvc原理

    • 第一个 Bean tomcatServletWebServerFactory() 是用来创建 Servlet Web 服务器的。在这个例子中,我们使用 Tomcat 作为 Servlet 容器,因此创建了一个 TomcatServletWebServerFactory 对象,并设置了端口号为 8080。这个 Bean 的主要作用是创建一个嵌入式的 Tomcat 服务器,用于运行 Spring Boot 应用程序。
    • 第二个 Bean dispatcherServlet() 是用来创建 DispatcherServlet 对象的。DispatcherServlet 是 Spring MVC 框架的核心组件,用于处理 HTTP 请求并将请求分发到对应的 Controller 类中进行处理。在这个例子中,我们创建了一个 DispatcherServlet 对象,并将其设置为根 Servlet。这个 Bean 的主要作用是创建一个 DispatcherServlet 对象,用于处理 HTTP 请求。
    • 第三个 Bean dispatcherServletRegistration() 是用来将 DispatcherServlet 注册到 Servlet 容器中的。在这个例子中,我们创建了一个 DispatcherServletRegistrationBean 对象,并将 DispatcherServlet 对象作为参数传入。然后,我们设置了 DispatcherServlet 对象的 URL 映射规则为 /,这意味着所有的 HTTP 请求都会被 DispatcherServlet 捕获和处理。最后,我们将 DispatcherServletRegistrationBean 对象返回,用于将 DispatcherServlet 注册到 Servlet 容器中。

Bean的生命周期

简单阶段

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

  1. 创建:根据 bean 的构造方法或者工厂方法来创建 bean 实例对象

  2. 依赖注入:根据 @Autowired,@Value 或其它一些手段,为 bean 的成员变量填充值、建立关系

  3. 初始化:回调各种 Aware 接口,调用对象的各种初始化方法

  4. 销毁:在容器关闭时,会销毁所有单例对象(即调用它们的销毁方法)

    • prototype 对象也能够销毁,不过需要容器这边主动调用

    创建
    依赖注入
    初始化
    可用
    销毁

typescript 复制代码
@Component
public class LifeCycleBean {
    private static final Logger log = LoggerFactory.getLogger(LifeCycleBean.class);
​
    public LifeCycleBean() {
        log.debug("构造");
    }
​
    @Autowired
    public void autowire(@Value("${JAVA_HOME}") String home) {
        log.debug("依赖注入: {}", home);
    }
​
    @PostConstruct
    public void init() {
        log.debug("初始化");
    }
​
    @PreDestroy
    public void destroy() {
        log.debug("销毁");
    }
}
  • 构造阶段

    在构造阶段中,Spring 容器会调用 Bean 的构造函数来创建实例,并将 Bean 的依赖项注入到构造函数中。如果 Bean 的构造函数需要依赖其他 Bean,Spring 容器会在构造函数调用之前先实例化这些依赖项。此外,如果 Bean 的构造函数需要进行一些初始化操作,例如设置默认值或分配内存空间,也可以在这个阶段完成。

  • 初始化阶段

    在初始化阶段中,Spring 容器会为 Bean 设置属性,注入依赖项,并调用 Bean 的各种生命周期回调方法。在这个阶段中,Bean 可以执行任何初始化逻辑,例如建立数据库连接、打开文件或初始化其他资源。常见的生命周期回调方法包括 @PostConstruct@PreDestroy 注解、实现 InitializingBeanDisposableBean 接口以及自定义的 Bean 后置处理器。这些回调方法可以让开发者在 Bean 初始化和销毁的不同阶段执行自定义的逻辑

  • 总结

    总的来说,构造阶段和初始化阶段是 Bean 生命周期中非常重要的两个阶段。构造阶段主要负责创建对象并分配内存空间,而初始化阶段主要负责将 Bean 实例变得完整,以便投入使用。在初始化阶段中,Bean 实例会得到属性值的赋值、依赖项的注入和自定义的初始化逻辑的执行。

示例

当 Spring 容器创建一个 Bean 实例时,它会经历两个阶段:构造阶段和初始化阶段。

在构造阶段中,Spring 容器会调用 Bean 的构造函数来创建实例,并将 Bean 的依赖项注入到构造函数中。在这个阶段,Bean 的属性尚未设置,因此不能执行任何操作依赖于属性的逻辑。下面是一个示例:

csharp 复制代码
public class MyBean {
    private String name;
​
    public MyBean(String name) {
        this.name = name;
        System.out.println("MyBean constructor called");
    }
​
    public void sayHello() {
        System.out.println("Hello, " + name);
    }
}

在初始化阶段中,Spring 容器会为 Bean 设置属性,注入依赖项,并调用 Bean 的各种生命周期回调方法。常见的生命周期回调方法包括 @PostConstruct@PreDestroy 注解、实现 InitializingBeanDisposableBean 接口以及自定义的 Bean 后置处理器。下面是一个示例:

csharp 复制代码
public class MyBean {
    private String name;
​
    public MyBean(String name) {
        this.name = name;
        System.out.println("MyBean constructor called");
    }
​
    @PostConstruct
    public void init() {
        System.out.println("MyBean init called");
    }
​
    public void sayHello() {
        System.out.println("Hello, " + name);
    }
​
    @PreDestroy
    public void destroy() {
        System.out.println("MyBean destroy called");
    }
}

在上面的示例中,@PostConstruct 注解标识的 init() 方法会在 Bean 初始化之后立即执行,@PreDestroy 注解标识的 destroy() 方法会在容器关闭时执行。这些方法可以执行任何初始化或清理逻辑。

在实际开发中,我们还可以通过自定义 Bean 后置处理器来扩展 Bean 的生命周期。下面是一个示例:

typescript 复制代码
public class MyBeanPostProcessor implements BeanPostProcessor {
​
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("MyBeanPostProcessor postProcessBeforeInitialization called for " + beanName);
        return bean;
    }
​
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("MyBeanPostProcessor postProcessAfterInitialization called for " + beanName);
        return bean;
    }
}

在上面的示例中,MyBeanPostProcessor 实现了 BeanPostProcessor 接口,并覆盖了 postProcessBeforeInitialization()postProcessAfterInitialization() 方法。这些方法会在 Bean 初始化之前和之后执行,可以用来定制 Bean 实例的创建过程。

当运行上述示例代码时,控制台的输出结果如下:

sql 复制代码
MyBean constructor called
MyBeanPostProcessor postProcessBeforeInitialization called for myBean
MyBean init called
MyBeanPostProcessor postProcessAfterInitialization called for myBean
Hello, world!
MyBean destroy called

可以看到,首先输出了 "MyBean constructor called",表示 Bean 的构造函数被调用,然后输出了 "MyBeanPostProcessor postProcessBeforeInitialization called for myBean",表示自定义的 Bean 后置处理器的 postProcessBeforeInitialization() 方法被调用。接着输出了 "MyBean init called",表示 @PostConstruct 注解标识的初始化方法被调用。然后输出了 "MyBeanPostProcessor postProcessAfterInitialization called for myBean",表示自定义的 Bean 后置处理器的 postProcessAfterInitialization() 方法被调用。最后输出了 "Hello, world!",表示 Bean 实例被完整地创建,并且可以执行其方法。最后输出了 "MyBean destroy called",表示 @PreDestroy 注解标识的销毁方法在容器关闭时被调用。

综上所述,构造阶段和初始化阶段是 Bean 生命周期中非常重要的两个阶段。在构造阶段中,Spring 容器会调用 Bean 的构造函数来创建实例,并将 Bean 的依赖项注入到构造函数中;在初始化阶段中,Spring 容器会为 Bean 设置属性,注入依赖项,并调用 Bean 的各种生命周期回调方法。

增强阶段

java 复制代码
@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {
​
    private static final Logger log = LoggerFactory.getLogger(MyBeanPostProcessor.class);
​
    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean"))
            log.debug("<<<<<< 销毁之前执行, 如 @PreDestroy");
    }
​
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean"))
            log.debug("<<<<<< 实例化之前执行, 这里返回的对象会替换掉原本的 bean");
        return null;
    }
​
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean")) {
            log.debug("<<<<<< 实例化之后执行, 这里如果返回 false 会跳过依赖注入阶段");
//            return false;
        }
        return true;
    }
​
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean"))
            log.debug("<<<<<< 依赖注入阶段执行, 如 @Autowired、@Value、@Resource");
        return pvs;
    }
​
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean"))
            log.debug("<<<<<< 初始化之前执行, 这里返回的对象会替换掉原本的 bean, 如 @PostConstruct、@ConfigurationProperties");
        return bean;
    }
​
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean"))
            log.debug("<<<<<< 初始化之后执行, 这里返回的对象会替换掉原本的 bean, 如代理增强");
        return bean;
    }
}

创建前后的增强

  • postProcessBeforeInstantiation

    • 这里返回的对象若不为 null 会替换掉原本的 bean,并且仅会走 postProcessAfterInitialization 流程
  • postProcessAfterInstantiation

    • 这里如果返回 false 会跳过依赖注入阶段

依赖注入前的增强

  • postProcessProperties

    • 如 @Autowired、@Value、@Resource

初始化前后的增强

  • postProcessBeforeInitialization

    • 这里返回的对象会替换掉原本的 bean
    • 如 @PostConstruct、@ConfigurationProperties
  • postProcessAfterInitialization

    • 这里返回的对象会替换掉原本的 bean
    • 如代理增强

销毁之前的增强

  • postProcessBeforeDestruction

    • 如 @PreDestroy

模板设计模式

014-第三讲-模板方法哔哩哔哩bilibili

大流程已经固定好了, 通过接口回调(bean 后处理器)在一些关键点前后提供扩展

csharp 复制代码
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); // 对依赖注入阶段的扩展
    }
}

运行该代码,控制台输出的结果如下:

kotlin 复制代码
构造 java.lang.Object@5cad8086
依赖注入 java.lang.Object@5cad8086
解析 @Autowired
解析 @Resource
初始化 java.lang.Object@5cad8086

可以看到,按照 getBean() 方法中定义的算法骨架,首先构造了一个 Object 对象,然后进行依赖注入,接着通过添加的两个 BeanPostProcessor 对象,分别解析了 @Autowired@Resource 注解。最后进行了初始化,并输出了相关信息。

  • getBean() 方法定义了一个算法的骨架,包含了构造、依赖注入、初始化等步骤,其中 依赖注入 步骤的实现是采用了模板方法设计模式中的典型做法,即将其实现委托给实现 BeanPostProcessor 接口的类。这样,子类可以通过实现 BeanPostProcessor 接口,对依赖注入 步骤进行自定义扩展,而不需要改变算法的结构。
  • 可以看到,在该算法中,依赖注入步骤的具体实现是由添加的 BeanPostProcessor 对象实现的,这展示了模板方法设计模式的灵活性和可扩展性。
相关推荐
bug菌¹42 分钟前
滚雪球学SpringCloud[4.2讲]: Zuul:Netflix API Gateway详解
spring·spring cloud·gateway
小哇6661 小时前
spring-TransactionTemplate 编程式事务
数据库·spring
计算机学姐2 小时前
基于python+django+vue的影视推荐系统
开发语言·vue.js·后端·python·mysql·django·intellij-idea
JustinNeil2 小时前
简化Java对象转换:高效实现大对象的Entity、VO、DTO互转与代码优化
后端
ChinaRainbowSea2 小时前
十三,Spring Boot 中注入 Servlet,Filter,Listener
java·spring boot·spring·servlet·web
小游鱼KF2 小时前
Spring学习前置知识
java·学习·spring
青灯文案12 小时前
SpringBoot 项目统一 API 响应结果封装示例
java·spring boot·后端
微尘83 小时前
C语言存储类型 auto,register,static,extern
服务器·c语言·开发语言·c++·后端
计算机学姐3 小时前
基于PHP的电脑线上销售系统
开发语言·vscode·后端·mysql·编辑器·php·phpstorm
阿乾之铭4 小时前
spring MVC 拦截器
java·spring·mvc