Spring原理学习(三):BeanFactory后处理器原理解析与模拟实现

一、简单认识BeanFactory后处理器

1.1 BeanFactory后处理器的作用 

        接前文:Spring原理学习(一):BeanFactory和ApplicationContext的原理和实现 我们已经简单介绍了 BeanFactory后处理器 的作用,今天我们先再来再次体验一下。

        先准备一个主启动类: 

public class A05 {
    private static final Logger log = LoggerFactory.getLogger(A05.class);

    public static void main(String[] args) throws IOException {

        // GenericApplicationContext 是一个【干净】的容器,没有spring添加的各种后处理器
        GenericApplicationContext context = new GenericApplicationContext();

        //注册config
        context.registerBean("config", Config.class);

        // 初始化容器
        context.refresh();

        // 看看容器里被注册的bean有哪些
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

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

         然后准备一个bean,上面加了@Configuration和 @Bean 注解;并且加上了@ComponentScan 注解,应该能扫描到加有@Component注解的Bean2。

@Configuration
@ComponentScan("com.itheima.a05.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/test");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }
}
@Component
public class Bean2 {

    private static final Logger log = LoggerFactory.getLogger(Bean2.class);

    public Bean2() {
        log.debug("我被 Spring 管理啦");
    }
}

         所以config容器里应该有5个bean:config本身、扫描到的bean2、自己管理的三个(bean2、sqlSessionFactory、druidDataSource)。

        但是运行之后我们发现:

        只有我们自己添加的一个bean。 这说明执勤啊提到的注解都没有被解析。而解析这些注解的功能就是beanFactory后处理器提供的。

1.2  ConfigurationClassPostProcessor 后处理器

         我们加上ConfigurationClassPostProcessor 后处理器就可以解析这些注解了。

public class A05 {
    private static final Logger log = LoggerFactory.getLogger(A05.class);

    public static void main(String[] args) throws IOException {

        // GenericApplicationContext 是一个【干净】的容器
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
    
        //解析@ComponentScan @Bean @Import @ImportResource
        context.registerBean(ConfigurationClassPostProcessor.class);

        // 初始化容器
        context.refresh();

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

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

        运行结果:

1.3 MapperScannerConfigurer 后处理器 

        再加上ConfigurationClassPostProcessor 后处理器就可以解析这些注解了 

public class A05 {
    private static final Logger log = LoggerFactory.getLogger(A05.class);

    public static void main(String[] args) throws IOException {

        // GenericApplicationContext 是一个【干净】的容器
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
    
        //解析@ComponentScan @Bean @Import @ImportResource
        context.registerBean(ConfigurationClassPostProcessor.class);
        //解析@MapperScanner
        context.registerBean(MapperScannerConfigurer.class, bd -> { 
            bd.getPropertyValues().add("basePackage", "com.itheima.a05.mapper");
        }); 

        // 初始化容器
        context.refresh();

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

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

        Mapper1 和 Mapper2加上了@Mapper注解,Mapper3没有 

@Mapper
public interface Mapper1 {
}
@Mapper
public interface Mapper2 {
}
public class Mapper3 {
}

         运行结果:

二、模拟实现后处理器——解析@ComponentScan

        首先要明确执行的步骤:

  1. 先找到加有@Component注解的是哪些包,并拿到包下的资源
  2. 找到包下有哪些bean加上了@Component注解或派生注解
  3. 生成这些资源对应的beanDefinition和beanName
  4. 注册进beanFactory
public class ComponentScanPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override // context.refresh
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        try {
            //查找哪个类上有该注解
            ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
            if (componentScan != null) {
                for (String p : componentScan.basePackages()) {
                    //打印出来之后是com.itheima.a05.component这种格式的
                    System.out.println(p);
                    //我们要做格式转换 com.itheima.a05.component -> classpath*:com/itheima/a05/component/**/*.class
                    String path = "classpath*:" + p.replace(".", "/") + "/**/*.class";
                    //打印出来之后是classpath*:com/itheima/a05/component/**/*.class
                    System.out.println(path);
                    //CachingMetadataReaderFactory用于读取类的源信息
                    CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                    //getResources用于获取类路径下的所有资源
                    Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
                    AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
                    for (Resource resource : resources) {
                        // 读取类的源信息
                        MetadataReader reader = factory.getMetadataReader(resource);
                        // 读取类上的注解信息
                        AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
                        //是否加了 @Component 注解
                        boolean hasAnnotation = annotationMetadata.hasAnnotation(Component.class.getName());
                        //是否加了 @Component 派生注解,比如@Controller
                        boolean hasMetaAnnotation = annotationMetadata.hasMetaAnnotation(Component.class.getName());
                        if (hasAnnotation || hasMetaAnnotation) {
                            AbstractBeanDefinition bd = BeanDefinitionBuilder
                                    .genericBeanDefinition(reader.getClassMetadata().getClassName())
                                    .getBeanDefinition();
                            //生成bean的名称
                            String name = generator.generateBeanName(bd, beanFactory);
                            //注册到bean工厂
                            beanFactory.registerBeanDefinition(name, bd);
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

         运行结果:

image-20220329192201153 

三、模拟实现后处理器——解析@Bean 

public class AtBeanPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        try {
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            //这里为了省事,写死了路径,后续优化可以考虑先找找有@Component注解的包有哪些,然后逐一读取
            MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/itheima/a05/Config.class"));
            Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
            for (MethodMetadata method : methods) {
                System.out.println(method);
                String initMethod = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
                builder.setFactoryMethodOnBean(method.getMethodName(), "config");
                //指定自动装配模式
                builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
                if (initMethod.length() > 0) {
                    builder.setInitMethodName(initMethod);
                }
                AbstractBeanDefinition bd = builder.getBeanDefinition();
                beanFactory.registerBeanDefinition(method.getMethodName(), bd);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 四、模拟实现后处理器——MapperScannerConfigurer  

        需要注意的是,我们要注册进spring中的是MapperFactoryBean,而不是Mapper。 

public class MapperPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        try {
            //扫描包下的资源
            PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resolver.getResources("classpath:com/itheima/a05/mapper/**/*.class");
            AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            for (Resource resource : resources) {
                MetadataReader reader = factory.getMetadataReader(resource);
                ClassMetadata classMetadata = reader.getClassMetadata();
                //判断是不是接口
                if (classMetadata.isInterface()) {
                    //这里要注意,交给spring管理的类型是MapperFactoryBean,而不是Mapper
                    AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class)
                            .addConstructorArgValue(classMetadata.getClassName())
                            .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)
                            .getBeanDefinition();
                    //bd2仅仅是为了生成名字,spring内部也是这么做的
                    AbstractBeanDefinition bd2 = BeanDefinitionBuilder.genericBeanDefinition(classMetadata.getClassName()).getBeanDefinition();
                    String name = generator.generateBeanName(bd2, beanFactory);
                    beanFactory.registerBeanDefinition(name, bd);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

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

    }
}

猜你喜欢

转载自blog.csdn.net/m0_49499183/article/details/129966889
今日推荐