Spring

目录

一、BeanFactory和ApplicationContext的区别

二、ApplicationContext的能力

三、beanFactory容器实现

四、ApplicationContext实现

1、较为经典的容器,基于classpath 下xml格式的配置文件来创建

2、基于磁盘路径下的xml格式的配置文件

3、较为经典的容器,基于Java配置类来创建

4、较为经典的容器,基于Java配置类来创建,用于web环境

 五、bean的生命周期 

六、Bean后处理器(为Bean生命周期各个阶段提供扩展)

AutowiredAnnotationBeanPostProcessor详解

 1、其中主要起作用的方法为beanPostProcessor.postProcessProperties(PropertyValues pvs, Object bean, String beanName)

 2、模拟源码原理

七、BeanFactory后置处理器

1、ConfigurationClassPostProcessor后置处理器,用于解析@ComponentScan @Bean @Import @ImportResource注解


一、BeanFactory和ApplicationContext的区别

applicationContext继承于beanFactory,对beanFactory功能进行了扩展

二、ApplicationContext的能力

1、messageSource: 处理国际化资源的能力,支持多种语言

2、resourcePatternResolver: 通配符匹配资源(磁盘路径/类路径找到的文件)的能力 

3、applicationEventPublisher: 发布事件对象

4、environmentCapable: 读取系统环境变量(*.properties, *.yml)

三、beanFactory容器实现

1、beanFactory后置处理器主要功能:补充了一些bean定义,例如@Configration、@Bean

2、bean后置处理器,针对bean的生命周期的各个阶段提供扩展,例如@Autowired @Resource

小结:

 1、beanFactory不会做的事

1、不会主动调用BeanFactory后处理器

2、不会主动添加Bean后处理器

3、不会主动初始化单例(用到的时候才会加载)

4、不会解析beanFactory 还不会解析${}和#{}

2、bean 后处理器会有排序的逻辑

1、@Autowire注解是按照类型注入,如一个接口存在两个相同的实现类(且属性名与任何一个实现类不同),此时按照类型注入会报错

  • 根据属性名去匹配,当前要注入的属性名和哪个实现类同名,则注入哪个实现类

2、@Resorce是按照名字去找,若没有同名的则按照类型去找

  • 可以在注解中添加属性name,按照哪个值去找

3、如果@Autowire和@Resorce同时存在,则@Autowire会先生效,因为@Autowire的后置处理器先被执行,如果重新调整两个注解的处理器,则生效顺序不同

(以上功能,applicationContext都会帮助我们做好)

四、ApplicationContext实现

1、较为经典的容器,基于classpath 下xml格式的配置文件来创建

 能从xml中读取bean,主要是XmlBeanDefinitionReader发挥作用,原理如下:

  

2、基于磁盘路径下的xml格式的配置文件

 原理同1

3、较为经典的容器,基于Java配置类来创建

4、较为经典的容器,基于Java配置类来创建,用于web环境

 五、bean的生命周期 

package A13;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * @author shanshan.wang
 * @since 2023/2/1 19:24
 */
@Component
@Data
public class LifeCycleBean {

    private static final Logger log = LoggerFactory.getLogger(LifeCycleBean.class);
    /**
     * 方法执行顺序
     * 1、构造方法
     * 2、依赖注入
     * 3、初始化
     * 4、销毁(bean是单例时调用,其他类型的调用时间不同 )
     */
    @Autowired
    public void autowire(@Value("${JAVA_HOME}") String home) {
        // 当参数是实体对象时,会根据类型进行注入
        // 当参数是String类型时,不会主动进行注入,需要加@Value注解
        log.info("依赖注入:{}", home);
    }

    @PostConstruct
    public void init() {
        log.info("初始化");
    }

    @PreDestroy
    public void destroy() {
        log.info("销毁");
    }
}
package A13;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * @author shanshan.wang
 * @since 2023/2/2 10:27
 */
@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.info("销毁之前执行,如@PreDestory");
        }
    }

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

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

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

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

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

}

执行结果: 

六、Bean后处理器(为Bean生命周期各个阶段提供扩展)

各个处理器执行时机

  1. AutowiredAnnotationBeanPostProcessor:解析@Autowired 依赖注入阶段执行
  2. CommonAnnotationBeanPostProcessor:
    1. @Resource:依赖注入阶段
    2. @PostConstruct:初始化前(虽然名字叫实例化后)
    3. @PreDestroy:销毁前
  3. ConfiguraPropertiesBindingPostProcessor:解析@ConfigurationProperties 初始化前
package A15;

import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.context.support.GenericApplicationContext;

/**
 * @author shanshan.wang
 * @since 2023/2/3 10:31
 */
public class Application {
    public static void main(String[] args) {
        // GenericApplicationContext 是一个干净的容器(其中无任何bean工厂处理器,bean处理器,像AnnotationConfigApplicationContext这个容器中就已经提前放好了beanFactory后置处理器)
        GenericApplicationContext context = new GenericApplicationContext();

        // 使用原始方法注册三个bean
        context.registerBean("bean1", Bean1.class);
        context.registerBean("bean2", Bean2.class);
        context.registerBean("bean3", Bean3.class);

        // new ContextAnnotationAutowireCandidateResolver() 能够解析@Value注解
        context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        // 解析@Autowired注解
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
        // 解析@Resource @PostConstruct @PreDestroy(容器关闭时,改注解才被解析执行单例销毁)
        context.registerBean(CommonAnnotationBeanPostProcessor.class);
        // 解析@ConfigurationProperties
        ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
        // 初始化器
        // 执行BeanFactory后处理器,添加bean后置处理器,初始化所有单例
        context.refresh();

        // 销毁容器
        context.close();
    }
}
package A15;

import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

/**
 * @author shanshan.wang
 * @since 2023/2/3 10:33
 */
@Data
public class Bean1 {
    private static final Logger log = LoggerFactory.getLogger(Bean1.class);

    private Bean2 bean2;
    private Bean3 bean3;
    private String home;

    /**
     * 一般注解都会放在属性上
     * 这里之所以都放在方法上是因为这样可以清楚的将信息打印出来
     * 方便了解,bean是否注入成功
     */

    @Autowired
    public void setBean2(Bean2 bean2) {
        log.info("@Autowired 生效:{}", bean2);
        this.bean2 = bean2;
    }

    @Resource
    public void setBean3(Bean3 bean3) {
        log.info("@Resource 生效:{}", bean3);
        this.bean3 = bean3;
    }

    @Autowired
    public void autowire(@Value("${java.home:666}") String home) {
        // 当参数是实体对象时,会根据类型进行注入
        // 当参数是String类型时,不会主动进行注入,需要加@Value注解
        log.info("@Value 生效:{}", home);
    }

    @PostConstruct
    public void init() {
        log.info("@PostConstruct 生效");
    }

    @PreDestroy
    public void destroy() {
        log.info("@PreDestroy 生效");
    }
}
package A15;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * @author shanshan.wang
 * @since 2023/2/3 10:34
 */
@Data
@ConfigurationProperties(prefix = "java", ignoreInvalidFields = true)
public class Bean2 {
    private String name;
    private String home;
}

AutowiredAnnotationBeanPostProcessor详解

package A17;


import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;

/**
 * @author shanshan.wang
 * @since 2023/2/3 15:53
 */
public class Application {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // 将对象放到spring容器中
        // registerSingleton只需要提供bean名称及bean实例,缺点是这个bean是直接new出来放到容器中
        // spring认为这是一个完整的bean,不会再去走创建流程、依赖注入、初始化等
        beanFactory.registerSingleton("bean2", new Bean2());
        beanFactory.registerSingleton("bean3", new Bean3());

        // 解析@Value注解
        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        // 获取后置处理器对象
        // 正常情况下,后置处理器会在依赖注入阶段被调用,执行bean的属性赋值
        AutowiredAnnotationBeanPostProcessor beanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
        beanPostProcessor.setBeanFactory(beanFactory);

        Bean1 bean1 = new Bean1();
        System.out.println(bean1); //Bean1(bean2=null, bean3=null, home=null)
        // 执行后置处理器,为属性赋值
        beanPostProcessor.postProcessProperties(null, bean1, "bean1");
        System.out.println(bean1); //Bean1(bean2=Bean2(name=null, home=null), bean3=null, home=null)
    }
}

 1、其中主要起作用的方法为beanPostProcessor.postProcessProperties(PropertyValues pvs, Object bean, String beanName)

  • 第一个参数为自己指定实体对象中每个属性注入什么值,而不用spring自动装配模式
  • 第二个参数为被注入的目标
  • 第三个参数为bean名称

该方法主要有两个功能:

  • findAutowiringMetadata 获取加了@Autowired的属性及方法、
  • metadata.inject用反射给属性赋值,反射调用set方法

 2、模拟源码原理

package A17;


import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.core.MethodParameter;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @author shanshan.wang
 * @since 2023/2/3 15:53
 */
public class Application {
    public static void main(String[] args) throws Throwable {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // 将对象放到spring容器中
        // registerSingleton只需要提供bean名称及bean实例,缺点是这个bean是直接new出来放到容器中
        // spring认为这是一个完整的bean,不会再去走创建流程、依赖注入、初始化等
        beanFactory.registerSingleton("bean2", new Bean2());
        beanFactory.registerSingleton("bean3", new Bean3());

        // 解析@Value注解
        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        // 获取后置处理器对象
        // 正常情况下,后置处理器会在依赖注入阶段被调用,执行bean的属性赋值
        AutowiredAnnotationBeanPostProcessor beanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
        beanPostProcessor.setBeanFactory(beanFactory);

        Bean1 bean1 = new Bean1();
        System.out.println(bean1); //Bean1(bean2=null, bean3=null, home=null)
//        // 执行后置处理器,为属性赋值
//        beanPostProcessor.postProcessProperties(null, bean1, "bean1");
//        System.out.println(bean1); //Bean1(bean2=Bean2(name=null, home=null), bean3=null, home=null)

        // 模拟postProcessProperties方法开始》》》》》》》》》》》
        // 1、反射调用方法获取加了注解的属性&&方法
        Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
        findAutowiringMetadata.setAccessible(true);
        InjectionMetadata  metadata = (InjectionMetadata)findAutowiringMetadata.invoke(beanPostProcessor, "bean1", Bean1.class, null);
        // 获取到了加了@Autowired注解的setBean2和autowire方法 及 加了@Autowired注解的bean3属性
        System.out.println(metadata);
        
        // 2、调用metadata.inject方法进行依赖注入,注入时按类型查找值
        metadata.inject(bean1, "bean1", null);
        System.out.println(bean1);
        // 《《《《《《《《《模拟postProcessProperties方法结束
        
        // 对metadata.inject方法解析开始》》》》》》》》
        // 1、属性注入
        Field bean3 = Bean1.class.getDeclaredField("bean3");
        // 1.1设置为false,如果容器中没有找到对应的对象不会报错
        DependencyDescriptor descriptor = new DependencyDescriptor(bean3, false);
        // 1.2根据成员变量类型去找要注入谁
        Object o = beanFactory.doResolveDependency(descriptor, "bean3", null, null);
        // 1.3 将找到的对象通过反射赋值给对应的属性
        
        // 2、方法注入
        Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
        // 对于方法而言,一个方法对应多个DependencyDescriptor对象,因为一个方法可能注入多个参数
        DependencyDescriptor descriptor1 = new DependencyDescriptor(new MethodParameter(setBean2, 0), false);
        beanFactory.doResolveDependency(descriptor1, null, null, null);
        // 《《《《《《《《对metadata.inject方法解析结束
        
    }
}

七、BeanFactory后置处理器

1、ConfigurationClassPostProcessor后置处理器,用于解析@ComponentScan @Bean @Import @ImportResource注解

package A19;

import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;

/**
 * @author shanshan.wang
 * @since 2023/2/7 20:42
 */
public class Application {
    public static void main(String[] args) {
        // GenericApplicationContext 是一个干净的容器(其中无任何bean工厂处理器,bean处理器,像AnnotationConfigApplicationContext这个容器中就已经提前放好了beanFactory后置处理器)
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);

        // 解析@ComponentScan @Bean @Import @ImportResource注解
        context.registerBean(ConfigurationClassPostProcessor.class);
        // 解析@Mapper注解,需要指定要扫描的包
        context.registerBean(MapperScannerConfigurer.class, beanDefinition -> beanDefinition.getPropertyValues().add("basePackage", "A19.mapper"));
        

        // 初始化器
        // 执行BeanFactory后处理器,添加bean后置处理器,初始化所有单例
        context.refresh();

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

        // 销毁容器
        context.close();
    }
}
package A19;

import A19.bean.Bean1;
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

/**
 * @author shanshan.wang
 * @since 2023/2/7 20:27
 */
@Configuration
@ComponentScan
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://mysql.jidudev.com:3306/jidu_business_order?zeroDateTimeBehavior=convertToNull&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useLegacyDatetimeCode=false&useSSL=false&allowMultiQueries=true");
        dataSource.setUsername("bus_order_wr");
        dataSource.setPassword("qE4dA0oR7b");
        return dataSource;
    }

}
package A19.bean;

/**
 * @author shanshan.wang
 * @since 2023/2/7 21:10
 */
public class Bean1 {
}

===============================

package A19.bean;

import A17.Bean1;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;

/**
 * @author shanshan.wang
 * @since 2023/2/7 20:31
 */
@Controller
public class Bean2 {
    private static final Logger log = LoggerFactory.getLogger(Bean1.class);

    public Bean2() {
        log.info("我是Bean2, 我被spring管理了....");
    }
}

============================================
package A19.bean;

import A17.Bean1;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * @author shanshan.wang
 * @since 2023/2/7 20:31
 */
@Component
public class Bean3 {
    private static final Logger log = LoggerFactory.getLogger(Bean1.class);

    public Bean3() {
        log.info("我是Bean3, 我被spring管理啦...");
    }
}

===================================
package A19.bean;

import A17.Bean1;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author shanshan.wang
 * @since 2023/2/7 20:31
 */
public class Bean4 {
    private static final Logger log = LoggerFactory.getLogger(Bean1.class);

    public Bean4() {
        log.info("我是Bean4, 我被spring管理啦...");
    }
}

 模拟源码,解析@ComponentScan注解

  • 判断类上是否有@Component注解
  • 将注解的属性值替换为类路径
  • 根据类路径从容器中获取到对应的资源
  • 根据资源从容器中拿到类元信息
  • 判断类上是否加了@Component注解 或者 间接加了@Component注解
  • 为每个类生成beanDefinition对象
  • 将bean放到容器中
package A19;

import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * @author shanshan.wang
 * @since 2023/2/7 20:42
 */
public class Application {
    public static void main(String[] args) throws IOException {
        // GenericApplicationContext 是一个干净的容器(其中无任何bean工厂处理器,bean处理器,像AnnotationConfigApplicationContext这个容器中就已经提前放好了beanFactory后置处理器)
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);

//        // 解析@ComponentScan @Bean @Import @ImportResource注解
//        context.registerBean(ConfigurationClassPostProcessor.class);
//        // 解析@Mapper注解,需要指定要扫描的包
//        context.registerBean(MapperScannerConfigurer.class, beanDefinition -> beanDefinition.getPropertyValues().add("basePackage", "A19.mapper"));

        // 模拟解析@ComponentScan注解开始》》》》》》》》》
        // 查看类上是否有@ComponentScan注解
        ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);

        if (componentScan != null) {
            // 说明类上有@ComponentScan注解
            // 获取到注解上的basePackages内容
            String[] packages = componentScan.basePackages();
            for (String pac :packages){
                // 将获取到的属性值替换为类路径
                String path = "classpath*:" + pac.replace(".", "/") + "/**/*.class";
                // 从容器中根据类路径获取到类信息
                Resource[] resources = context.getResources(path);
                // 元信息读取工厂
                CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                // 用于获取bean名称(For example: com.xyz.FooServiceImpl -> fooServiceImpl)
                AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
                for (Resource resource : resources) {
                    // 获取到对应资源的元信息
                    MetadataReader metadataReader = factory.getMetadataReader(resource);
                    // 获取到资源上所加注解的相关数据
                    AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();

                    // 判断是否有@Component注解 或者 间接加了@Component注解
                    if (annotationMetadata.hasAnnotation(Component.class.getName()) || annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
                        // 获取beanDefinition对象
                        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(metadataReader.getClassMetadata().getClassName()).getBeanDefinition();
                        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
                        // 获取bean名称
                        String beanName = generator.generateBeanName(beanDefinition, beanFactory);
                        // 将bean放到容器中
                        beanFactory.registerBeanDefinition(beanName, beanDefinition);
                    }
                }

            }
        }
        
        // 模拟解析@ComponentScan注解结束《《《《《《《《《《《《《《《《

        // 初始化器
        // 执行BeanFactory后处理器,添加bean后置处理器,初始化所有单例
        context.refresh();

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

        // 销毁容器
        context.close();
    }
}

将模拟代码抽取出后置处理器

这部分的调整是因为之前直接从上下文中根据路径查找对应的资源,现阶段是bean工厂后置处理器,当前并不知道上下文是什么,所以换一种方式获取

package A19;

import lombok.SneakyThrows;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;

/**
 * @author shanshan.wang
 * @since 2023/2/9 10:35
 */
public class ComponentScanProcessor implements BeanFactoryPostProcessor {

    @SneakyThrows
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);

        if (componentScan != null) {
            // 说明类上有@ComponentScan注解
            // 获取到注解上的basePackages内容
            String[] packages = componentScan.basePackages();
            for (String pac :packages){
                // 将获取到的属性值替换为类路径
                String path = "classpath*:" + pac.replace(".", "/") + "/**/*.class";
                // 从容器中根据类路径获取到类信息
                Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
                CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                // 用于获取bean名称(For example: com.xyz.FooServiceImpl -> fooServiceImpl)
                AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
                for (Resource resource : resources) {
                    // 获取到类元信息
                    MetadataReader metadataReader = factory.getMetadataReader(resource);
                    // 获取到类上所加注解的相关数据
                    AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();

                    // 判断是否有@Component注解 或者 间接加了@Component注解
                    if (annotationMetadata.hasAnnotation(Component.class.getName()) || annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
                        // 获取beanDefinition对象
                        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(metadataReader.getClassMetadata().getClassName()).getBeanDefinition();

                        if (configurableListableBeanFactory instanceof  DefaultListableBeanFactory) {
                            DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
                            // 获取bean名称
                            String beanName = generator.generateBeanName(beanDefinition, beanFactory);
                            // 将bean放到容器中
                            beanFactory.registerBeanDefinition(beanName, beanDefinition);
                        }
                    }
                }

            }
        }
    }
}

package A19;

import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * @author shanshan.wang
 * @since 2023/2/7 20:42
 */
public class Application {
    public static void main(String[] args) throws IOException {
        // GenericApplicationContext 是一个干净的容器(其中无任何bean工厂处理器,bean处理器,像AnnotationConfigApplicationContext这个容器中就已经提前放好了beanFactory后置处理器)
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);

//        // 解析@ComponentScan @Bean @Import @ImportResource注解
//        context.registerBean(ConfigurationClassPostProcessor.class);
//        // 解析@Mapper注解,需要指定要扫描的包
//        context.registerBean(MapperScannerConfigurer.class, beanDefinition -> beanDefinition.getPropertyValues().add("basePackage", "A19.mapper"));
        context.registerBean(ComponentScanProcessor.class);

        // 初始化器
        // 执行BeanFactory后处理器,添加bean后置处理器,初始化所有单例
        context.refresh();

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

        // 销毁容器
        context.close();
    }
}

2、MapperPostProcessor源码实现

1、spring底层加载mapper文件的方式

实际上加载到spring容器中的bean实际上

package A24;

import A19.bean.Bean1;
import A19.mapper.Mapper2;
import A24.mapper.Mapper1;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

/**
 * @author shanshan.wang
 * @since 2023/2/7 20:27
 */
@Configuration
@ComponentScan("A19.bean")
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://mysql.jidudev.com:3306/jidu_business_order?zeroDateTimeBehavior=convertToNull&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useLegacyDatetimeCode=false&useSSL=false&allowMultiQueries=true");
        dataSource.setUsername("bus_order_wr");
        dataSource.setPassword("qE4dA0oR7b");
        return dataSource;
    }

    public MapperFactoryBean<Mapper1> mapper1(SqlSessionFactory sqlSessionFactory) {
        // spring 容器中实际上注入的是MapperFactoryBean类型的实体,而非具体的Mapper
        MapperFactoryBean<Mapper1> factory = new MapperFactoryBean<>(Mapper1.class);
        factory.setSqlSessionFactory(sqlSessionFactory);

        return factory;
    }

    public MapperFactoryBean<Mapper2> mapper2(SqlSessionFactory sqlSessionFactory) {
        MapperFactoryBean<Mapper2> factory = new MapperFactoryBean<>(Mapper2.class);
        factory.setSqlSessionFactory(sqlSessionFactory);

        return factory;
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值