前書き
Springを使用する場合、モジュールを開く機能を実現するためにEnableアノテーションが必要なだけです。これは非常に便利ですが、この機能はどのように実現されますか?
一般的に使用されるEnableアノテーションは次のとおりです
注釈 | 効果 |
---|---|
@EnableAspectJAutoProxy | AspectJ自動プロキシをオンにする |
@EnableAsync | 非同期メソッドのサポートを有効にする |
@EnableScheduling | タイマータスクのサポートをオンにする |
@EnableWebMVC | WebMVCサポートを有効にする |
@EnableTransactionManagement | 注釈付きトランザクションサポートをオンにする |
@EnableCaching | 注釈キャッシュのサポートを有効にする |
@EnableAutoConfiguration | 自動構成をオンにする |
実際、Enableアノテーションの最下層は@Importアノテーションによって実現され、@ Importアノテーションは必要なBeanをSpringコンテナーに注入します。
次のように、@ Importアノテーションを使用してBeanを注入する方法は3つあります。
- 構成クラスに基づく
- ImportSelectorインターフェースに基づく
- ImportBeanDefinitionRegistrarインターフェースに基づく
波のデモ
@EnableHelloWorld
public class EnableModuleDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(EnableModuleDemo.class);
context.refresh();
String helloWorld = context.getBean("helloWorld", String.class);
// hello world
System.out.println(helloWorld);
context.close();
}
}
コンテナーを開始した後、コンテナーからhelloWorldという名前のBeanを取得できることがわかります。インジェクションプロセスは@EnableHelloWorldアノテーションにあります。
構成クラスに基づく
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(HelloWorldConfiguration.class)
public @interface EnableHelloWorld {
}
@Configuration
public class HelloWorldConfiguration {
@Bean
public String helloWorld() {
return "hello world";
}
}
ImportSelectorインターフェースに基づく
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(HelloWorldImportSelector.class)
public @interface EnableHelloWorld {
}
public class HelloWorldImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{
"com.javashitang.HelloWorldConfiguration"};
}
}
ImportBeanDefinitionRegistrarインターフェースに基づく
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(HelloWorldImportBeanDefinitionRegistrar.class)
public @interface EnableHelloWorld {
}
public class HelloWorldImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(HelloWorldConfiguration.class);
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
}
}
豆を注入するだけではありませんか?なぜそんなに多くの方法をするのですか?一言で言えば、オンデマンドで拡張します
以前のEnableアノテーションがどのように実装されているか見てみましょう。
構成クラスに基づく
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(SchedulingConfiguration.class)
@Documented
public @interface EnableScheduling {
}
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class SchedulingConfiguration {
@Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
return new ScheduledAnnotationBeanPostProcessor();
}
}
構成クラスを介して新しいBeanPostProcessorを挿入し、BeanPostProcessorで@Scheduledアノテーションのサポートを追加します
ImportSelectorインターフェースに基づく
@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 Ordered.LOWEST_PRECEDENCE;
}
public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {
private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";
@Override
@Nullable
public String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {
ProxyAsyncConfiguration.class.getName()};
case ASPECTJ:
return new String[] {
ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
ユーザーが構成したさまざまなコードメソッドに従って、さまざまな構成クラスを選択し、ロードするクラスの名前を返します
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
// 要排除的bean的类型
Class<?>[] exclude() default {
};
// 要排除的bean的名字
String[] excludeName() default {
};
}
ImportBeanDefinitionRegistrarインターフェースに基づく
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 直接往registry中注册BeanDefinition
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);
}
}
}
}
BeanDefinitionRegistryを直接提供し、BeanDefinitionを自分で注入します。これは低レベルの実装に適しています
リファレンスブログ
[1] https://blog.csdn.net/andy_zhang2007/article/details/96612243
[2] https://blog.csdn.net/qq_26525215/article/details/53524844?utm_medium=distribute.pc_relevant.none-task -blog-baidujs_title-1&spm =
1001.2101.3001.4242ImportAware接口的作用
[3] https://javazhiyin.blog.csdn.net/article/details/101186808