BeanFactory后处理器
- BeanFactory后处理器的作用:为 BeanFactory 提供扩展;@ComponentScan, @Bean, @Mapper 等注解的解析属于核心容器(即 BeanFactory)的扩展功能,这些扩展功能由不同的BeanFactory后处理器来完成, 其实主要就是补充了一些 bean 定义
- 常见的 BeanFactory 后处理器
- 实现自己的BeanFactory后处理器
一 常见BeanFactory后处理器
ConfigurationClassPostProcessor
:扫描@Config @Bean @ComponentScan @Component @Controller 等注解MapperScannerConfigurer
: 扫描@MapperSanner @Mapper 等注解
使用方式
public static void main(String[] args) {
// GenericApplicationContext 是一个【干净】的容器
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.shunyum.a05.mapper");
});
context.refresh();
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
context.close();
}
二 实现自己的BeanFactory后处理器
自定义一个类,实现BeanDefinitionRegisterPostProcess接口,重写postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法;该方法本质上就是通过识别类和类中的方法上的注解,对定义的Bean进行处理。
重点为下面几个类:
- PathMatchingResourcePatternResolver:表达式匹配资源,通过resolver.getResource(str)来获取某个目录下的资源Resources;
- CachingMetadataReaderFactory:元数据处理工厂,通过facotry.getMetaDataReader(resouce)来获取一个MetaDataReadaer对象,该对象包含类的类名、包含的方法、注解等信息;
- MetadataReader:通过该对象来进行一系列的操作,例如metaDataReader.getAnnotationMetaData()来获取该类上添加的注解
注:BeanDefinitionRegisterPostProcess继承自BeanFacotryPostProcessor
2.1 自定义Bean工厂后处理器来处理@Component注解
public class MyComponentScan implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
try {
ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
if (Objects.nonNull(componentScan)) {
for (String basePackage : componentScan.basePackages()) {
// com.shunyum.a05
// classpath*:com/shunyum/a05/**/*.class
String path = "classpath*:" + basePackage.replace(".", "/") + "/**/*.class";
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
AnnotationBeanNameGenerator annotationBeanNameGenerator = new AnnotationBeanNameGenerator();
for (Resource resource : resources) {
MetadataReader metadataReader = factory.getMetadataReader(resource);
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
if (annotationMetadata.hasAnnotation(Component.class.getName())
|| annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(metadataReader.getClassMetadata().getClassName())
.getBeanDefinition();
String beanName = annotationBeanNameGenerator.generateBeanName(beanDefinition,
registry);
registry.registerBeanDefinition(beanName, beanDefinition);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.2 自定义Bean工厂后处理器来处理@Bean注解
public class AtBeanPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
try {
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
MetadataReader metadataReader = factory.getMetadataReader(new ClassPathResource("com/shunyum/a05/Config.class"));
Set<MethodMetadata> annotatedMethods = metadataReader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
for (MethodMetadata method : annotatedMethods) {
System.out.println(method);
String initMethod = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition()
.setFactoryMethodOnBean(method.getMethodName(), "config")
// 解决通过@Bean方法创建Bean时的自动注入
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR)
// 处理initMethod属性
.setInitMethodName(initMethod)
;
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
registry.registerBeanDefinition(method.getMethodName(), beanDefinition);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
2.3 自定义Bean工厂后处理器来处理@Mapper注解
public class MyMapperScan implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
try {
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath:com/shunyum/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()) {
AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class)
.addConstructorArgValue(classMetadata.getClassName())
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)
.getBeanDefinition();
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 {
}
}