老样子,直接上代码演示,准备一个干净的容器:
// ⬇️GenericApplicationContext 是一个【干净】的容器
GenericApplicationContext context = new GenericApplicationContext();
//注册configBean
context.registerBean("config", Config.class);
// ⬇️初始化容器
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
// ⬇️销毁容器
context.close();
config类:
@Configuration
@ComponentScan("com.tangyuan.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(initMethod = "init")
public DruidDataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/shopping");
dataSource.setUsername("root");
dataSource.setPassword("1234");
return dataSource;
}
}
按照代码演示,这里一共有5个Bean,一个Config,一个component包下面的Bean,还有Config类管理的三个bean
来看输出结果:
为什么只输出了我们自己编程添加的bean?因为@ComponentScan组件扫描没有生效,@Bean注解也没有生效。
我们要怎么样才能解析这些注解呢?使用Bean工厂后处理器
//解析的注解:@ComponentScan @Bean @Import @ImportResource
context.registerBean(ConfigurationClassPostProcessor.class);
这时,我们来看输出结果:
mapper层接口的扫描:
context.registerBean(MapperScannerConfigurer.class, bd -> { // @MapperScanner
bd.getPropertyValues().add("basePackage", "com.tangyuan.a05.mapper");
});
输出结果如下:
模拟@ComponentScan注解的解析:
//查询类上是否有 ComponentScan注解
ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
if (componentScan != null) {
for (String p : componentScan.basePackages()) {
//获取包名
System.out.println(p);
//转换格式
// com.tangyuan.a05.component -> classpath*:com/tangyuan/a05/component/**/*.class
String path = "classpath*:" + p.replace(".", "/") + "/**/*.class";
System.out.println(path);
//读取类上面的源信息
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
//通过通配符获取资源
Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
//分析Component注解,生成bean的名称
AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
for (Resource resource : resources) {
// System.out.println(resource);
//信息存放位置
MetadataReader reader = factory.getMetadataReader(resource);
// 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()));
//如果直接加了 ComponentScan注解或者间接加了 ComponentScan注解
if (annotationMetadata.hasAnnotation(Component.class.getName())
|| annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
//创建BeanDefinition
AbstractBeanDefinition bd = BeanDefinitionBuilder
.genericBeanDefinition(reader.getClassMetadata().getClassName())
.getBeanDefinition();
//生成bean的名称
String name = generator.generateBeanName(bd, beanFactory);
//添加到bean工厂中
beanFactory.registerBeanDefinition(name, bd);
}
}
}
}
输出结果:
在这里,我们可以将代码抽取出来,整理为一个独立的bean工厂后处理器:
//分析ComponentScan注解,并作Bean定义的补充
public class ComponentScanPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override // context.refresh
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
try {
//查询类上是否有 ComponentScan注解
ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
if (componentScan != null) {
for (String p : componentScan.basePackages()) {
//获取包名
System.out.println(p);
//转换格式
// com.tangyuan.a05.component -> classpath*:com/tangyuan/a05/component/**/*.class
String path = "classpath*:" + p.replace(".", "/") + "/**/*.class";
System.out.println(path);
//读取类上面的源信息
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
//通过通配符获取资源
Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
//分析Component注解,生成bean的名称
AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
for (Resource resource : resources) {
// System.out.println(resource);
//信息存放位置
MetadataReader reader = factory.getMetadataReader(resource);
// 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()));
//如果直接加了 ComponentScan注解或者间接加了 ComponentScan注解
if (annotationMetadata.hasAnnotation(Component.class.getName())
|| annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
//创建BeanDefinition
AbstractBeanDefinition bd = BeanDefinitionBuilder
.genericBeanDefinition(reader.getClassMetadata().getClassName())
.getBeanDefinition();
//生成bean的名称
String name = generator.generateBeanName(bd, beanFactory);
//添加到bean工厂中
beanFactory.registerBeanDefinition(name, bd);
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用时,将Bean工厂处理器注册即可:
context.registerBean(ComponentScanPostProcessor.class); // 解析 @ComponentScan
注:配置类充当的是工厂的角色,配置类中用@Bean标记的方法角色工厂方法
解析 @Bean
//@Bean注解
public class AtBeanPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
try {
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
//读取配置类的信息
MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/tangyuan/a05/Config.class"));
//获取被注解标注的方法信息
Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
for (MethodMetadata method : methods) {
System.out.println(method);
//获取@Bean注解的属性
String initMethod = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
//创建 BeanDefinitionBuilder 对象(用工厂方法来创建)
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
//工厂方法名字
builder.setFactoryMethodOnBean(method.getMethodName(), "config");
//指定装配模式
builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
if (initMethod.length() > 0) {
//初始化方法名字
builder.setInitMethodName(initMethod);
}
AbstractBeanDefinition bd = builder.getBeanDefinition();
//注册
beanFactory.registerBeanDefinition(method.getMethodName(), bd);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
手动添加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;
}
缺点:不能批量添加
//mapper接口
public class MapperPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
try {
//通配符解析器
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath:com/tangyuan/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()) {
//定义BeanDefinition
AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class)
//给构造方法设置参数值
.addConstructorArgValue(classMetadata.getClassName())
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)
.getBeanDefinition();
//根据mapper接口生成BeanDefinition
AbstractBeanDefinition bd2 = BeanDefinitionBuilder.genericBeanDefinition(classMetadata.getClassName()).getBeanDefinition();
//根据bd2生成名字
String name = generator.generateBeanName(bd2, beanFactory);
//注册
beanFactory.registerBeanDefinition(name, bd);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
知识点:
-
ConfigurationClassPostProcessor 可以解析
-
@ComponentScan
-
@Bean
-
@Import
-
@ImportResource
-
-
MapperScannerConfigurer 可以解析
-
Mapper 接口
-
收获💡
-
@ComponentScan, @Bean, @Mapper 等注解的解析属于核心容器(即 BeanFactory)的扩展功能
-
这些扩展功能由不同的 BeanFactory 后处理器来完成,其实主要就是补充了一些 bean 定义