Spring@Import註解的三種用法
阿新 • • 發佈:2021-02-06
目錄
3.引入ImportBeanDefinitionRegistrar的實現
4.1如果引入的類是ImportBeanDefinitionRegistrar.class的實現類
4.2如果引入的類是ImportSelector.class的實現類
4.4.2ImportBeanDefinitionRegistrar註冊bean
服務介面
public interface IUserService { void sayHello(); }
服務實現
public class UserServiceImpl implements IUserService {
@Override
public void sayHello() {
System.out.println("xxx");
}
}
1.直接引入
@Import({UserServiceImpl.class}) @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
2.引入ImportSelector的實現
public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { return new String[]{UserServiceImpl.class.getName()}; } } 引入selector @Import(MyImportSelector.class) @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
3.引入ImportBeanDefinitionRegistrar的實現
@Import(MyImportBeanDefinitionRegistrar.class)
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
註冊引入類的beanDefinition
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
registry.registerBeanDefinition("userService", new RootBeanDefinition(UserServiceImpl.class));
}
}
4.Import原始碼解析
以springBoot的啟動容器 AnnotationConfigApplicationContext為例,容器建立的時候,會建立bean定義閱讀器 AnnotatedBeanDefinitionReader,會往 beanFactory的 beanDefinitionMap中註冊 ConfigurationClassPostProcessor的beanDefinition【Spring IOC載入過程】。他是 BeanDefinitionRegistryPostProcessor的實現類,所以他在容器呼叫 invokeBeanFactoryPostProcessors方法的時候會被提前例項化出來,並呼叫。 入口public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry);
}
解析配置類上所有import匯入的類getImports(sourceClass),找到候選類
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
throws IOException {
// 使用set跳過迴圈import
if (visited.add(sourceClass)) {
for (SourceClass annotation : sourceClass.getAnnotations()) {
String annName = annotation.getMetadata().getClassName();
if (!annName.equals(Import.class.getName())) {
// 遞迴解析非import註解,處理深層次的import
collectImports(annotation, imports, visited);
}
}
// 解析import註解的value屬性
imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
}
}
解析所有import直接引入的類
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
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.class的實現類
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
// 根據類名載入class
Class<?> candidateClass = candidate.loadClass();
// 例項化selector
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
Predicate<String> selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
exclusionFilter = exclusionFilter.or(selectorFilter);
}
// 延遲引入
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
// 呼叫自定義的selectImports方法,傳入了@Import註解所在類的元資料,拿到匯入的bean的類名
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
// 遞迴呼叫,如果引入的類也是importSelector或者ImportBeanDefinitionRegistrar也要解析
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
// 如果引入的類是ImportBeanDefinitionRegistrar.class的實現類
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
// 載入實現類class
Class<?> candidateClass = candidate.loadClass();
// 例項化實現類
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
// 放進map裡面存放起來importBeanDefinitionRegistrars等待呼叫
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// 直接引入的類 存入importStack
// 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), exclusionFilter);
}
}
}
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();
}
}
}
4.1如果引入的類是ImportBeanDefinitionRegistrar.class的實現類
把它載入並例項化出來,然後把它暫存到importBeanDefinitionRegistrars裡面,等待後續的解析
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 =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
4.2如果引入的類是ImportSelector.class的實現類
載入並例項化
else {
// 呼叫實現類的selectImports方法,拿到需要引入的類名
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
// 遞迴處理引入的類,最終轉化為引入普通的類,從4.3出口出去
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
4.3如果引入的類是其他的類
繫結引入的類和當前配置類,建立ConfigurationClass,等待後續解析
else {
// 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), exclusionFilter);
}
候選類(引入的類)作為配置類來進行處理,等待後面的解析。candidate.asConfigClass(configClass),
在ConfigurationClass中會把當前類和引入類通過importedBy進行繫結,表示這是一個被引入的類。 後續在載入beanDefiniton的時候,通過configClass.isImported來判斷,如果是被引入的類,那麼就註冊到beanDefinitionMap中public ConfigurationClass(MetadataReader metadataReader, @Nullable ConfigurationClass importedBy) {
this.metadata = metadataReader.getAnnotationMetadata();
this.resource = metadataReader.getResource();
this.importedBy.add(importedBy);
}
4.4從配置類載入beanDefinition
把bean定義寫入到beanDefinitionMap中
this.reader.loadBeanDefinitions(configClasses);private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
// 普通引入的類從這裡註冊
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
// 處理@Bean工廠方法引入
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// 處理引入其他的配置檔案
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 解析前面的importBeanDefinitionRegistrars,註冊需要引入的beanDefinition
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
4.4.1普通引入類註冊
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
AnnotationMetadata metadata = configClass.getMetadata();
AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
configBeanDef.setScope(scopeMetadata.getScopeName());
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
configClass.setBeanName(configBeanName);
if (logger.isDebugEnabled()) {
logger.debug("Registered bean definition for imported class '" + configBeanName + "'");
}
}
4.4.2ImportBeanDefinitionRegistrar註冊bean
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
for (Map.Entry<ImportBeanDefinitionRegistrar, AnnotationMetadata> entry : registrars.entrySet()) {
entry.getKey().registerBeanDefinitions(entry.getValue(), this.registry);
}
}