O tutorial básico anterior do springboot 2.x: @Async abre tarefas assíncronas. Usamos a anotação @EnableAsync para habilitar a execução assíncrona.
Existem muitas anotações @ Enable * na estrutura SpringBoot, como: @EnableAspectJAutoProxy, @EnableCaching, @EnableAutoConfiguration, @ EnableSwagger2 Este capítulo explica o princípio por trás disso.
Navegação neste artigo
Várias anotações @ Enable * típicas
As três anotações @ EnableSwagger2, @EnableAsync e @EnableAspectJAutoProxy estão postadas abaixo. Não é difícil ver que todas essas três anotações usam a anotação @Import.
A anotação @Import suporta a importação de classes Java comuns e sua declaração como bean.
A anotação @Enable real é injetar Bean no contêiner springboot ioc por meio da capacidade da anotação @Import para fazer certas configurações entrarem em vigor.
@EnableScheduling
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({SchedulingConfiguration.class})
@Documented
public @interface EnableScheduling {
}
@EnableAsync
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AsyncConfigurationSelector.class})
public @interface EnableAsync {
Class<? extends Annotation> annotation() default Annotation.class;
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default 2147483647;
}
@EnableAspectJAutoProxy
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
@Import annotation using
Permitir classes anotadas com @Configuration
O @Import anotado por @EnableScheduling importa a classe SchedulingConfiguration.Vamos ver a implementação desta classe.
Podemos ver que esta classe usa anotações @Configuration e @Bean.
A anotação @Import permite que as classes anotadas com @Configuration sejam injetadas no contêiner.
@Configuration
@Role(2)
public class SchedulingConfiguration {
public SchedulingConfiguration() {
}
@Bean(
name = {"org.springframework.context.annotation.internalScheduledAnnotationProcessor"}
)
@Role(2)
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
return new ScheduledAnnotationBeanPostProcessor();
}
}
Permite o uso de classes que implementam a interface ImportSelectorj
@EnableAsync anotado @Import importa a classe AsyncConfigurationSelector, vamos dar uma olhada na implementação dessa classe.
A classe AsyncConfigurationSelector implementa a interface ImportSelector e substitui o método selectImports.
A anotação @Import aqui injetará a classe de caminho completa retornada por selectImports no contêiner.
public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {
private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME = "org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";
public AsyncConfigurationSelector() {
}
@Nullable
public String[] selectImports(AdviceMode adviceMode) {
switch(adviceMode) {
case PROXY:
return new String[]{ProxyAsyncConfiguration.class.getName()};
case ASPECTJ:
return new String[]{"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration"};
default:
return null;
}
}
}
Permitido é uma classe que implementa a interface ImportBeanDefinitionRegistrar
@EnableAspectJAutoProxy anotado @Import importa a classe AspectJAutoProxyRegistrar, vamos dar uma olhada na implementação dessa classe.
AspectJAutoProxyRegistrar implementa a interface ImportBeanDefinitionRegistrar. A função de ImportBeanDefinitionRegistrar é adicionar Beans automaticamente às classes de configuração existentes em tempo de execução e analisar e gerar beans quando o contêiner Spring é iniciado, reescrevendo o método registerBeanDefinitions.
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
AspectJAutoProxyRegistrar() {
}
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
@Import annotation Análise de código-fonte do fluxo de processamento do SpringBoot
- O método de atualização de AbstractApplicationContext é chamado quando o contêiner Spring IOC é inicializado
- Vários BeanFactoryPostProcessor serão chamados na atualização. O método processConfigBeanDefinitions de ConfigurationClassPostProcessor lida com anotações como @Configuration e @Import.
- ConfigurationClassPostProcessor é realmente processado internamente por ConfigurationClassParser.
- Vamos nos concentrar no tratamento @Import da classe ConfigurationClassParser.
Análise do código-fonte da classe ConfigurationClassParser
O código de processamento principal está no método processImports de ConfigurationClassParser, que implementa o processamento das três maneiras de usar @Import neste artigo.
private void processImports(ConfigurationClass configClass, ConfigurationClassParser.SourceClass currentSourceClass, Collection<ConfigurationClassParser.SourceClass> importCandidates, Predicate<String> exclusionFilter, boolean checkForCircularImports) {
//....省略部分代码
ConfigurationClassParser.SourceClass candidate = (ConfigurationClassParser.SourceClass)var6.next();
Class candidateClass;
if (candidate.isAssignable(ImportSelector.class)) {
//对于处理ImportSelector注解处理
candidateClass = candidate.loadClass();
ImportSelector selector = (ImportSelector)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 {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<ConfigurationClassParser.SourceClass> importSourceClasses = this.asSourceClasses(importClassNames, exclusionFilter);
this.processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
} else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
//对于ImportBeanDefinitionRegistrar接口处理
candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar = (ImportBeanDefinitionRegistrar)ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
} else {
this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
//对于@Configuration注解处理
this.processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
//....省略部分代码
}
Mil milhas começam com um único passo. Este é o décimo primeiro artigo da série de tutoriais SpringBoot. Todos os códigos-fonte do projeto podem ser baixados em meu GitHub .