BeanFactory 后处理器
演示 - BeanFactory 后处理器的作用
代码参考
A05
package com.itheima.a05;
import com.itheima.a05.mapper.Mapper1;
import com.itheima.a05.mapper.Mapper2;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
/*
BeanFactory 后处理器的作用
*/
public class A05 {
private static final Logger log = LoggerFactory.getLogger(A05.class);
public static void main(String[] args) throws IOException {
// ⬇️GenericApplicationContext 是一个【干净】的容器
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config", Config.class);
// ⬇️初始化容器
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
// ⬇️销毁容器
context.close();
/*
学到了什么
a. @ComponentScan, @Bean, @Mapper 等注解的解析属于核心容器(即 BeanFactory)的扩展功能
b. 这些扩展功能由不同的 BeanFactory 后处理器来完成, 其实主要就是补充了一些 bean 定义
*/
}
}
Config
package com.itheima.a05;
import com.alibaba.druid.pool.DruidDataSource;
import com.itheima.a05.mapper.Mapper1;
import com.itheima.a05.mapper.Mapper2;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
/**
* @Configuration 标注的类相当于一个工厂
* 里面的 @Bean 其实就充当了一个共工厂方法
* 所以在创建的时候我们用的是工厂方法的模式来创建BeanDeification
*/
@Configuration
@ComponentScan("com.itheima.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/test");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
// @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;
// }
}
下面做一些解释
当我们运行下面代码时会注册一个config的bean,但是在Config.class 类中,本身被标志为@Configuration,里面还有一些以@Bean注解注入的bean,在我们预期是不但注册了config,还要注册类中标志了@Bean的bean,下面我们运行一下如下代码打印一下BeanDefinitionName看看都有哪些bean注入进来了:
结果(可以发现只有config注入了进来):
可以得出结论,config类中的 @ComponentScan、@Bean等注解都没有生效(没解析),是谁来解析呢,就是我们要讨论的BeanFactory后处理器。
ConfigurationClassPostProcessor BeanFactory后处理器
在加上这个 ConfigurationClassPostProcessor 后处理器之后在运行一下。(这里 context.refresh();会初始化容器,,也就是加载一些我们需要的类,所以就只需将后处理器注入即可)
context.registerBean(ConfigurationClassPostProcessor.class); // 可以解析 @ComponentScan @Bean @Import @ImportResoure
结果如下:(可以发现除了config、ConfigurationClassPostProcessor以外,又多了几个,这些都是我们利用注解入@Bean、@Component注入进去的):
MapperScannerConfigurer BeanFactory后处理器
这个是根MyBatis整合用到的一个后处理器,作用就是扫描一些mybatis的mapper接口作为BeanDefinition补充到我们的bean工厂来,在 @MapperScan底层也是这个在起作用
加上代码之后运行一下(第二个参数补充了一下扫描的包):
mapper 代码(记得要扫描你的mapper放的包下):
package com.itheima.a05.mapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface Mapper1 {
}
结果(标记的地方是注册进去的一些Bean):
第一个 MapperScannerConfigurer 我们自己注入进来的吧,在后面 mapper1、mapper2 也成功注入进来了,说明我们配置的扫描mapper接口生效了,在后面五个是一些常用的后处理器,作用是解析一些注解等,具体在前面已经讲过了。
总结
- ConfigurationClassPostProcessor 可以解析
- @ComponentScan
- @Bean
- @Import
- @ImportResource
- MapperScannerConfigurer 可以解析
- Mapper 接口
收获
- @ComponentScan, @Bean, @Mapper 等注解的解析属于核心容器(即 BeanFactory)的扩展功能
- 这些扩展功能由不同的 BeanFactory 后处理器来完成,其实主要就是补充了一些 bean 定义