内容概要:
- BeanFactory 后处理器的作用: 为 BeanFactory 提供扩展
- 为 BeanFactory 补充一些bean的定义,用于解析 @Configuration @Component @Bean…
- 常见的 BeanFactory 后处理器
- ConfigurationClassPostProcessor
@Configuration
@ComponentScan("com.spring.learn.component")
public class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
}
@Slf4j
class Bean1 {
public Bean1() {
log.debug("初始化 Bean1");
}
}
// com.spring.learn.component 包下的 Bean2 Bean3 Bean4
@Slf4j
@Component
public class Bean2 {
public Bean2() {
log.debug("初始化 Bean2");
}
}
@Slf4j
@Controller
public class Bean3 {
public Bean3() {
log.debug("初始化 Bean3");
}
}
@Slf4j
public class Bean4 {
public Bean4() {
log.debug("初始化 Bean4");
}
}
public static void test(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config", Config.class);
// 初始化容器
context.refresh(); // 用于初始化所有单例,执行BeanFactory后处理器和Bean后处理器
// 只有config的BeanDefinition, config里的 @ComponentScan @Bean 注解都没有解析生效
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName); // 只有config
}
// 销毁容器
context.close();
}
ConfigurationClassPostProcessor
: BeanFactory 后处理器,可以解析 @ComponentScan @Bean @Import @ImportResource…等注解public static void testConfigurationClassPostProcessor(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config", Config.class);
// 添加BeanFactory后处理器,可以解析 @ComponentScan @Bean @Import @ImportResource...
context.registerBean(ConfigurationClassPostProcessor.class);
// 初始化容器
context.refresh(); // 用于初始化所有单例,执行BeanFactory后处理器和Bean后处理器
// 5个的BeanDefinition,config里的 @ComponentScan @Bean 注解有解析生效
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName); // config、ConfigurationClassPostProcessor、bean2、bean3、bean1
}
// 销毁容器
context.close();
}
ConfigurationClassPostProcessor
BeanFactory 后处理器的执行过程@ComponentScan
: 扫描指定包下添加了 @Component 注解的Bean,并将Bean管理到Spring容器中(即将Bean的定义注册到BeanFactory里)
com.spring.learn.component
-> classpath*:com/spring/learn/component/**/*.class
(** 是指所有子包)public static void testComponentScan(String[] args) throws IOException {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config", Config.class);
// 查找某各类上有没有指定的注解
ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
// 以解析 @ComponentScan 为例,扫描指定包下添加了 @Component 注解的Bean,并将Bean管理到Spring容器中(即将Bean的定义注册到BeanFactory里)
if (componentScan != null) {
// 获取 @ComponentScan 扫描的包,扫描包下的所有class文件
for (String basePackage : componentScan.basePackages()) {
System.out.println(basePackage);
// Spring 最终是以文件的方式获取资源,如 com.spring.learn.component -> classpath*:com/spring/learn/component/**/*.class (** 是指所有子包)
String path = "classpath*:" + basePackage.replace(".", "/") + "/**/*.class";
System.out.println(path);
// 用于读取类(*.class文件)的元信息,包括类的名字、注解等信息
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
// 获取文件资源
Resource[] resources = context.getResources(path);
// 根据注解获取BeanName,向BeanFactory中注册Bean的定义时,需要beanName,所以用到了这个类
AnnotationBeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
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()));
// 判断类上是否添加了指定注解的派生注解(只添加了注解,该方法返回false)
// 派生注解: 如 @Controller 注解上有 @Component,则类上添加 @Controller 注解就是添加了 @Component 派生注解
System.out.println("是否添加了 @Component 派生注解:" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));
if (annotationMetadata.hasAnnotation(Component.class.getName()) || annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
// 生成当前类的BeanDefinition,将Bean的定义注册到BeanFactory里
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName()).getBeanDefinition();
String beanName = beanNameGenerator.generateBeanName(beanDefinition, beanFactory);
beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
}
}
}
// 初始化容器
context.refresh(); // 用于初始化所有单例,执行BeanFactory后处理器和Bean后处理器
System.out.println(">>>>>>>>>>");
// 3个的BeanDefinition,@ComponentScan 注解有解析生效
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName); // config bean2 bean3
}
// 销毁容器
context.close();
}
postProcessBeanFactory()
在执行context.refresh()时会回调这个方法调用postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
方法/**
* 根据 TestBeanFactoryPostProcessor.testComponentScan() 方法,自定义一个解析 @ComponentScan 注解的BeanFactory后处理器
* 实现 BeanFactoryPostProcessor(或者其子接口 BeanDefinitionRegistryPostProcessor), 重写postProcessBeanFactory() 方法,在执行context.refresh()时会回调这个方法调用
*/
public class ComponentScanPostProcessor implements BeanFactoryPostProcessor {
/**
* 执行时机: 执行context.refresh()时,会调用该方法
* @param configurableListableBeanFactory
* @throws BeansException
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
try {
// 查找某各类上有没有指定的注解
ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
// 以解析 @ComponentScan 为例,扫描指定包下添加了 @Component 注解的Bean,并将Bean管理到Spring容器中(即将Bean的定义注册到BeanFactory里)
if (componentScan != null) {
// 获取 @ComponentScan 扫描的包,扫描包下的所有class文件
for (String basePackage : componentScan.basePackages()) {
System.out.println(basePackage);
// Spring 最终是以文件的方式获取资源,如 com.spring.learn.component -> classpath*:com/spring/learn/component/**/*.class (** 是指所有子包)
String path = "classpath*:" + basePackage.replace(".", "/") + "/**/*.class";
// 用于读取类(*.class文件)的元信息,包括类的名字、注解等信息
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
// 获取文件资源
Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
// 根据注解获取BeanName,向BeanFactory中注册Bean的定义时,需要beanName,所以用到了这个类
AnnotationBeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
for (Resource resource : resources) {
MetadataReader reader = factory.getMetadataReader(resource);
AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
// 判断类上是否直接添加了指定注解 / 派生注解
// 派生注解: 如 @Controller 注解上有 @Component,则类上添加 @Controller 注解就是添加了 @Component 派生注解
if (annotationMetadata.hasAnnotation(Component.class.getName()) || annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
// 生成当前类的BeanDefinition,将Bean的定义注册到BeanFactory里
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName()).getBeanDefinition();
String beanName = beanNameGenerator.generateBeanName(beanDefinition, beanFactory);
beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(beanMethod.getReturnTypeName()).getBeanDefinition();
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition()
.setFactoryMethodOnBean(factoryMethodName, factoryBeanName)
.getBeanDefinition();
build.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
@Configuration
@ComponentScan("com.huat.lisa.studyspring.s05.component")
public class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean(initMethod = "init")
public DruidDataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean;
}
}
public static void testBean(String[] args) throws IOException {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config", Config.class);
// 以解析 @Bean 为例, 如何将Bean添加到Spring容器中进行管理,又如何初始化以及获取Bean对象
// 根据class文件读取 @Configuration 注解标注的类(Config类)的元信息,根据配置类元信息,获取所有 @Bean 注解标注的方法
// 这种方式获取类信息不会使用反射,效率更高,更推荐这种方式
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/huat/lisa/studyspring/s05/Config.class"));
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
// 获取使用 @Bean 注解标注的所有方法,将方法返回的Bean注册到BeanFactory
Set<MethodMetadata> beanMethods = annotationMetadata.getAnnotatedMethods(Bean.class.getName());
for (MethodMetadata beanMethod : beanMethods) {
System.out.println(beanMethod + "--" + beanMethod.getDeclaringClassName() + "--" + beanMethod.getMethodName() + "--" + beanMethod.getReturnTypeName());
String initMethodName = beanMethod.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
// 设置工厂方法名 工厂类名,创建Bean的定义,告诉BeanFactory要通过哪个工厂方法来创建Bean
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition()
.setFactoryMethodOnBean(beanMethod.getMethodName(), "config")
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); // 设置自动装配模式
if (initMethodName.length() > 0) {
builder.setInitMethodName(initMethodName); // 设置初始化方法
}
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
beanFactory.registerBeanDefinition(beanMethod.getMethodName(), beanDefinition);
}
// 初始化容器,用于初始化所有单例,执行BeanFactory后处理器和Bean后处理器
context.refresh();
// config bean1 sqlSessionFactoryBean dataSource, 其中sqlSessionFactoryBean设置dataSource成功,dataSource设置db连接信息成功,也执行了init方法
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
context.close();
}