资讯详情

全面深度讲解spring5底层原理二(6-12讲)

转载自:https://blog.csdn.net/qq_38505969/article/details/123739542

介绍

代码仓库地址:https://gitee.com/CandyWall/spring-source-study 跟着做学习笔记,这个笔记和视频内容的项目名称和代码略有不同。我把49个代码的每个代码拆分成独立的springboot项目,并且项目名称尽量做到了见名知意,都是基于我自己的考量,代码都已经过运行验证过的,仅供参考。

视频教程地址:https://www.bilibili.com/video/BV1P44y1N7QG

注:

1. 每个对应一个二级标题,每个三级标题都是用子项目名命名的,与我的代码仓库项目一一对应; 2. 使用代码lombok简化了插件Bean中的get()、set()使用方法和日志记录lombok的@Slf4j注解。

每个子项目对应的视频链接和一些重要内容的笔记

第六讲 Aware和InitializingBean接口以及@Autowired注解故障分析

spring_06_aware_initializingbean

p26 025-第六讲-Aware与InitializingBean接口

Aware 接口用于注入与容器相关的信息,例如:

a. BeanNameAware 注入 Bean 的名字

b. BeanFactoryAware 注入 BeanFactory 容器

c. ApplicationContextAware 注入 ApplicationContext 容器

d. EmbeddedValueResolverAware 注入 分析,分析${}

定义一个MyBean类,实现BeanNameAwareApplicationContextAwareInitializingBean接口和实现方法,然后定义两种方法,其中一种是添加的@Autowired注解,注入ApplicationContext容器,另一个加@PostConstruct具体代码如下:

public class MyBean implements BeanNameAware, ApplicationContextAware, InitializingBean { 
                @Override     public void setBeanName(String name) { 
                    log.debug("当前bean:"   this   ",实现 BeanNameAware 调用方法,名称为:"   name);     }     @Override     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
                    log.debug("当前bean:"   this   ",实现 ApplicationContextAware 调用方法,容器称:"   applicationContext);     }     @Override     public void afterPropertiesSet() throws Exception { 
           
        log.debug("当前bean:" + this + ",实现 InitializingBean 调用的方法,初始化");
    }
    @Autowired
    public void aaa(ApplicationContext applicationContext) { 
           
        log.debug("当前bean:" + this +",使用 @Autowired 容器是:" + applicationContext);
    }
    @PostConstruct
    public void init() { 
           
        log.debug("当前bean:" + this + ",使用 @PostConstruct 初始化");
    }
}

测试代码:

public class TestAwareAndInitializingBean { 
           
    @Test
    public void testAware1() throws Exception { 
           
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("myBean", MyBean.class);
        context.refresh();
        context.close();
    }
}

运行结果:

image-20220330173209568

加了@Autowired@PostConstruct注解的方法并没有被执行,而AwareInitializingBean接口方法都被执行了。

修改测试代码,把解析@Autowired@PostConstruct注解的Bean后处理加进来,然后再运行一下

public class TestAwareAndInitializingBean { 
           
    @Test
    public void testAware1() throws Exception { 
           
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("myBean", MyBean.class);
        // 解析 @Autowired 注解的Bean后处理器
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
        // 解析 @PostConstruct 注解的Bean后处理器
        context.registerBean(CommonAnnotationBeanPostProcessor.class);
        context.refresh();
        context.close();
    }
}

运行结果:

可以看到这下都执行了

有人可能会问:bcd的功能用 @Autowired注解就能实现啊,为啥还要用 Aware 接口呢? InititalizingBean 接口可以用 @PostConstruct注解实现,为啥还要用InititalizingBean呢? 简单地说:

  • @Autowired@PostConstruct注解的解析需要用到 Bean 后处理器,属于扩展功能,而 Aware 接口属于内置功能,不加任何扩展,Spring就能识别;

  • 某些情况下,扩展功能会失效,而内置功能不会失效

    p27 026-第六讲-@Autowired失效分析

    • 例1:比如没有把解析@Autowired@PostStruct注解的Bean的后处理器加到Bean工厂中,你会发现用 Aware 注入 ApplicationContext 成功, 而 @Autowired 注入 ApplicationContext 失败

    • 例2:定义两个Java Config类(类上加@Configuration注解),名字分别叫MyConfig1MyConfig2,都实现注入ApplicationContext容器和初始化功能,MyConfig1@Autowired@PostConstruct注解实现,MyConfig2用实现AwareInitializingBean接口的方式实现,另外,两个Config类中都通过@Bean注解的方式注入一个BeanFactoryPostProcessor,代码如下:

      MyConfig1:

      @Slf4j
      public class MyConfig1 { 
                     
          @Autowired
          public void setApplicationContext(ApplicationContext applicationContext) { 
                     
              log.debug("注入 ApplicationContext");
          }
          @PostConstruct
          public void init() { 
                     
              log.debug("初始化");
          }
          @Bean
          public BeanFactoryPostProcessor processor1() { 
                     
              return beanFactory -> { 
                     
                  log.debug("执行 processor1");
              };
          }
      }
      

      测试代码:

      @Slf4j
      public class TestAwareAndInitializingBean { 
                     
          @Test
          public void testAware_MyConfig1() { 
                     
              GenericApplicationContext context = new GenericApplicationContext();
              // MyConfig1没有加上@
              context.registerBean("myConfig1", MyConfig1.class);
              // 解析 @Autowired 注解的Bean后处理器
              context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
              // 解析 @PostConstruct 注解的Bean后处理器
              context.registerBean(CommonAnnotationBeanPostProcessor.class);
              // 解析@ComponentScan、@Bean、@Import、@ImportResource注解的后处理器
              // 这个后处理器不加出不来效果
              context.registerBean(ConfigurationClassPostProcessor.class);
              // 1. 添加beanfactory后处理器;2. 添加bean后处理器;3. 初始化单例。
              context.refresh();
              context.close();
      }
      

      运行结果:

      MyConfig2:

      @Slf4j
      public class MyConfig2 implements ApplicationContextAware, InitializingBean { 
                     
          @Override
          public void setApplicationContext(ApplicationContext applicationContext) { 
                     
              log.debug("注入 ApplicationContext");
          }
          @Override
          public void afterPropertiesSet() throws Exception { 
                     
              log.debug("初始化");
          }
          @Bean
          public BeanFactoryPostProcessor processor1() { 
                     
              return beanFactory -> { 
                     
                  log.debug("执行 processor1");
              };
          }
      }
      

      测试代码:

      @Slf4j
      public class TestAwareAndInitializingBean { 
                     
          @Test
          public void testAutowiredAndInitializingBean_MyConfig2() { 
                     
              GenericApplicationContext context = new GenericApplicationContext();
              context.registerBean("myConfig2", MyConfig2.class);
              // 1. 添加beanfactory后处理器;2. 添加bean后处理器;3. 初始化单例。
              context.refresh();
              context.close();
          }
      }
      

      运行结果:

      Java配置类在添加了 bean 工厂后处理器后,你会发现用传统接口方式的注入和初始化依然成功,而 @Autowired@PostConstruct 的注入和初始化失败。

      那是什么原因导致的呢?

      配置类 @Autowired 注解失效分析

      • Java 配置类不包含 BeanFactoryPostProcessor 的情况

        ApplicationContext BeanFactoryPostProcessor BeanPostProcessor Java配置类 3. 创建和初始化 3.1 执行 Aware 及 InitializingBean 3.2 创建成功 1. 执行 BeanFactoryPostProcessor 2. 注册 BeanPostProcessor ApplicationContext BeanFactoryPostProcessor BeanPostProcessor Java配置类

总结:

  • Aware 接口提供了一种【内置】 的注入手段,可以注入 BeanFactoryApplicationContext
  • InitializingBean 接口提供了一种 【内置】 的初始化手段;
  • 内置的注入和初始化不收扩展功能的影响,总会被执行,因此 spring 框架内部的类常用它们。

第七讲 Bean的初始化与销毁

spring_07_init_destroy

p28 027-第七讲-初始化与销毁

定义Bean1类,实现InitializingBean接口和对应的接口方法afterPropertiesSet(),再定义init1()方法,在方法上加@PostConstruct注解,最后定义init3()

@Slf4j
public class Bean1 implements InitializingBean { 
           
    @PostConstruct
    public void init1() { 
           
        log.debug("初始化1,@PostConstruct");
    }
    @Override
    public void afterPropertiesSet() throws Exception { 
           
        log.debug("初始化2,InitializingBean接口");
    }
    public void init3() { 
           
        log.debug("初始化3,@Bean的initMethod");
    }
}

定义Bean2类,实现DisposableBean接口和对应的接口方法destroy(),再定义destroy1()方法,在方法上加@PreDestroy注解,最后定义init3()

@Slf4j
public class Bean2 implements DisposableBean { 
           
    @PreDestroy
    public void destroy1() { 
           
        log.debug("销毁1,@PreDestory");
    }
    @Override
    public void destroy() throws Exception { 
           
        log.debug("销毁2,DisposableBean接口");
    }
    public void destroy3() { 
           
        log.debug("销毁3,@Bean的destroyMethod");
    }
}

定义Config类,类上加@Configuration注解,类中通过@Bean注解把Bean1Bean2加到Bean工厂中,分别在@Bean注解中指定initMethod = "init3",destroyMethod = "destroy"

@Configuration
public class Config { 
           
    @Bean(initMethod = "init3")
    public Bean1 bean1() { 
           
        return new Bean1();
    }
    @Bean(destroyMethod = "destroy3")
    public Bean2 bean2() { 
           
        return new Bean2();
    }
}

编写测试代码,观察三个初始化方法和三个销毁方法的执行顺序

@Slf4j
public class TestInitAndDestroy { 
           
    @Test
    public void testInitAndDestroy() throws Exception { 
           
        // ⬇️GenericApplicationContext 是一个【干净】的容器,这里只是为了看初始化步骤,就不用springboot启动类进行演示了
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
        // 解析@PostConstruct注解的bean后处理器
        context.registerBean(CommonAnnotationBeanPostProcessor.class);
        // 解析@Configuration、@Component、@Bean注解的bean工厂后处理器
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.refresh();
        context.close();
    }
}

运行结果:

可以看到,spring提供了多种初始化和销毁手段

  • 对于init,三个初始化方法的执行顺序是

    @PostConstruct -> InitializingBean接口 -> @BeaninitMethod

  • 对于destory, 三个销毁方法的执行顺序是

    @PreDestroy -> DisposableBean接口 -> @Beandestroy

第八讲 Scope类型、注意事项、销毁和失效分析

spring_08_scope

p29 028-第八讲-Scope

springscope类型:

  • singleton:单例
  • prototype:多例
  • requestweb请求
  • sessionweb的会话
  • applicationwebServletContext

测试scope类型中的requestsessionapplication

定义**BeanForRequestrequest**,在类型中定义destroy()方法,方法上加@PreDestory注解,代码如下:

@Slf4j
@Scope("request")
@Component
public class BeanForRequest { 
           
    @PreDestroy
    public void destory() { 
           
        log.debug("destroy");
    }
}

定义**BeanForSessionsession**,在类型中定义destroy()方法,方法上加@PreDestory注解,代码如下:

@Slf4j
@Scope("request")
@Component
public class BeanForRequest { 
           
    @PreDestroy
    public void destory() { 
           
        log.debug("destroy");
    }
}

定义**BeanForApplicationapplication**,在类型中定义destroy()方法,方法上加@PreDestory注解,代码如下:

@Slf4j
@Scope("request")
@Component
public class BeanForRequest 

标签: p119举升传感器p150光电传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台