Spring原理学习

2023年 8月 7日 36.5k 0

Spring原理学习

容器与Bean

BeanFactory和ApplicationContext

BeanFactory

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

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

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

    image-20230715202055540

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

    image-20230715193310451

  • 表面上只有 getBean

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

ApplicationContext

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

image-20230715201426474

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

    • 国际化

      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

      hi=Hello
      

      messages_ja.properties

      hi=こんにちは
      

      messages_zh.properties

      hi=你好
      

      注意

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

      image-20230715202453748

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

      image-20230715202533236

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

事件驱动

概述

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

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

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 类需要知道有哪些服务类需要被调用,并且需要知道这些服务类的具体实现。这样会导致代码的可维护性和灵活性变差。

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

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 中使用事件驱动编程:

  • 创建事件类。事件类应该继承自 ApplicationEvent 类,并且包含一些与事件相关的属性和方法。
  • public class UserRegisteredEvent extends ApplicationEvent {
        private User user;
    ​
        public UserRegisteredEvent(Object source, User user) {
            super(source);
            this.user = user;
        }
    ​
        public User getUser() {
            return user;
        }
    }
    
  • 在发布事件的组件中注入 ApplicationEventPublisher 对象,并使用 publishEvent() 方法发布事件。
  • @Component
    public class UserService {
        @Autowired
        private ApplicationEventPublisher eventPublisher;
    ​
        public void register(User user) {
            // 注册用户
            //...
    ​
            // 发布用户注册事件
            eventPublisher.publishEvent(new UserRegisteredEvent(this, user));
        }
    }
    
  • 在监听事件的组件中使用 @EventListener 注解来监听事件,并在事件发生时执行相应的处理逻辑。
  • @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 配置文件中添加以下配置:

    
    

    这样,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

    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 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 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

    /*
        常见 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("srcmainresourcesa02.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(
                            "srcmainresourcesa02.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,生命周期主要阶段有

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

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

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

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

    • prototype 对象也能够销毁,不过需要容器这边主动调用
  • 创建
    依赖注入
    初始化
    可用
    销毁
    
    @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 的属性尚未设置,因此不能执行任何操作依赖于属性的逻辑。下面是一个示例:

    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 后置处理器。下面是一个示例:

    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 的生命周期。下面是一个示例:

    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 实例的创建过程。

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

    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 的各种生命周期回调方法。

    增强阶段

    @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("

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论