- BeanFactory 后处理器的作用:为BeanFactory提供扩展
- 常见的BeanFactory后处理器
Bean1
、
Bean2
、
Mapper1
、
Mapper2
、
Config
5个类
Bean2
上面加上@Component
Config
上加@Component
注解和@ComponentScan
注解,Config
中通过@Bean
注解定义Bean1
Mapper1
、Mapper2
上加@Mapper
注解Config
@Component
@ComponentScan("com/example/spring01/com/a05")
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://120.77.215.102:3306/czctest?characterEncoding=utf-8");
dataSource.setUsername("root");
dataSource.setPassword("czc521190");
return dataSource;
}
}
Bean1和Bean2
@Slf4j
public class Bean1 {
public Bean1(){
log.info("我是被 spring 管理啦");
}
}
-----------------------------------------
@Component
@Slf4j
public class Bean2 {
public Bean2(){
log.info("我是被 spring 管理啦");
}
}
Mapper1和Mapper2
@Mapper
public interface Mapper1 {
}
----------------------------
@Mapper
public interface Mapper2 {
}
public class TestBeanFactoryPostProcessors {
public static void main(String[] args) {
// GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config",Config.class);
// 解析@ComponentScan、@Bean、@Import、@ImportResource注解
context.registerBean(ConfigurationClassPostProcessor.class);
// 添加Bean工厂后处理器MapperScannerConfigurer,解析@MapperScan注解
context.registerBean(MapperScannerConfigurer.class,db->{
db.getPropertyValues().add("basePackage","com/example/spring01/com/a05/mapper");
});
// 初始化容器
context.refresh();
for (String name:context.getBeanDefinitionNames()){
System.out.println("name--:"+name);
}
// 容器销毁
context.close();
}
}
@Component
、@Bean
对应的Bean
工厂后处理器是ConfigurationClassPostProcessor
;@MapperScan
对应的Bean
工厂后处理器是MapperScannerConfigurer
。ComponentScan将加了
@Controller,@Repository,@Service,@Component注解的类注册到spring容器中
public static void main(String[] args) throws Exception {
// GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config",Config.class);
// 模拟@ComponentScan
ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
if(componentScan != null){
for (String s : componentScan.basePackages()) {
System.out.println(s);
//com.example.spring01.com.a05.component -> classpath*:com/example/spring01/com/a05/component/**/*.class
String path = "classpath*:" + s.replace(".","/") + "/**/*.class";
System.out.println(path);
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
Resource[] resources = context.getResources(path);
AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
for (Resource resource : resources) {
System.out.println("resource---"+resource);
MetadataReader reader = factory.getMetadataReader(resource);
AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
System.out.println("类名:"+ reader.getClassMetadata().getClassName());
System.out.println("是否加了 @Component 注解:" + annotationMetadata.hasAnnotation(Component.class.getName()));
System.out.println("是否加了 @Component派生 注解:" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));
// 如果加了@Component 注解 或在 @Component派生 注解
if(annotationMetadata.hasAnnotation(Component.class.getName() ) || annotationMetadata.hasMetaAnnotation(Component.class.getName())){
// 生成 beanDefinition
AbstractBeanDefinition bd =
BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName()).getBeanDefinition();
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
String beanName = generator.generateBeanName(bd, beanFactory);
beanFactory.registerBeanDefinition(beanName,bd);
}
}
}
}
// 初始化容器
context.refresh();
for (String name:context.getBeanDefinitionNames()){
System.out.println("name--:"+name);
}
// 容器销毁
context.close();
}
实现BeanFactoryPostProcessor两处修改
context.getResources(path) -> new PathMatchingResourcePatternResolver().getResources(path);
- 1
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory(); ------------- if(configurableListableBeanFactory instanceof DefaultListableBeanFactory){ DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory; String beanName = generator.generateBeanName(bd, beanFactory); beanFactory.registerBeanDefinition(beanName,bd); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
public class ComponentScanPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
try {
// 模拟@ComponentScan
ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
if(componentScan != null){
for (String s : componentScan.basePackages()) {
System.out.println(s);
//com.example.spring01.com.a05.component -> classpath*:com/example/spring01/com/a05/component/**/*.class
String path = "classpath*:" + s.replace(".","/") + "/**/*.class";
System.out.println(path);
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
for (Resource resource : resources) {
System.out.println("resource---"+resource);
MetadataReader reader = factory.getMetadataReader(resource);
AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
System.out.println("类名:"+ reader.getClassMetadata().getClassName());
System.out.println("是否加了 @Component 注解:" + annotationMetadata.hasAnnotation(Component.class.getName()));
System.out.println("是否加了 @Component派生 注解:" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));
// 如果加了@Component 注解 或在 @Component派生 注解
if(annotationMetadata.hasAnnotation(Component.class.getName() ) || annotationMetadata.hasMetaAnnotation(Component.class.getName())){
// 生成 beanDefinition
AbstractBeanDefinition bd =
BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName()).getBeanDefinition();
if(configurableListableBeanFactory instanceof DefaultListableBeanFactory){
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
String beanName = generator.generateBeanName(bd, beanFactory);
beanFactory.registerBeanDefinition(beanName,bd);
}
}
}
}
}
}catch (IOException e) {
e.printStackTrace();
}
}
}
引用自己写的后处理器
public static void main(String[] args) throws Exception {
// GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config",Config.class);
context.registerBean(ComponentScanPostProcessor.class);
// 初始化容器
context.refresh();
for (String name:context.getBeanDefinitionNames()){
System.out.println("name--:"+name);
}
// 容器销毁
context.close();
}
@Component
注解实现BeanDefinitionRegistryPostProcessor
两次修改
context.getResources(path) -> new PathMatchingResourcePatternResolver().getResources(path);
- 1
去掉DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
- 1
public class CandyComponentScanPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
try {
// 模拟@ComponentScan
ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
if(componentScan != null){
for (String s : componentScan.basePackages()) {
System.out.println(s);
//com.example.spring01.com.a05.component -> classpath*:com/example/spring01/com/a05/component/**/*.class
String path = "classpath*:" + s.replace(".","/") + "/**/*.class";
System.out.println(path);
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
for (Resource resource : resources) {
System.out.println("resource---"+resource);
MetadataReader reader = factory.getMetadataReader(resource);
AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
System.out.println("类名:"+ reader.getClassMetadata().getClassName());
System.out.println("是否加了 @Component 注解:" + annotationMetadata.hasAnnotation(Component.class.getName()));
System.out.println("是否加了 @Component派生 注解:" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));
// 如果加了@Component 注解 或在 @Component派生 注解
if(annotationMetadata.hasAnnotation(Component.class.getName() ) || annotationMetadata.hasMetaAnnotation(Component.class.getName())){
// 生成 beanDefinition
AbstractBeanDefinition bd =
BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName()).getBeanDefinition();
String beanName = generator.generateBeanName(bd, beanFactory);
beanFactory.registerBeanDefinition(beanName,bd);
}
}
}
}
}catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/example/spring01/com/a05/Config.class"));
Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
for (MethodMetadata method : methods) {
System.out.println("method:" + method);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
builder.setFactoryMethodOnBean(method.getMethodName(),"config");
builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
AbstractBeanDefinition bd = builder.getBeanDefinition();
context.getDefaultListableBeanFactory().registerBeanDefinition(method.getMethodName(),bd);
String initMethod = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
if(initMethod.length() >0 ){
builder.setInitMethodName(initMethod);
}
}
AtBeanPostProcessor 类
public class AtBeanPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
try {
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/example/spring01/com/a05/Config.class"));
Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
for (MethodMetadata method : methods) {
System.out.println("method:" + method);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
builder.setFactoryMethodOnBean(method.getMethodName(),"config");
builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
AbstractBeanDefinition bd = builder.getBeanDefinition();
if(configurableListableBeanFactory instanceof DefaultListableBeanFactory) {
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
beanFactory.registerBeanDefinition(method.getMethodName(), bd);
}
String initMethod = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
if(initMethod.length() >0 ){
builder.setInitMethodName(initMethod);
}
}
}catch (Exception e){
}
}
}
在Config,使用@Bean 注册
@Bean
public MapperFactoryBean<Mapper1> mapper1(SqlSessionFactory sqlSessionFactory){
MapperFactoryBean<Mapper1> factoryBean = new MapperFactoryBean<>(Mapper1.class);
factoryBean.setSqlSessionFactory(sqlSessionFactory);
return factoryBean;
}
@Bean
public MapperFactoryBean<Mapper2> mapper2(SqlSessionFactory sqlSessionFactory){
MapperFactoryBean<Mapper2> factoryBean = new MapperFactoryBean<>(Mapper2.class);
factoryBean.setSqlSessionFactory(sqlSessionFactory);
return factoryBean;
}
这里不能使用名字生成器和MapperFactoryBean的BeanDefinition作为参数直接生成名字,这样会导致多个相同的类型的对象因为名字一样产生覆盖的问题
解决办法 这里参考Spring源码的做法用@Mapper注解修饰的接口的BeanDefinition作为参数生成名字
public class MapperPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
try {
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath:com/example/spring01/com/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) {
throw new RuntimeException(e);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}