spring容器注册Bean的方式
通常有如下几种方式:
- ComponentScan + 注解(@Component, @Service, @Controller): 通常是自己写的类。
- @Bean注解:通常用于导入第三方包中的组件。
- @Import注解:快速向Spring容器中导入组件
@Import源码
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Indicates one or more <em>component classes</em> to import — typically
* {@link Configuration @Configuration} classes.
*
* <p>Provides functionality equivalent to the {@code <import/>} element in Spring XML.
* Allows for importing {@code @Configuration} classes, {@link ImportSelector} and
* {@link ImportBeanDefinitionRegistrar} implementations, as well as regular component
* classes (as of 4.2; analogous to {@link AnnotationConfigApplicationContext#register}).
*
* <p>{@code @Bean} definitions declared in imported {@code @Configuration} classes should be
* accessed by using {@link org.springframework.beans.factory.annotation.Autowired @Autowired}
* injection. Either the bean itself can be autowired, or the configuration class instance
* declaring the bean can be autowired. The latter approach allows for explicit, IDE-friendly
* navigation between {@code @Configuration} class methods.
*
* <p>May be declared at the class level or as a meta-annotation.
*
* <p>If XML or other non-{@code @Configuration} bean definition resources need to be
* imported, use the {@link ImportResource @ImportResource} annotation instead.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.0
* @see Configuration
* @see ImportSelector
* @see ImportBeanDefinitionRegistrar
* @see ImportResource
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
/**
* {@link Configuration @Configuration}, {@link ImportSelector},
* {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
*/
Class<?>[] value();
}
从注释中可得到以下信息:
- 可导入四种Class: Configuration, ImportSelector, ImportBeanDefinitionRegistrar以及普通的JavaBean。
- 在spring4.2后类似于AnnotationConfigApplicationContext#register功能
- 该注解可以被定义在类级别或作为一个元注解
- 如果是XML格式或非@Configuration格式的bean Definition,需要使用@ImportResource注解替代
直接注入Java Bean
此时的Javabean是一个普通类,不需要在@ComponentScan扫描路径,也不需要被加注了@Service, @Component等注解。见以下示例:
新建一个POJO
package win.elegentjs.spring.ioc.imports.javabeans;
import lombok.Data;
@Data
public class Org {
private String name;
private String desc;
}
一个非常普通的JavaBean, 使用@Import导入
package win.elegentjs.spring.ioc.imports.javabeans;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import(Org.class)
public class OrgConfig {
}
写测试类进行测试,看Org是否注册到spring容器中
package win.elegentjs.spring.ioc.imports.javabeans;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import win.elegentjs.spring.util.ArraysUtil;
@Slf4j
public class OrgImportSample {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(OrgConfig.class);
String[] beanDefinitions = context.getBeanDefinitionNames();
log.info(ArraysUtil.toString(beanDefinitions));
}
}
// result
2021-05-24 19:40:07.124 [main] INFO w.e.spring.ioc.imports.javabeans.OrgImportSample-
[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,
orgConfig,
win.elegentjs.spring.ioc.imports.javabeans.Org,
]
可以看出Org类被注册到了spring容器中,但有一点不同,通常采用@Configuration, @Component等注册的bean,最后的bean name默认是类名首字母小写的形式。而采用@Import注册的普通bean,bean name是类的完全限定名。
注入ImportSelector
注意:ImportSelector接口是spring中导入外部配置的核心。在SpringBoot的自动化配置和@EnableXXX(功能性注解)都有它的存在。
ImportSelector接口源码
package org.springframework.context.annotation;
import org.springframework.core.type.AnnotationMetadata;
/**
* Interface to be implemented by types that determine which @{@link Configuration}
* class(es) should be imported based on a given selection criteria, usually one or
* more annotation attributes.
*
* <p>An {@link ImportSelector} may implement any of the following
* {@link org.springframework.beans.factory.Aware Aware} interfaces,
* and their respective methods will be called prior to {@link #selectImports}:
* <ul>
* <li>{@link org.springframework.context.EnvironmentAware EnvironmentAware}</li>
* <li>{@link org.springframework.beans.factory.BeanFactoryAware BeanFactoryAware}</li>
* <li>{@link org.springframework.beans.factory.BeanClassLoaderAware BeanClassLoaderAware}</li>
* <li>{@link org.springframework.context.ResourceLoaderAware ResourceLoaderAware}</li>
* </ul>
*
* <p>Alternatively, the class may provide a single constructor with one or more of
* the following supported parameter types:
* <ul>
* <li>{@link org.springframework.core.env.Environment Environment}</li>
* <li>{@link org.springframework.beans.factory.BeanFactory BeanFactory}</li>
* <li>{@link java.lang.ClassLoader ClassLoader}</li>
* <li>{@link org.springframework.core.io.ResourceLoader ResourceLoader}</li>
* </ul>
*
* <p>{@code ImportSelector} implementations are usually processed in the same way
* as regular {@code @Import} annotations, however, it is also possible to defer
* selection of imports until all {@code @Configuration} classes have been processed
* (see {@link DeferredImportSelector} for details).
*
* @author Chris Beams
* @since 3.1
* @see DeferredImportSelector
* @see Import
* @see ImportBeanDefinitionRegistrar
* @see Configuration
*/
public interface ImportSelector {
/**
* Select and return the names of which class(es) should be imported based on
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
*/
String[] selectImports(AnnotationMetadata importingClassMetadata);
}
从文档的注释中可得到以下信息:
-
它的主要作用是收集需要导入的配置类,selectImports方法的返回值就是我们向Spring容器中导入的类的全类名。
-
如果ImportSelector接口的实现类同时实现了各种Aware接口,如:EnvironmentAware, BeanFactoryAware, BeanClassLoaderAware, ResourceLoaderAware。那么在调用selectImports之前上面接口的对应方法会先得到执行。这句话理解起来其实不难:上面各种XXXAware是spring容器的实例化机制,容器检测到当前类实现了各种XXXAware会优先调用接口实现方法注入对应对象。
-
如果有需要控制加载时机,即需要在所有的@Configuration处理完成后再处理@Import导入,可实现DeferredImportSelector接口
分析AnnotationMetadata
/**
* Select and return the names of which class(es) should be imported based on
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
*/
String[] selectImports(AnnotationMetadata importingClassMetadata);
AnnotationMetadata是selectImports方法的参数,该参数能获取到当前标注@Import注解的类的所有注解信息。
ImportSelector接口实例
自定义ImportSelector
package win.elegentjs.spring.ioc.imports.selector;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import win.elegentjs.spring.ioc.imports.javabeans.Org;
/**
* 自定义的ImportSelector,实现导入Org Bean,
* bean name: win.elegentjs.spring.ioc.imports.javabeans.Org
*/
public class MyImportSelector implements ImportSelector, BeanFactoryAware {
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {
Org.class.getName()
};
}
}
再做Import导入
package win.elegentjs.spring.ioc.imports.selector;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import(MyImportSelector.class)
public class MyImportSelectorConfig {}
最后写测试类测试
package win.elegentjs.spring.ioc.imports.selector;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import win.elegentjs.spring.ioc.imports.javabeans.OrgConfig;
import win.elegentjs.spring.util.ArraysUtil;
@Slf4j
public class MyImportSelectorSample {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(MyImportSelectorConfig.class);
String[] beanDefinitions = context.getBeanDefinitionNames();
log.info(ArraysUtil.toString(beanDefinitions));
}
}
// result
2021-05-24 20:24:16.255 [main] INFO w.e.s.ioc.imports.selector.MyImportSelectorSample-
[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,
myImportSelectorConfig,
win.elegentjs.spring.ioc.imports.javabeans.Org,
]
分析@EnableTransactionManagement注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
上面为@EnableTransactionManagement的源码,只保留了注解的定义部分。其他细节等后面讲到事务时再详细讲解。
从上面源码可以看出这是一个复合注解,可以加载到类上,该注解上标注了@Import注解,当@EnableTransactionManagement加注到类上时,间接的@Import也会被注解。
下面分析下TransactionManagementConfigurationSelector类,源码如下:
package org.springframework.transaction.annotation;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.AdviceModeImportSelector;
import org.springframework.context.annotation.AutoProxyRegistrar;
import org.springframework.transaction.config.TransactionManagementConfigUtils;
import org.springframework.util.ClassUtils;
/**
* Selects which implementation of {@link AbstractTransactionManagementConfiguration}
* should be used based on the value of {@link EnableTransactionManagement#mode} on the
* importing {@code @Configuration} class.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
* @see EnableTransactionManagement
* @see ProxyTransactionManagementConfiguration
* @see TransactionManagementConfigUtils#TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME
* @see TransactionManagementConfigUtils#JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME
*/
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
/**
* Returns {@link ProxyTransactionManagementConfiguration} or
* {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY}
* and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()},
* respectively.
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
该类的继承体系如下:
在父类AdviceModeImportSelector中实现了ImportSelector接口,我们看下它的实现:
/**
* This implementation resolves the type of annotation from generic metadata and
* validates that (a) the annotation is in fact present on the importing
* {@code @Configuration} class and (b) that the given annotation has an
* {@linkplain #getAdviceModeAttributeName() advice mode attribute} of type
* {@link AdviceMode}.
* <p>The {@link #selectImports(AdviceMode)} method is then invoked, allowing the
* concrete implementation to choose imports in a safe and convenient fashion.
* @throws IllegalArgumentException if expected annotation {@code A} is not present
* on the importing {@code @Configuration} class or if {@link #selectImports(AdviceMode)}
* returns {@code null}
*/
@Override
public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (attributes == null) {
throw new IllegalArgumentException(String.format(
"@%s is not present on importing class '%s' as expected",
annType.getSimpleName(), importingClassMetadata.getClassName()));
}
AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
String[] imports = selectImports(adviceMode);
if (imports == null) {
throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
}
return imports;
}
它实现的核心是找出配置的AdviceMode,然后交由子类的selectImports方法实现,返回的Class类数组就是要加载的Bean。
以下是TransactionManagementConfigurationSelector部分源码:
/**
* Returns {@link ProxyTransactionManagementConfiguration} or
* {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY}
* and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()},
* respectively.
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
自己实现一个@EnableXX注解
定义一个Enable注解
package win.elegentjs.spring.ioc.imports.enables;
import org.springframework.context.annotation.Import;
import win.elegentjs.spring.ioc.imports.selector.MyImportSelector;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.TYPE)
@Import(MyImportSelector.class)
public @interface EnableOrg {
}
定义一个Config引入该注解
package win.elegentjs.spring.ioc.imports.enables;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import win.elegentjs.spring.ioc.imports.javabeans.Org;
@Configuration
@EnableOrg
public class EnableOrgConfig {
}
测试,看执行效果
package win.elegentjs.spring.ioc.imports.enables;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import win.elegentjs.spring.ioc.imports.selector.MyImportSelectorConfig;
import win.elegentjs.spring.util.ArraysUtil;
@Slf4j
public class MyEnableOrgSample {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(EnableOrgConfig.class);
String[] beanDefinitions = context.getBeanDefinitionNames();
log.info(ArraysUtil.toString(beanDefinitions));
}
}
// result:
2021-05-25 11:08:14.649 [main] INFO w.e.spring.ioc.imports.enables.MyEnableOrgSample-
[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,
enableOrgConfig,
win.elegentjs.spring.ioc.imports.javabeans.Org,
]
可以看出同样可以加载自定义的Bean。
ImportSelector在哪里被Spring容器解析
上面演示了自定义的ImportSelector可以被容器识别,那容器如何解析并加载Bean的,这里给个大概的实现,具体的过程后面学习spring容器加载原理时会详细介绍。
ConfigurationClassParser的processImports方法
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) { //对ImportSelector的处理
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) { //如果为延迟导入处理则加入集合当中
this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
}
else { //根据ImportSelector方法的返回值来进行递归操作
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else { // 如果当前的类既不是ImportSelector也不是ImportBeanDefinitionRegistar就进行@Configuration的解析处理
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
使用ImportBeanDefinitionRegistrar注册Bean
这是使用@Import注入的第三种方式,先看源码:
package org.springframework.context.annotation;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.type.AnnotationMetadata;
/**
* Interface to be implemented by types that register additional bean definitions when
* processing @{@link Configuration} classes. Useful when operating at the bean definition
* level (as opposed to {@code @Bean} method/instance level) is desired or necessary.
*
* <p>Along with {@code @Configuration} and {@link ImportSelector}, classes of this type
* may be provided to the @{@link Import} annotation (or may also be returned from an
* {@code ImportSelector}).
*
* <p>An {@link ImportBeanDefinitionRegistrar} may implement any of the following
* {@link org.springframework.beans.factory.Aware Aware} interfaces, and their respective
* methods will be called prior to {@link #registerBeanDefinitions}:
* <ul>
* <li>{@link org.springframework.context.EnvironmentAware EnvironmentAware}</li>
* <li>{@link org.springframework.beans.factory.BeanFactoryAware BeanFactoryAware}
* <li>{@link org.springframework.beans.factory.BeanClassLoaderAware BeanClassLoaderAware}
* <li>{@link org.springframework.context.ResourceLoaderAware ResourceLoaderAware}
* </ul>
*
* <p>Alternatively, the class may provide a single constructor with one or more of
* the following supported parameter types:
* <ul>
* <li>{@link org.springframework.core.env.Environment Environment}</li>
* <li>{@link org.springframework.beans.factory.BeanFactory BeanFactory}</li>
* <li>{@link java.lang.ClassLoader ClassLoader}</li>
* <li>{@link org.springframework.core.io.ResourceLoader ResourceLoader}</li>
* </ul>
*
* <p>See implementations and associated unit tests for usage examples.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
* @see Import
* @see ImportSelector
* @see Configuration
*/
public interface ImportBeanDefinitionRegistrar {
/**
* Register bean definitions as necessary based on the given annotation metadata of
* the importing {@code @Configuration} class.
* <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
* registered here, due to lifecycle constraints related to {@code @Configuration}
* class processing.
* <p>The default implementation delegates to
* {@link #registerBeanDefinitions(AnnotationMetadata, BeanDefinitionRegistry)}.
* @param importingClassMetadata annotation metadata of the importing class
* @param registry current bean definition registry
* @param importBeanNameGenerator the bean name generator strategy for imported beans:
* {@link ConfigurationClassPostProcessor#IMPORT_BEAN_NAME_GENERATOR} by default, or a
* user-provided one if {@link ConfigurationClassPostProcessor#setBeanNameGenerator}
* has been set. In the latter case, the passed-in strategy will be the same used for
* component scanning in the containing application context (otherwise, the default
* component-scan naming strategy is {@link AnnotationBeanNameGenerator#INSTANCE}).
* @since 5.2
* @see ConfigurationClassPostProcessor#IMPORT_BEAN_NAME_GENERATOR
* @see ConfigurationClassPostProcessor#setBeanNameGenerator
*/
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
BeanNameGenerator importBeanNameGenerator) {
registerBeanDefinitions(importingClassMetadata, registry);
}
/**
* Register bean definitions as necessary based on the given annotation metadata of
* the importing {@code @Configuration} class.
* <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
* registered here, due to lifecycle constraints related to {@code @Configuration}
* class processing.
* <p>The default implementation is empty.
* @param importingClassMetadata annotation metadata of the importing class
* @param registry current bean definition registry
*/
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}
}
从源码看出ImportBeanDefinitionRegistrar是一个接口,通过registerBeanDefinitions()方法,我们可以向Spring容器注册Bean实例。Spring官方在注册Bean时,大部分是使用registerBeanDefinitions接口。
所有实现了该接口的类会被ConfigurationClassPostProcessor处理,该类实现了BeanFactoryPostProcessor接口,所以ImportBeanDefinitionRegistrar中注册的Bean是优先于依赖其的bean初始化的,也能被aop, validator等机制处理。
使用方式
需要搭配@Configuration, @Import使用。 以下为使用示例:
自定义ImportBeanDefinitionRegistrar,注册beanDefinition, bean name是org。
package win.elegentjs.spring.ioc.imports.registrar;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import win.elegentjs.spring.ioc.imports.javabeans.Org;
/**
* 自定义的ImportBeanDefinitionRegistrar
*/
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* AnnotationMetadata: 当前类的注解信息
* BeanDefinitionRegistry:BeanDefinition注册类
* 通过调用BeanDefinitionRegistry接口的registerBeanDefinition()方法,可以将所有需要添加到容器中的bean注入到容器中。
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){
BeanDefinition beanDefinition = new RootBeanDefinition(Org.class);
registry.registerBeanDefinition("org", beanDefinition);
}
}
使用@Import导入
package win.elegentjs.spring.ioc.imports.registrar;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class RegistrarOrgConfig {
}
写测试类
package win.elegentjs.spring.ioc.imports.registrar;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import win.elegentjs.spring.util.ArraysUtil;
@Slf4j
public class RegistrarOrgSample {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(RegistrarOrgConfig.class);
String[] beanDefinitions = context.getBeanDefinitionNames();
log.info(ArraysUtil.toString(beanDefinitions));
}
}
//result:
2021-05-25 11:39:21.584 [main] INFO w.e.s.ioc.imports.registrar.RegistrarOrgSample-
[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,
registrarOrgConfig,
org,
]
可以看出自定义的org bean已被注册。
小结
本章讲解了使用@Import注册bean的三种方式:
- 普通java bean
- ImportSelector: 自定义的@EnableXXX广泛使用的方式
- ImportBeanDefinitionRegistrar:很多spring 自带的bean采用的此种方式
Spring容器如何加载各种类型的bean后面会重点介绍,敬请关注。