一、什么是ImportBeanDefinitionRegistrar
ImportBeanDefinitionRegistrar接口是也是spring的扩展点之一,ImportBeanDefinitionRegistrar类只能通过其他类 @Import的方式来加载,通常是启动类或配置类。它可以支持我们自己写的代码封装成BeanDefinition对象;实现此接口的类会回调postProcessBeanDefinitionRegistry方法,注册到spring容器中。
把bean注入到spring容器不止有 @Service @Component等注解方式;还可以实现此接口,这种方式是最灵活的,能在registerBeanDefinitions
方法中获取到BeanDefinitionRegistry
容器注册对象,可以手动控制BeanDefinition的创建和注册。
public interface ImportBeanDefinitionRegistrar {
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
this.registerBeanDefinitions(importingClassMetadata, registry);
}
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}
}
二、ImportBeanDefinitionRegistrar使用很简单
加载指定类
定义一个类TestImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar接口,在配置类TestConfiguration加上注解@Import一个TestImportBeanDefinitionRegistrar实现类,重写registerBeanDefinitions方法,手动注册bean,实现注册BeanDefinition到容器中,也可以实现一些Aware接口,以便获取Spring的一些数据。加载指定DataSource类如下:
public class TestImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar,ResourceLoaderAware,BeanFactoryAware {
private static ResourceLoader resourceLoader;
private static BeanFactory beanFactory;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//创建DataSourceBean
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(DataSource.class);
beanDefinition.setSynthetic(true);
MutablePropertyValues mpv = beanDefinition.getPropertyValues();
//spring名称约定为defaultTargetDataSource和targetDataSources
mpv.addPropertyValue("defaultTargetDataSource", defaultTargetDataSource);
mpv.addPropertyValue("targetDataSources", DataSourceSet.getTargetDataSourcesMap());
beanDefinitionRegistry.registerBeanDefinition("dataSource", beanDefinition);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory=beanFactory;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader=resourceLoader;
}
}
@Import(TestImportBeanDefinitionRegistrar.class)
@Configuration
public class TestConfiguration {
}
这样就注册了一个bean名字是dataSource,有两个属性分别是defaultTargetDataSource和targetDataSources。那么使用这个类直接用 @Autowired和@Resource注入即可。
加载扫描器类
如果我们并不知道需要register哪些bean。这里我们还需要借助一个扫描器类ClassPathBeanDefinitionScanner
,通过扫描器获取我们需要注册的bean。首先创建一个@Mapper
注解,再新建一个CountryMapper
类,使用该Mapper注解。
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
public @interface Mapper {
}
@Mapper
public class CountryMapper {
}
创建一个MyClassPathBeanDefinitionScanner
类继承ClassPathBeanDefinitionScanner
,扫描使用@Mapper
的注解的类,ClassPathBeanDefinitionScanner
又继承ClassPathScanningCandidateComponentProvider
类,ClassPathScanningCandidateComponentProvider
中有两个TypeFilter集合,includeFilters、excludeFilters。满足任意includeFilters会被加载,同样的满足任意excludeFilters不会被加载。
@Slf4j
public class MyClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner{
public MyClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
super(registry, useDefaultFilters);
}
protected void registerFilters() {
addIncludeFilter(new AnnotationTypeFilter(Mapper.class));
}
@Override
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
return super.doScan(basePackages);
}
}
registerFilters()方法
核心代码就是registerFilters()方法,然后在我们的ImportBeanDefinitionRegistrar
实现类中调用:
public class MapperAutoConfiguredMyBatisRegistrar
implements ImportBeanDefinitionRegistrar{
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
MyClassPathBeanDefinitionScanner scanner = new MyClassPathBeanDefinitionScanner(registry, false);
scanner.setResourceLoader(resourceLoader);
scanner.registerFilters();
scanner.doScan("com.faderw.school.domain");
}
}
这里我们自定义带有@Mapper注解的类CountryMapper就被注入到IOC容器了,可以直接使用噢。
三、ImportBeanDefinitionRegistrar原理
TestImportBeanDefinitionRegistrar是被TestConfiguration类import导入的,所以要加载到TestImportBeanDefinitionRegistrar必然要先加载TestConfiguration才行;所以先看Configuration的代码,找到ConfigurationClassPostProcessor类,它实现了BeanDefinitionRegistryPostProcessor接口。
Map<String, BeanDefinitionRegistryPostProcessor> beanMap =
beanFactory.getBeansOfType(BeanDefinitionRegistryPostProcessor.class, true, false);
List<BeanDefinitionRegistryPostProcessor> registryPostProcessorBeans =
new ArrayList<BeanDefinitionRegistryPostProcessor>(beanMap.values());
OrderComparator.sort(registryPostProcessorBeans);
for (BeanDefinitionRegistryPostProcessor postProcessor : registryPostProcessorBeans) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
从spring容器中拿到实现了BeanDefinitionRegistryPostProcessor接口的类。拿到后执行对应的postProcessBeanDefinitionRegistry方法:
//从invokeBeanFactoryPostProcessors方法调过来
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
RootBeanDefinition iabpp = new RootBeanDefinition(ImportAwareBeanPostProcessor.class);
iabpp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(IMPORT_AWARE_PROCESSOR_BEAN_NAME, iabpp);
//取得registry的id并做判重处理或记录
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called for this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called for this post-processor against " + registry);
}
//保存处理过的registry,避免重复处理
this.registriesPostProcessed.add(registryId);
//处理java配置形式的bean定义
processConfigBeanDefinitions(registry);
}
最后调用了processConfigBeanDefinitions方法处理java配置形式的bean定义:
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
Set<BeanDefinitionHolder> configCandidates = new LinkedHashSet<BeanDefinitionHolder>();
//加载当前已知所有bean定义
for (String beanName : registry.getBeanDefinitionNames()) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
// 判断对应bean是否为配置类,如果是,则加入到configCandidates
// @Configuration, @Component, @ComponentScan, @Import, @Bean等注解
if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
//如果找不到@configuration类,则立即返回
if (configCandidates.isEmpty()) {
return;
}
...........
// 实例化ConfigurationClassParser 为了解析 各个配置类
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
System.out.println("ConfigurationClassPostProcessor bd " + bd.getBeanClassName());
try {
if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parser.parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parser.parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("Failed to load bean class: " + bd.getBeanClassName(), ex);
}
}
parser.validate();
......
ConfigurationClassParser#parse方法:
public void parse(String className, String beanName) throws IOException {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
processConfigurationClass(new ConfigurationClass(reader, beanName));
}
processConfigurationClass方法:
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
...................
do {
//重点
metadata = doProcessConfigurationClass(configClass, metadata);
}
while (metadata != null);
.................
}
doProcessConfigurationClass方法:
protected AnnotationMetadata doProcessConfigurationClass(ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException {
// Recursively process any member (nested) classes first
processMemberClasses(metadata);
// Process any @PropertySource annotations
//处理@PropertySource 加载外面资源文件
AnnotationAttributes propertySource = MetadataUtils.attributesFor(metadata,
org.springframework.context.annotation.PropertySource.class);
if (propertySource != null) {
processPropertySource(propertySource);
}
// Process any @ComponentScan annotations
//处理 @ComponentScan 扫描包
AnnotationAttributes componentScan = MetadataUtils.attributesFor(metadata, ComponentScan.class);
if (componentScan != null) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, metadata.getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if necessary
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
this.parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
}
}
}
//处理@Import注解
// Process any @Import annotations
Set<Object> imports = new LinkedHashSet<Object>();
Set<String> visited = new LinkedHashSet<String>();
collectImports(metadata, imports, visited);
if (!imports.isEmpty()) {
processImport(configClass, metadata, imports, true);
}
// Process any @ImportResource annotations
if (metadata.isAnnotated(ImportResource.class.getName())) {
AnnotationAttributes importResource = MetadataUtils.attributesFor(metadata, ImportResource.class);
String[] resources = importResource.getStringArray("value");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// Process individual @Bean methods
//处理@Bean注解
Set<MethodMetadata> beanMethods = metadata.getAnnotatedMethods(Bean.class.getName());
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process superclass, if any
if (metadata.hasSuperClass()) {
String superclass = metadata.getSuperClassName();
if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// superclass found, return its annotation metadata and recurse
if (metadata instanceof StandardAnnotationMetadata) {
Class<?> clazz = ((StandardAnnotationMetadata) metadata).getIntrospectedClass();
return new StandardAnnotationMetadata(clazz.getSuperclass(), true);
}
else {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(superclass);
return reader.getAnnotationMetadata();
}
}
}
// No superclass -> processing is complete
return null;
}
processImport方法:
private void processImport(ConfigurationClass configClass, AnnotationMetadata metadata,
Collection<?> classesToImport, boolean checkForCircularImports) throws IOException {
if (checkForCircularImports && this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack, configClass.getMetadata()));
}else {
this.importStack.push(configClass);
try {
for (Object candidate : classesToImport) {
Object candidateToCheck = (candidate instanceof Class ? (Class) candidate :
this.metadataReaderFactory.getMetadataReader((String) candidate));
//实现ImportSelector接口的处理
if (checkAssignability(ImportSelector.class, candidateToCheck)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = (candidate instanceof Class ? (Class) candidate :
this.resourceLoader.getClassLoader().loadClass((String) candidate));
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
processImport(configClass, metadata, Arrays.asList(selector.selectImports(metadata)), false);
}
//实现ImportBeanDefinitionRegistrar接口的处理
else if (checkAssignability(ImportBeanDefinitionRegistrar.class, candidateToCheck)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = (candidate instanceof Class ? (Class) candidate :
this.resourceLoader.getClassLoader().loadClass((String) candidate));
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
invokeAwareMethods(registrar);
//调用该类的registerBeanDefinitions方法
registrar.registerBeanDefinitions(metadata, this.registry);
}
else {
//候选类不是importSelector或importBeanDefinitionRegistrar
//@Configuration类的处理
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as a @Configuration class
this.importStack.registerImport(metadata,
(candidate instanceof Class ? ((Class) candidate).getName() : (String) candidate));
processConfigurationClass(candidateToCheck instanceof Class ?
new ConfigurationClass((Class) candidateToCheck, true) :
new ConfigurationClass((MetadataReader) candidateToCheck, true));
}
}
}
catch (ClassNotFoundException ex) {
throw new NestedIOException("Failed to load import candidate class", ex);
}
finally {
this.importStack.pop();
}
}
}
最终调用了DefaultListableBeanFactory的registerBeanDefinition方法,这里就是处理ImportBeanDefinitionRegistrar接口实现类的地方:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if("configurationTest".equals(beanName)){
System.out.println(" registerBeanDefinition(String beanName, BeanDefinition beanDefinition) " + beanName);
}
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// old? 还记得 “允许 bean 覆盖” 这个配置吗?allowBeanDefinitionOverriding
BeanDefinition oldBeanDefinition;
synchronized (this.beanDefinitionMap) {
// 之后会看到,所有的 Bean 注册后会放入这个 beanDefinitionMap 中
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
// 处理重复名称的 Bean 定义的情况
if (oldBeanDefinition != null) {
if (!this.allowBeanDefinitionOverriding) {
// 如果不允许覆盖的话,抛异常
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
}
else {
//添加beanDefinitionNames
this.beanDefinitionNames.add(beanName);
this.frozenBeanDefinitionNames = null;
}
// 覆盖
this.beanDefinitionMap.put(beanName, beanDefinition);
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
Assert.hasText(beanName, "'beanName' must not be empty");
synchronized (this.beanDefinitionMap) {
BeanDefinition bd = this.beanDefinitionMap.remove(beanName);
if (bd == null) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("No bean named '" + beanName + "' found in " + this);
}
throw new NoSuchBeanDefinitionException(beanName);
}
this.beanDefinitionNames.remove(beanName);
this.frozenBeanDefinitionNames = null;
}
resetBeanDefinition(beanName);
}
这段代码主要就是把定义的bean放到beanDefinitionMap里去。beanDefinitionMap维护的就是bean的定义,当需要获取的时候就从里面拿到对应的BeanDefinition,根据BeanDefinition生成一个对象。
以上就是ImportBeanDefinitionRegistrar手动控制BeanDefinition创建注册详解的详细内容,更多关于BeanDefinition创建注册的资料请关注编程网其它相关文章!