Spring高级(一)—— 容器与Bean

目录

1、容器接口

1、BeanFactory 与 ApplicationContext 的区别

2、国际化(MessageSource)

3、根据通配符获取资源(ResourcePatternResolver)

 4、获取配置信息(EnvironmentCapable)

5、发送事件(ApplicationEventPublisher)

2、容器实现

1、BeanFactory的实现

2、ApplicationContext的实现

3、Bean的生命周期

1、Bean的生命周期

 2、模板方法设计模式

3、 bean后处理器的排序

4、bean后处理器

​编辑  

@Autowired bean 后处理器运行分析

5、BeanFactory后处理器

1、工厂后处理器的模拟实现——@ComponentScan

2、工厂后处理器的模拟实现——@Bean

 3、工厂后处理器的模拟实现——@MapperScan

6、Aware接口

配置类 @Autowired 失效分析

 7、初始化与销毁

8、Scope

singleton 注入其它 scope 失效


1、容器接口

  • BeanFactory 接口,典型功能有:

    • getBean

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

    • 国际化

    • 通配符方式获取一组 Resource 资源

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

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

1、BeanFactory 与 ApplicationContext 的区别

 

  1. 到底什么是 BeanFactory?

    • 它是 ApplicationContext 的父接口

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

  2. BeanFactory 能干点啥?

    • 表面上只有 getBean

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

    • 例子中通过反射查看了它的成员变量 singletonObjects,内部包含了所有的单例 bean

@SpringBootApplication
public class SpringbootMybatisApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootMybatisApplication.class, args);

        Field singletonObjects = null;
        try {
            singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
            singletonObjects.setAccessible(true);

            ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
            Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);

            map.forEach((k,v) -> {
                if(k.contains("component")){
                    System.out.println(k+"=="+v);
                }

            });
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

  1. ApplicationContext 比 BeanFactory 多点啥?
    • ApplicationContext 组合并扩展了 BeanFactory 的功能

    • 国际化、通配符方式获取一组 Resource 资源、整合 Environment 环境、事件发布与监听

    • 新学一种代码之间解耦途径,事件解耦

2、国际化(MessageSource)

        System.out.println(context.getMessage("hi",null, Locale.CHINA));
        System.out.println(context.getMessage("hi",null, Locale.ENGLISH));

 

#国际化
spring.messages.basename=i18n.messages
spring.messages.encoding=utf-8
  • ApplicationContext 中 MessageSource bean 的名字固定为 messageSource
  • 使用 SpringBoot 时,国际化文件名固定为 messages
  • 空的 messages.properties 也必须存在

3、根据通配符获取资源(ResourcePatternResolver)

        //classpath表示到类路径下找
        //Resource[] resources = context.getResources("classpath:application.properties");
        //加 * 可以获取jar中的文件
        Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
        for (Resource resource : resources) {
            System.out.println(resource);
        }

 4、获取配置信息(EnvironmentCapable)

        //不区分大小写,可以获取系统配置信息,或者配置文件中的信息
        System.out.println(context.getEnvironment().getProperty("java_home"));
        System.out.println(context.getEnvironment().getProperty("spring.messages.encoding"));

5、发送事件(ApplicationEventPublisher)

//        context.publishEvent(new MyEvent(context));
        context.getBean(Component1.class).register();
public class MyEvent extends ApplicationEvent {
    public MyEvent(Object source) {
        super(source);
    }
}
@Component
public class Component1 {

    @Autowired
    private ApplicationEventPublisher publisher;

    public void  register(){
        System.out.println("用户注册");
        publisher.publishEvent(new MyEvent(this));
    }
}
@Component
public class Component2 {

    @EventListener
    public void listen(MyEvent event){
        System.out.println(event);
        System.out.println("发送短信");
    }
}

2、容器实现

1、BeanFactory的实现

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

        // 给 BeanFactory 添加一些常用的后处理器(给bean工厂添加后处理器)
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
        //建立后处理器与beanFactory的联系
        // BeanFactory 后处理器主要功能,补充了一些 bean 定义,解析 @Bean
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });

        // Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
        //后处理器是按顺序执行的,通过选择器改变后处理器的顺序
        //他们都实现了 Order 接口,通过getOrder 方法,值越小优先级越高
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
                .sorted(beanFactory.getDependencyComparator()).forEach(beanPostProcessor -> {
            System.err.println(">>>>>>"+beanPostProcessor);
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        });
        //准备好所有单例(提前创建),默认延迟创建
        beanFactory.preInstantiateSingletons();

        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.err.println(name);
        }
        System.err.println("====================");
        System.err.println(beanFactory.getBean(Bean1.class).getBean2());
        /*
            a. beanFactory 不会做的事
                   1. 不会主动调用 BeanFactory 后处理器
                   2. 不会主动添加 Bean 后处理器
                   3. 不会主动初始化单例
                   4. 不会解析beanFactory 还不会解析 ${ } 与 #{ }
            b. bean 后处理器会有排序的逻辑
         */
        System.out.println("================");
        System.out.println(beanFactory.getBean(Bean1.class).getIner());

    }

    @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();
        }
    }

    static  class Bean1{
        public Bean1() {
            System.out.println("bean1初始化");
        }

        @Autowired
        private Bean2 bean2;

        public Bean2 getBean2(){
            return bean2;
        }

//        @Autowired
        @Resource(name = "bean4")
        private Iner bean3;

        public Iner getIner(){
            return bean3;
        }
    }

    static  class Bean2{
        public Bean2() {
            System.out.println("bean2初始化");
        }
    }

    interface Iner{

    }

    static class Bean3 implements Iner{
        public Bean3() {
            System.out.println("bean3初始化");
        }
    }

    static class Bean4 implements Iner{
        public Bean4() {
            System.out.println("bean4初始化");
        }
    }
}
  • 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 需要额外设置才能解析 ${} 与 #{}

2、ApplicationContext的实现

public class TestApplication {
    public static void main(String[] args) {

        test4();
//        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//        System.err.println("------读取之前------");
//        for (String name : beanFactory.getBeanDefinitionNames()) {
//            System.out.println(name);
//        }
//
//        System.err.println("------读取之后------");
//        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
//        reader.loadBeanDefinitions(new ClassPathResource("b01.xml"));
//        for (String name : beanFactory.getBeanDefinitionNames()) {
//            System.err.println(name);
//        }
    }

    //基于 classpath 下 xml 格式的配置文件来创建
    private static void test1(){
        ClassPathXmlApplicationContext context
                = new ClassPathXmlApplicationContext("b01.xml");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(">>>>>"+name);
        }

        System.err.println(context.getBean(Bean2.class).getBean1());
    }

    //基于磁盘路径下 xml 格式的配置文件来创建
    public static void test2(){
        FileSystemXmlApplicationContext context
                = new FileSystemXmlApplicationContext("D:\\IntelliJ IDEA\\test\\springboot-mybatis\\src\\main\\resources\\b01.xml");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(">>>>>"+name);
        }

        System.err.println(context.getBean(Bean2.class).getBean1());
    }

    //基于 java 配置类来创建
    public static void test3(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(">>>>>"+name);
        }

        System.err.println(context.getBean(Bean2.class).getBean1());
    }

    //基于 java 配置类来创建, 用于 web 环境
    public static void test4(){
        AnnotationConfigServletWebServerApplicationContext context
                = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
    }

    @Configuration
    static class WebConfig{
        //tomcat的webServer服务器
        @Bean
        public ServletWebServerFactory servletWebServerFactory(){
            return new TomcatServletWebServerFactory();
        }

        //dispatcher
        @Bean
        public DispatcherServlet dispatcherServlet() {
            return new DispatcherServlet();
        }

        //给dispatcher一个路径注册到tomcat服务器
        @Bean
        public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet){
            return new DispatcherServletRegistrationBean(dispatcherServlet,"/");
        }

        //控制器
        @Bean("/hello")
        public Controller controller(){
            return (request, response) -> {
                response.getWriter().println("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 version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="bean1" class="com.springboot.springbootmybatis.TestApplication.Bean1"/>

    <bean id="bean2" class="com.springboot.springbootmybatis.TestApplication.Bean2">
        <property name="bean1" ref="bean1" />
    </bean>

    <!--加入了一些后处理器-->
    <context:annotation-config />

</beans>
  1. 常见的 ApplicationContext 容器实现

  2. 内嵌容器、DispatcherServlet 的创建方法、作用

3、Bean的生命周期

1、Bean的生命周期

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

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

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

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

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

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

@SpringBootApplication
public class Day3Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Day3Application.class, args);
        context.close();
    }
}
@Component
public class LifeCycleBean {

    public LifeCycleBean(){
        System.err.println("构造。。。");
    }

    @Autowired
    public void autowire(@Value("${JAVA_HOME}") String home){
        System.err.println("依赖注入:"+home);
    }

    @PostConstruct
    public void init(){
        System.err.println("初始化。。。");
    }

    @PreDestroy
    public void destory(){
        System.err.println("销毁。。。");
    }
}
@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {


    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean"))
            System.err.println("<<<<<< 销毁之前执行, 如 @PreDestroy");
    }

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean"))
            System.err.println("<<<<<< 实例化之前执行, 这里返回的对象会替换掉原本的 bean");
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean")) {
            System.err.println("<<<<<< 实例化之后执行, 这里如果返回 false 会跳过依赖注入阶段");
//            return false;
        }
        return true;
    }

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean"))
            System.err.println("<<<<<< 依赖注入阶段执行, 如 @Autowired、@Value、@Resource");
        return pvs;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean"))
            System.err.println("<<<<<< 初始化之前执行, 这里返回的对象会替换掉原本的 bean, 如 @PostConstruct、@ConfigurationProperties");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean"))
            System.err.println("<<<<<< 初始化之后执行, 这里返回的对象会替换掉原本的 bean, 如代理增强");
        return bean;
    }
}

 

创建前后的增强

  • postProcessBeforeInstantiation

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

  • postProcessAfterInstantiation

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

依赖注入前的增强

  • postProcessProperties

    • 如 @Autowired、@Value、@Resource

初始化前后的增强

  • postProcessBeforeInitialization

    • 这里返回的对象会替换掉原本的 bean

    • 如 @PostConstruct、@ConfigurationProperties

  • postProcessAfterInitialization

    • 这里返回的对象会替换掉原本的 bean

    • 如代理增强

销毁之前的增强

  • postProcessBeforeDestruction

    • 如 @PreDestroy

 2、模板方法设计模式

public class TestMethodTemplate {

    public static void main(String[] args) {

        MyBeanFactory beanFactory = new MyBeanFactory();
        beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
            @Override
            public void inject(Object bean) {
                System.out.println("解析 @Autowired");
            }
        });
        beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Resource"));
        beanFactory.getBean();
    }

    static class MyBeanFactory{
        private List<BeanPostProcessor> processorList = new ArrayList<>();

        public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor){
            processorList.add(beanPostProcessor);
        }

        public void getBean(){
            Object bean = new Object();
            System.err.println("构造:"+bean);
            System.err.println("依赖注入:"+bean);
            for (BeanPostProcessor beanPostProcessor : processorList) {
                beanPostProcessor.inject(bean);
            }
            System.err.println("初始化:"+bean);
        }

    }

    //将不确定的部分抽象成接口
    static interface BeanPostProcessor{
        public void inject(Object bean);
    }
}

3、 bean后处理器的排序

/*
    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;
        }
    }
}
  1. 实现了 PriorityOrdered 接口的优先级最高

  2. 实现了 Ordered 接口与加了 @Order 注解的平级, 按数字升序

  3. 其它的排在最后

4、bean后处理器

作用:为bean生命周期各个阶段提供扩展

public class DayApplication {

    public static void main(String[] args) {
        //GenericApplicationContext 是一个【干净】的容器
        GenericApplicationContext context = new GenericApplicationContext();

        context.registerBean("bean1",Bean1.class);
        context.registerBean("bean2", Bean2.class);
        context.registerBean("bean3", Bean3.class);
        context.registerBean("bean4",Bean4.class);

        //@Value中值的获取
        context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);//@Autowired @Value(依赖注入)

        //@Resource(依赖注入) @PostConstruct(初始化前) @PreDestroy(销毁前)
        context.registerBean(CommonAnnotationBeanPostProcessor.class);

        //完成属性的绑定(初始化前)
        ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());

        //初始化容器
        context.refresh();//执行beanFactory后处理器, 添加bean后处理器, 初始化所有单例
        System.err.println(context.getBean(Bean4.class));
        //销毁容器
        context.close();
    }
}
public class Bean1 {

    private Bean2 bean2;

    @Autowired
    private void setBean2(Bean2 bean2){
        this.bean2 = bean2;
        System.err.println("@Autowired生效:"+bean2);
    }


    private Bean3 bean3;

    @Resource
    public void setBean3(Bean3 bean3){
        this.bean3 = bean3;
        System.err.println("@Resource生效:"+bean3);
    }

    private String home;

    @Autowired
    private void setHome(@Value("${JAVA_HOME}") String home){
        this.home = home;
        System.err.println("Value生效:"+home);
    }

    @PostConstruct
    public void init(){
        System.err.println("初始化。。。");
    }

    @PreDestroy
    public void destory(){
        System.err.println("销毁。。。");
    }

    @Override
    public String toString() {
        return "Bean1{" +
                "bean2=" + bean2 +
                ", bean3=" + bean3 +
                ", home='" + home + '\'' +
                '}';
    }
}
@ConfigurationProperties(prefix = "java")
public class Bean4 {
    private String home;

    private String  version;

    public String getHome() {
        return home;
    }

    public void setHome(String home) {
        this.home = home;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    @Override
    public String toString() {
        return ">>>>>Bean4{" +
                "home='" + home + '\'' +
                ", version='" + version + '\'' +
                '}';
    }
}

  

  1. @Autowired 等注解的解析属于 bean 生命周期阶段(依赖注入, 初始化)的扩展功能,这些扩展功能由 bean 后处理器来完成

  2. 每个后处理器各自增强什么功能

    • AutowiredAnnotationBeanPostProcessor 解析 @Autowired 与 @Value

    • CommonAnnotationBeanPostProcessor 解析 @Resource、@PostConstruct、@PreDestroy

    • ConfigurationPropertiesBindingPostProcessor 解析 @ConfigurationProperties

  3. 另外 ContextAnnotationAutowireCandidateResolver 负责获取 @Value 的值,解析 @Qualifier、泛型、@Lazy 等

@Autowired bean 后处理器运行分析

// AutowiredAnnotationBeanPostProcessor 运行分析
public class MyAutowired {

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        beanFactory.registerSingleton("bean2",new Bean2());// 任务是个成品的bean,不会走创建过程,依赖注入,初始化
        beanFactory.registerSingleton("bean3",new Bean3());
        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());// @Value

        AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
        processor.setBeanFactory(beanFactory);

        Bean1 bean1 = new Bean1();
        System.out.println(">>>>>>"+bean1);
        processor.postProcessProperties(null,bean1,"bean1");
        System.out.println(">>>>>>"+bean1);
    }
}

调用方式: 

 

        Bean1 bean1 = new Bean1();
//        System.out.println(">>>>>>"+bean1);
//        processor.postProcessProperties(null,bean1,"bean1");
//        System.out.println(">>>>>>"+bean1);

        Method method = processor.getClass().getDeclaredMethod("findAutowiringMetadata", String.class,Class.class, PropertyValues.class);
        method.setAccessible(true);
        // 获取 Bean1 上加了 @Value @Autowired 的成员变量,方法参数信息
        InjectionMetadata metadata = (InjectionMetadata) method.invoke(processor, "bean1", bean1.getClass(), null);

        // 2. 调用 InjectionMetadata 来进行依赖注入, 注入时按类型查找值
        metadata.inject(bean1,"bean1",null);
        System.out.println(">>>>>>"+bean1);

 InjectionMetadata中的属性:

 

// AutowiredAnnotationBeanPostProcessor 运行分析
public class MyAutowired {

    public static void main(String[] args) throws Throwable {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        beanFactory.registerSingleton("bean2",new Bean2());// 任务是个成品的bean,不会走创建过程,依赖注入,初始化
        beanFactory.registerSingleton("bean3",new Bean3());
        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());// @Value
        beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders);

        AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
        processor.setBeanFactory(beanFactory);

        Bean1 bean1 = new Bean1();
//        System.out.println(">>>>>>"+bean1);
//        processor.postProcessProperties(null,bean1,"bean1");
//        System.out.println(">>>>>>"+bean1);

//        Method method = processor.getClass().getDeclaredMethod("findAutowiringMetadata", String.class,Class.class, PropertyValues.class);
//        method.setAccessible(true);
//        // 获取 Bean1 上加了 @Value @Autowired 的成员变量,方法参数信息
//        InjectionMetadata metadata = (InjectionMetadata) method.invoke(processor, "bean1", bean1.getClass(), null);

        // 2. 调用 InjectionMetadata 来进行依赖注入, 注入时按类型查找值
//        metadata.inject(bean1,"bean1",null);
//        System.out.println(">>>>>>"+bean1);

        Field bean3 = bean1.getClass().getDeclaredField("bean3");
        //ctrl+p 可显示需要的参数,将属性、方法封装到 DependencyDescriptor中
        DependencyDescriptor dd1 = new DependencyDescriptor(bean3,false);
        //找到要注入的对象
        Object o1 = beanFactory.doResolveDependency(dd1, null, null, null);
        System.err.println(o1);

        Method setBean2 = bean1.getClass().getDeclaredMethod("setBean2", Bean2.class);
        DependencyDescriptor dd2 =
                new DependencyDescriptor(new MethodParameter(setBean2,0),false);
        Object o2 = beanFactory.doResolveDependency(dd2, null, null, null);
        System.err.println(o2);

        Method setHome = bean1.getClass().getDeclaredMethod("setHome", String.class);
        DependencyDescriptor dd3 =
                new DependencyDescriptor(new MethodParameter(setHome,0),false);
        Object o3 = beanFactory.doResolveDependency(dd3, null, null, null);
        System.err.println(o3);

    }
}

 

  1. AutowiredAnnotationBeanPostProcessor.findAutowiringMetadata 用来获取某个 bean 上加了 @Value @Autowired 的成员变量,方法参数的信息,表示为 InjectionMetadata

  2. InjectionMetadata 可以完成依赖注入

  3. InjectionMetadata 内部根据成员变量,方法参数封装为 DependencyDescriptor 类型

  4. 有了 DependencyDescriptor,就可以利用 beanFactory.doResolveDependency 方法进行基于类型的查找

5、BeanFactory后处理器

@SpringBootApplication
public class Day5Application {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config",Config.class);

        //可解析 @ComponentScan @Bean @Import @ImportResource
        context.registerBean(ConfigurationClassPostProcessor.class);
        // @MapperScanner
        context.registerBean(MapperScannerConfigurer.class,beanDefinition -> {
            beanDefinition.getPropertyValues().add("basePackage","com.springboot.springbootmybatis.day5.mapper");
        });
        context.refresh();

        for (String name : context.getBeanDefinitionNames()) {
            System.err.println(name);
        }

        context.close();
    }
}
@Configuration
@ComponentScan("com.springboot.springbootmybatis.day5.component")
public class Config {
    @Bean
    public Bean1 bean1() {
        return new Bean1();
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }

    @Bean(initMethod = "init")
    public DruidDataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/my");
        dataSource.setUsername("root");
        dataSource.setPassword("mysql");
        return dataSource;
    }

/*    @Bean
    public MapperFactoryBean<Mapper1> mapper1(SqlSessionFactory sqlSessionFactory) {
        MapperFactoryBean<Mapper1> factory = new MapperFactoryBean<>(Mapper1.class);
        factory.setSqlSessionFactory(sqlSessionFactory);
        return factory;
    }

    @Bean
    public MapperFactoryBean<Mapper2> mapper2(SqlSessionFactory sqlSessionFactory) {
        MapperFactoryBean<Mapper2> factory = new MapperFactoryBean<>(Mapper2.class);
        factory.setSqlSessionFactory(sqlSessionFactory);
        return factory;
    }*/
}

  • ConfigurationClassPostProcessor 可以解析

    • @ComponentScan

    • @Bean

    • @Import

    • @ImportResource

  • MapperScannerConfigurer 可以解析

    • Mapper 接口

  1. @ComponentScan, @Bean, @Mapper 等注解的解析属于核心容器(即 BeanFactory)的扩展功能

  2. 这些扩展功能由不同的 BeanFactory 后处理器来完成,其实主要就是补充了一些 bean 定义

1、工厂后处理器的模拟实现——@ComponentScan

 

public class MyPostProcessor implements BeanFactoryPostProcessor {

    @Override //context.refresh()时调用
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

        try{
            ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
            if(componentScan != null){
                for (String basePackage : componentScan.basePackages()) {
                    // com.itheima.a05.component -> classpath*:com/itheima/a05/component/**/*.class
                    String path = basePackage.replace(".","/")+"/**/*.class";
                    Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);

                    CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                    AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();

                    for (Resource resource : resources) {
                        MetadataReader reader = factory.getMetadataReader(resource);
//                    System.err.println("类的的信息:"+reader.getClassMetadata().getClassName());
//                    System.out.println("是否加了 @Componet:"+reader.getAnnotationMetadata().hasAnnotation(Component.class.getName()));
                        //间接加了,@Controller 上用了 @Component
//                    System.out.println("是否加了 @Componet 派生:"+reader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName()));

                        if(reader.getAnnotationMetadata().hasAnnotation(Component.class.getName())
                                || reader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName())){

                            AbstractBeanDefinition beanDefinition
                                    = BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName()).getBeanDefinition();
                            if(configurableListableBeanFactory instanceof DefaultListableBeanFactory){
                                DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
                                String name = generator.generateBeanName(beanDefinition, beanFactory);
                                beanFactory.registerBeanDefinition(name,beanDefinition);
                            }

                        }
                    }
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }
}

  

  1. Spring 操作元数据的工具类 CachingMetadataReaderFactory

  2. 通过注解元数据(AnnotationMetadata)获取直接或间接标注的注解信息

  3. 通过类元数据(ClassMetadata)获取类名,AnnotationBeanNameGenerator 生成 bean 名

  4. 解析元数据是基于 ASM 技术

2、工厂后处理器的模拟实现——@Bean

public class MyBeanPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        try{
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/springboot/springbootmybatis/day5/Config.class"));
            Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
            for (MethodMetadata method : methods) {
                System.err.println(method.getMethodName());

                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
                builder.setFactoryMethodOnBean(method.getMethodName(),"config");
                //对于构造、工厂方法的参数自动装配用 AUTOWIRE_CONSTRUCTOR
                builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
                //解析@Bean的属性:@Bean(initMethod = "init")
                String initMethod = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
                if(initMethod.length() > 0){
                    builder.setInitMethodName(initMethod);
                }

                AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
                if(configurableListableBeanFactory instanceof DefaultListableBeanFactory) {
                    DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
                    beanFactory.registerBeanDefinition(method.getMethodName(),beanDefinition);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }
}

 3、工厂后处理器的模拟实现——@MapperScan

public class MyMapperPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        try {
            PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resolver.getResources("classpath:com/springboot/springbootmybatis/day5/**/*.class");
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();

            for (Resource resource : resources) {
                MetadataReader reader = factory.getMetadataReader(resource);
                ClassMetadata metadata = reader.getClassMetadata();
                //判断是否为接口
                if (metadata.isInterface()) {
                    AbstractBeanDefinition beanDefinition
                            = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class)
                            .addConstructorArgValue(metadata.getClassName())
                            .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)
                            .getBeanDefinition();

                    //给每个mapper生成对应的名字
                    AbstractBeanDefinition beanDefinition2
                            = BeanDefinitionBuilder.genericBeanDefinition(metadata.getClassName()).getBeanDefinition();
                    String beanName = generator.generateBeanName(beanDefinition2, beanFactory);
                    beanFactory.registerBeanDefinition(beanName,beanDefinition);
                }
            }
            
        }catch (Exception e){
            e.printStackTrace();
        }

    }
}

  1. Mapper 接口被 Spring 管理的本质:实际是被作为 MapperFactoryBean 注册到容器中

  2. Spring 的诡异做法,根据接口生成的 BeanDefinition 仅为根据接口名生成 bean 名

6、Aware接口

public class Day6Application {
    public static void main(String[] args) {

        GenericApplicationContext context = new GenericApplicationContext();
        /*
            有些功能用 @Autowired 就能实现啊, 为啥还要用 Aware 接口呢
            简单地说:
                a. @Autowired 的解析需要用到 bean 后处理器, 属于扩展功能
                b. 而 Aware 接口属于内置功能, 不加任何扩展, Spring 就能识别
            某些情况下, 扩展功能会失效, 而内置功能不会失效

            下面例子:你会发现用 Aware 注入 ApplicationContext 成功, 而 @Autowired 注入 ApplicationContext 失败
         */
        context.registerBean("mybean",MyBean.class);
        
        context.refresh();
        context.close();
    }
}
public class MyBean implements BeanNameAware, ApplicationContextAware, InitializingBean {
    @Override
    public void setBeanName(String s) {
        System.err.println("当前bean "+this+" 的名称:"+s);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.err.println("当前bean "+this+" 的容器:"+applicationContext);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.err.println("当前bean "+this+" 初始化。。。");
    }

    @Autowired
    public void doAuto(ApplicationContext applicationContext){
        System.err.println(">>>>当前bean "+this+" 的容器:"+applicationContext);
    }

    @PostConstruct
    public void init(){
        System.err.println(">>>>当前bean "+this+" 初始化。。。");
    }
}

  1. Aware 接口提供了一种【内置】 的注入手段,例如

    • BeanNameAware 注入 bean 的名字

    • BeanFactoryAware 注入 BeanFactory 容器

    • ApplicationContextAware 注入 ApplicationContext 容器

    • EmbeddedValueResolverAware 注入 ${} 解析器

  2. InitializingBean 接口提供了一种【内置】的初始化手段

  3. 对比

    • 内置的注入和初始化不受扩展功能的影响,总会被执行

    • 而扩展功能受某些情况影响可能会失效

    • 因此 Spring 框架内部的类常用内置注入和初始化

配置类 @Autowired 失效分析

@Configuration
public class MyConfig1 {


    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        System.err.println("注入 ApplicationContext");
    }

    @PostConstruct
    public void init() {
        System.err.println("初始化");
    }

    @Bean //  beanFactory 后处理器
    public BeanFactoryPostProcessor processor1() {

        return beanFactory -> {
            System.err.println("执行 processor1");
        };
    }

}

加后处理器之前:    加了之后:

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

 

 Java 配置类包含 BeanFactoryPostProcessor 的情况,因此要创建其中的 BeanFactoryPostProcessor 必须提前创建 Java 配置类,而此时的 BeanPostProcessor 还未准备好,导致 @Autowired 等注解失效

解决方法:

  • 用内置依赖注入和初始化取代扩展依赖注入和初始化

  • 用静态工厂方法代替实例工厂方法,避免工厂对象提前被创建

 7、初始化与销毁

//初始化和销毁的执行顺序
@SpringBootApplication
public class Day7Application {
    public static void main(String[] args) {

        ConfigurableApplicationContext context = SpringApplication.run(Day7Application.class, args);

        context.close();
    }

    @Bean(initMethod = "init3")
    public Bean1 bean1(){
        return new Bean1();
    }

    @Bean(destroyMethod = "destroy3")
    public Bean2 bean2() {
        return new Bean2();
    }
}
public class Bean1 implements InitializingBean {
    private static final Logger log = LoggerFactory.getLogger(Bean1.class);

    @PostConstruct
    public void init1() {
        System.err.println("初始化1");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.err.println("初始化2");
    }

    public void init3() {
        System.err.println("初始化3");
    }
}
public class Bean2 implements DisposableBean {
    private static final Logger log = LoggerFactory.getLogger(Bean2.class);

    @PreDestroy
    public void destroy1() {
        System.err.println("销毁1");
    }

    @Override
    public void destroy() throws Exception {
        System.err.println("销毁2");
    }

    public void destroy3() {
        System.err.println("销毁3");
    }
}

Spring 提供了多种初始化手段,除了 @PostConstruct,@Bean(initMethod) 之外,还可以实现 InitializingBean 接口来进行初始化,如果同一个 bean 用了以上手段声明了 3 个初始化方法,那么它们的执行顺序是

  1. @PostConstruct 标注的初始化方法

  2. InitializingBean 接口的初始化方法

  3. @Bean(initMethod) 指定的初始化方法

与初始化类似,Spring 也提供了多种销毁手段,执行顺序为

  1. @PreDestroy 标注的销毁方法

  2. DisposableBean 接口的销毁方法

  3. @Bean(destroyMethod) 指定的销毁方法

8、Scope

@RestController
public class MyController {

    @Lazy
    @Autowired
    private BeanForRequest beanForRequest;

    @Lazy
    @Autowired
    private BeanForSession beanForSession;

    @Lazy
    @Autowired
    private BeanForApplication beanForApplication;

    @GetMapping(value = "/test", produces = "text/html")
    public String test(HttpServletRequest request, HttpSession session) {
        ServletContext sc = request.getServletContext();
        String sb = "<ul>" +
                    "<li>" + "request :" + beanForRequest + "</li>" +
                    "<li>" + "session :" + beanForSession + "</li>" +
                    "<li>" + "application :" + beanForApplication + "</li>" +
                    "</ul>";
        return sb;
    }

}
@Scope("request")
@Component
public class BeanForRequest {
    
    @PreDestroy
    public void destroy() {
        System.err.println("request 销毁");
    }

}
@Scope("session")
@Component
public class BeanForSession {

    @PreDestroy
    public void destroy() {
        System.err.println("session 销毁");

    }
}
@Scope("application")
@Component
public class BeanForApplication {

    @PreDestroy
    public void destroy() {
        System.err.println("application 销毁");
    }
}

在当前版本的 Spring 和 Spring Boot 程序中,支持五种 Scope

  • singleton,容器启动时创建(未设置延迟),容器关闭时销毁

  • prototype,每次使用时创建,不会自动销毁,需要调用 DefaultListableBeanFactory.destroyBean(bean) 销毁

  • request,每次请求用到此 bean 时创建,请求结束时销毁

  • session,每个会话用到此 bean 时创建,会话结束时销毁

  • application,web 容器用到此 bean 时创建,容器停止时销毁

有些文章提到有 globalSession 这一 Scope,也是陈旧的说法,目前 Spring 中已废弃

singleton 注入其它 scope 失效

以单例注入多例为例

@ComponentScan("com.springboot.springbootmybatis.day9")
public class Day9Application {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Day9Application.class);

        E e = context.getBean(E.class);
        System.err.println(">>>"+e.getF1().getClass());
        System.err.println(">>>"+e.getF1());
        System.err.println(">>>"+e.getF1());

        System.err.println("\n>>>"+e.getF2().getClass());
        System.err.println(">>>"+e.getF2());
        System.err.println(">>>"+e.getF2());

        System.err.println("\n>>>"+e.getF3().getClass());
        System.err.println(">>>"+e.getF3());
        System.err.println(">>>"+e.getF3());

        System.err.println("\n>>>"+e.getF4().getClass());
        System.err.println(">>>"+e.getF4());
        System.err.println(">>>"+e.getF4());
    }
}
@Component
public class E {

    @Lazy
    @Autowired
    private F1 f1;

    @Autowired
    private F2 f2;

    @Autowired
    private ObjectFactory<F3> f3;

    @Autowired
    private ApplicationContext context;

    public F1 getF1() {
        return f1;
    }

    public F2 getF2() {
        return f2;
    }

    public F3 getF3() {
        return f3.getObject();
    }

    public F4 getF4() {
        return context.getBean(F4.class);
    }
}

 

 

原因:对于单例对象来讲,依赖注入仅发生了一次,后续再没有用到多例的 F,因此 E 用的始终是第一次依赖注入的 F

解决:

  • 仍然使用 @Lazy 生成代理

  • 代理对象虽然还是同一个,但当每次使用代理对象的任意方法时,由代理创建新的 f 对象

注意:

  • @Lazy 加在也可以加在成员变量上,但加在 set 方法上的目的是可以观察输出,加在成员变量上就不行了

  • @Autowired 加在 set 方法的目的类似

  1. 单例注入其它 scope 的四种解决方法

    • @Lazy

    • @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)

    • ObjectFactory

    • ApplicationContext

  2. 解决方法虽然不同,但理念上殊途同归: 都是推迟其它 scope bean 的获取


版权声明:本文为weixin_56697114原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。