Bootstrap

14.Bean工厂后置处理器-解析@ComponentScan

package com.xkj.org.a05;

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;

@Configuration
@ComponentScan("com.xkj.org.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
    public DruidDataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        return dataSource;
    }

}
package com.xkj.org.a05.component;

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

@Component
public class Bean2 {

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

    public Bean2() {
        log.debug("我被Spring管理啦");
    }
}
package com.xkj.org.a05.component;

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

@Component
public class Bean3 {

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

    public Bean3() {
        log.debug("我被Spring管理啦");
    }
}
package com.xkj.org.a05;

import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
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.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;

import java.io.IOException;

public class A05Application {

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

    public static void main(String[] args) throws IOException {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
//        //bean工厂后置处理器
//        context.registerBean(ConfigurationClassPostProcessor.class);
//        //bean工厂后置处理器,第二个参数指定扫描的包(很少使用)
//        context.registerBean(MapperScannerConfigurer.class, bd -> {
//            bd.getPropertyValues().add("basePackage", "com.xkj.org.a05.mapper");
//        });

        // 去寻找@ComponentScan注解
        ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
        if(componentScan != null) {
            // 找到需要扫描的包有哪些
            for (String basePackage : componentScan.basePackages()) {
                System.out.println("basePackage="+basePackage);
                // com.xkj.org.a05.component -> classpath*:com/xkj/org/a05/component/**/*.class
                // 将class文件的包路径 转化成 文件路径
                String path = "classpath*:" + basePackage.replace(".", "/") + "/**/*.class";
                // path=classpath*:com/xkj/org/a05/component/**/*.class
                System.out.println("path="+path);
                // 读取类的元信息的工厂
                CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                Resource[] resources = context.getResources(path);
                AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
                for (Resource resource: resources) {
                    // resource=file [D:\projects\reggie_take_out\target\classes\com\xkj\org\a05\component\Bean2.class]
                    System.out.println("resource=" + resource);
                    MetadataReader reader = factory.getMetadataReader(resource);
                    // 得到类信息
                    ClassMetadata classMetadata = reader.getClassMetadata();
                    System.out.println("类名:"+classMetadata.getClassName());
                    // 得到注解信息
                    AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
                    // 判断是否有@Component注解
                    System.out.println("是否存在@Component注解:"+
                            annotationMetadata.hasAnnotation(Component.class.getName()));
                    System.out.println("是否存在@Component注解,甚至是派生的,就是间接加了@Component注解的(@Controller)==="+
                            annotationMetadata.hasMetaAnnotation(Component.class.getName()));
                    if(annotationMetadata.hasAnnotation(Component.class.getName())
                            || annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
                        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(classMetadata.getClassName())
                                .getBeanDefinition();
                        String beanName = generator.generateBeanName(beanDefinition, context.getDefaultListableBeanFactory());
                        context.getDefaultListableBeanFactory().registerBeanDefinition(beanName, beanDefinition);
                    }
                }
            }
        }

        context.refresh();

        for (String name: context.getBeanDefinitionNames()) {
            System.out.println("beanDefinitionName ="+name);

         }

        context.close();
    }
}

方法抽取:

package com.xkj.org.a05;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.context.support.GenericApplicationContext;


public class A05Application {

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

    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
        //注册bean工厂的后置处理器
        context.registerBean(ComponentScanPostProcessor.class);
        context.refresh();

        for (String name: context.getBeanDefinitionNames()) {
            System.out.println("beanDefinitionName ="+name);
        }

        context.close();
    }
}
package com.xkj.org.a05;

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.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;


public class ComponentScanPostProcessor implements BeanFactoryPostProcessor {

    /**
     * 此方法会在context.refresh时候调用
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        try {
            // 去寻找@ComponentScan注解
            ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
            if(componentScan != null) {
                // 找到需要扫描的包有哪些
                for (String basePackage : componentScan.basePackages()) {
                    System.out.println("basePackage="+basePackage);
                    // com.xkj.org.a05.component -> classpath*:com/xkj/org/a05/component/**/*.class
                    // 将class文件的包路径 转化成 文件路径
                    String path = "classpath*:" + basePackage.replace(".", "/") + "/**/*.class";
                    // path=classpath*:com/xkj/org/a05/component/**/*.class
                    System.out.println("path="+path);
                    // 读取类的元信息的工厂
                    CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                    // 这里不再不使用context对象,换一种实现方式
                    Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
                    AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
                    for (Resource resource: resources) {
                        // resource=file [D:\projects\reggie_take_out\target\classes\com\xkj\org\a05\component\Bean2.class]
                        System.out.println("resource=" + resource);
                        MetadataReader reader = factory.getMetadataReader(resource);
                        // 得到类信息
                        ClassMetadata classMetadata = reader.getClassMetadata();
                        System.out.println("类名:"+classMetadata.getClassName());
                        // 得到注解信息
                        AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
                        // 判断是否有@Component注解
                        System.out.println("是否存在@Component注解:"+
                                annotationMetadata.hasAnnotation(Component.class.getName()));
                        System.out.println("是否存在@Component注解,甚至是派生的,就是间接加了@Component注解的(@Controller)==="+
                                annotationMetadata.hasMetaAnnotation(Component.class.getName()));
                        if(annotationMetadata.hasAnnotation(Component.class.getName())
                                || annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
                            AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(classMetadata.getClassName())
                                    .getBeanDefinition();
                            if(configurableListableBeanFactory instanceof DefaultListableBeanFactory) {
                                DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)configurableListableBeanFactory;
                                String beanName = generator.generateBeanName(beanDefinition, beanFactory);
                                beanFactory.registerBeanDefinition(beanName, beanDefinition);
                            }
                        }
                    }
                }
            }
        }catch (Exception e) {
            e.printStackTrace();
        }

    }
}

;