1.5.1BeanFactory后处理器的作用:为BeanFactory提供扩展
- ConfigurationClassPostProcessor和MapperScannerConfigurer基本作用:扫描所有注解的包
@Slf4j
public class Bean1 {
public Bean1() {
log.debug("我被 Spring 管理啦");
}
}
@Configuration
@ComponentScan("com.spring.demo.demo05.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/javatest");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
}
@Mapper
public interface Mapper1 {
}
项目结构
---demo05
------component
---------Bean2
---------Bean3
---------Bean4
------mapper
---------Mapper2
---------Mapper2
---------Mapper3
------A05Application
------Bean1
------Config
@Slf4j
public class A05Application {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config",Config.class);
context.registerBean(ConfigurationClassPostProcessor.class);
context.registerBean(MapperScannerConfigurer.class,db->{
db.getPropertyValues().add("basePackage","com.spring.demo.demo05.mapper");
});
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
context.close();
}
}
运行结果:
config
org.springframework.context.annotation.ConfigurationClassPostProcessor
org.mybatis.spring.mapper.MapperScannerConfigurer
bean2
bean3
bean1
sqlSessionFactoryBean
dataSource
mapper1
mapper2
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
如果不添加后置处理器的解析,运行结果:
config
1.5.2常见的BeanFactory后处理器
- 组件扫描ComponentScan:根据组件扫描找到对应的包,获取到该包下的所有资源
@Slf4j
public class A05Application {
public static void main(String[] args) throws IOException {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config",Config.class);
ComponentScan annotation = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
if(annotation != null){
for (String s : annotation.basePackages()) {
System.out.println("组件扫描到的包:"+s);
String path = "classpath*:"+s.replace(".", "/")+"/**/*.class";
System.out.println("资源路径:"+path);
Resource[] resource = context.getResources(path);
for (Resource resource1 : resource) {
System.out.println(resource1);
}
}
}
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
context.close();
}
}
运行结果:
组件扫描到的包:com.spring.demo.demo05.component
资源路径:classpath*:com/spring/demo/demo05/component/**/*.class
file [E:\Demo\JavaDemo\SpringSourceCodeDemo\target\classes\com\spring\demo\demo05\component\Bean2.class]
file [E:\Demo\JavaDemo\SpringSourceCodeDemo\target\classes\com\spring\demo\demo05\component\Bean3.class]
file [E:\Demo\JavaDemo\SpringSourceCodeDemo\target\classes\com\spring\demo\demo05\component\Bean4.class]
- 对上面的方法修改一下,可以判断类上是否加了某些注解
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
Resource[] resource = context.getResources(path);
for (Resource resource1 : resource) {
MetadataReader metadataReader = factory.getMetadataReader(resource1);
System.out.println("类名:"+metadataReader.getClassMetadata().getClassName());
System.out.println("是否加了@Compoent:"+metadataReader.getAnnotationMetadata().hasAnnotation(Component.class.getName()));
System.out.println("是否间接加了@Compoent:"+metadataReader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName()));
System.out.println("--------");
}
运行结果:
类名:com.spring.demo.demo05.component.Bean2
是否加了@Compoent:true
是否间接加了@Compoent:false
--------
类名:com.spring.demo.demo05.component.Bean3
是否加了@Compoent:false
是否间接加了@Compoent:true
--------
类名:com.spring.demo.demo05.component.Bean4
是否加了@Compoent:false
是否间接加了@Compoent:false
--------
- 将加了或间接加了@Compoent注解的类注册为Bean
修改2中的代码
Resource[] resource = context.getResources(path);
AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
for (Resource resource1 : resource) {
MetadataReader metadataReader = factory.getMetadataReader(resource1);
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
if(annotationMetadata.hasAnnotation(Component.class.getName())
|| annotationMetadata.hasMetaAnnotation(Component.class.getName())){
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(metadataReader.getClassMetadata().getClassName())
.getBeanDefinition();
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
String name = generator.generateBeanName(beanDefinition, beanFactory);
beanFactory.registerBeanDefinition(name,beanDefinition);
}
}
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println("bean:"+name);
}
context.close();
运行结果:
bean:config
bean:bean2
bean:bean3
我们可以将该方法抽取出来:
- 新建ComponentScanPostProcessor类,抽取代码
public class ComponentScanPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory){
try {
ComponentScan annotation = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
if (annotation != null) {
for (String s : annotation.basePackages()) {
String path = "classpath*:" + s.replace(".", "/") + "/**/*.class";
System.out.println(path);
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
Resource[] resource = new PathMatchingResourcePatternResolver().getResources(path);
AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
for (Resource resource1 : resource) {
MetadataReader metadataReader = factory.getMetadataReader(resource1);
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
if (annotationMetadata.hasAnnotation(Component.class.getName())
|| annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(metadataReader.getClassMetadata().getClassName())
.getBeanDefinition();
String name = generator.generateBeanName(beanDefinition, beanFactory);
beanFactory.registerBeanDefinition(name, beanDefinition);
}
}
}
}
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
@Slf4j
public class A05Application {
public static void main(String[] args) throws IOException {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config",Config.class);
context.registerBean(ComponentScanPostProcessor.class);
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println("bean:"+name);
}
context.close();
}
}
运行结果:
bean:config
bean:com.spring.demo.demo05.ComponentScanPostProcessor
bean:bean2
bean:bean3
- @Bean注解的解析
public class AtBeanPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
try{
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/spring/demo/demo05/Config.class"));
Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
for (MethodMetadata method : methods) {
System.out.println("bean解析--->"+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 != null){
builder.setInitMethodName(initMethod);
}
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
beanFactory.registerBeanDefinition(method.getMethodName(),beanDefinition);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
context.registerBean(AtBeanPostProcessor.class);
运行结果:
bean解析--->org.springframework.core.type.classreading.SimpleMethodMetadata@3ffcd140
bean解析--->org.springframework.core.type.classreading.SimpleMethodMetadata@23bb8443
bean解析--->org.springframework.core.type.classreading.SimpleMethodMetadata@1176dcec
bean:config
bean:com.spring.demo.demo05.AtBeanPostProcessor
bean:bean1
bean:sqlSessionFactoryBean
bean:dataSource
- @Mapper解析
最简单的解析:
@Bean
public MapperFactoryBean<Mapper1> mapper1(SqlSessionFactory sqlSessionFactory){
MapperFactoryBean<Mapper1> factory = new MapperFactoryBean<>(Mapper1.class);
factory.setSqlSessionFactory(sqlSessionFactory);
return factory;
}
@Bean
public MapperFactoryBean<Mapper2> mapper2(SqlSessionFactory sqlSessionFactory){
MapperFactoryBean<Mapper2> factory = new MapperFactoryBean<>(Mapper2.class);
factory.setSqlSessionFactory(sqlSessionFactory);
return factory;
}
但是这样的比较死板,不易扩展,虽然spring内部 也是这样实现的,但是spring也有更好的一种实现,我们模拟一下:
public class MapperPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
try {
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath:com/spring/demo/demo05/mapper/**/*.class");
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
for (Resource resource : resources) {
MetadataReader reader = factory.getMetadataReader(resource);
ClassMetadata classMetadata = reader.getClassMetadata();
if (classMetadata.isInterface()) {
AbstractBeanDefinition bd1 = 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,bd1);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
context.registerBean(MapperPostProcessor.class);
运行结果:
bean:config
bean:com.spring.demo.demo05.AtBeanPostProcessor
bean:com.spring.demo.demo05.MapperPostProcessor
bean:bean1
bean:sqlSessionFactoryBean
bean:dataSource
bean:mapper1
bean:mapper2
mapper1和mapper已经被解析到了
最后的目录结构:
---demo05
------component
---------Bean2
---------Bean3
---------Bean4
------mapper
---------Mapper2
---------Mapper2
---------Mapper3
------A05Application
------Bean1
------Config
------AtBeanPostProcessor
------ComponentScanPostProcessor
------MapperPostProcessor
|