Spring 高级 工厂后处理器模拟实现组件扫描-模拟ComponentScan 进阶
一、自定义Bean 后处理器 Processor
package com.mangoubiubiu.show.a05.component; import com.mangoubiubiu.show.a05.Config; 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.context.support.GenericApplicationContext; 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; import java.io.IOException; public class ComponentScanPostProcessor implements BeanFactoryPostProcessor { /** * context.refresh 初始化ApplicationContext的时候会回调这个方法 * @param configurableListableBeanFactory * @throws BeansException */ @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { try { //Spring工具类 读取类的源信息 CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory(); //查找某个类上有没有加注解 第一个参数 某个类的类型 第二个参数 要找的注解 ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class); if(componentScan!=null){ for (String p:componentScan.basePackages()) { System.out.println("包名:"+p); AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator(); //com.mangoubiubiu.show.a05.component StringBuilder path = new StringBuilder(); path.append("classpath*:").append(p.replace(".","/")).append("/**/*.class"); System.out.println("拼接后的包名:"+path.toString()); //读取路径下的文件 Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path.toString()); for (Resource res:resources) { System.out.println("读取到的文件信息为:"+res); MetadataReader reader = factory.getMetadataReader(res); System.out.println("得到类信息:"+ reader.getClassMetadata().getClassName()); AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata(); System.out.println("是否加了Component注解"+ annotationMetadata.hasAnnotation(Component.class.getName())); System.out.println("是否加了Component注解 派生"+ annotationMetadata.hasMetaAnnotation(Component.class.getName())); if(annotationMetadata.hasAnnotation(Component.class.getName()) || annotationMetadata.hasMetaAnnotation(Component.class.getName())){ AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName()).getBeanDefinition(); if (configurableListableBeanFactory instanceof DefaultListableBeanFactory ) { DefaultListableBeanFactory beanFactory = ((DefaultListableBeanFactory) configurableListableBeanFactory); String beanName = generator.generateBeanName(beanDefinition, beanFactory); beanFactory.registerBeanDefinition(beanName,beanDefinition); } } } } } } catch (IOException e) { e.printStackTrace(); } } }
二、将ComponentScanPostProcessor 注入到容器里面
package com.mangoubiubiu.show.a05; import com.mangoubiubiu.show.a05.component.ComponentScanPostProcessor; import lombok.extern.slf4j.Slf4j; 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.BeanNameGenerator; 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.awt.*; import java.io.IOException; @Slf4j public class A05Application { private MetadataReader reader; public static void main(String[] args) throws IOException { GenericApplicationContext context = new GenericApplicationContext(); //将config注册到容器里面 context.registerBean("config",Config.class); context.registerBean(ComponentScanPostProcessor.class); // context.registerBean(MapperScannerConfigurer.class,beanDefinition -> { // beanDefinition.getPropertyValues().add("basePackage","com.mangoubiubiu.show.a05.mapper"); // }); //初始化容器 context.refresh(); for (String name: context.getBeanDefinitionNames()) { System.out.println(name); } context.close(); } }
可以看到在Config类上面配了包扫描,指定包下标注了@Component或者@Controller的bean 被我们成功扫描进IOC容器里面。