Get Spring:Enable **アノテーションはどのように実装されていますか?

ここに画像の説明を挿入

前書き

Springを使用する場合、モジュールを開く機能を実現するためにEnableアノテーションが必要なだけです。これは非常に便利ですが、この機能はどのように実現されますか?

一般的に使用されるEnableアノテーションは次のとおりです

注釈 効果
@EnableAspectJAutoProxy AspectJ自動プロキシをオンにする
@EnableAsync 非同期メソッドのサポートを有効にする
@EnableScheduling タイマータスクのサポートをオンにする
@EnableWebMVC WebMVCサポートを有効にする
@EnableTransactionManagement 注釈付きトランザクションサポートをオンにする
@EnableCaching 注釈キャッシュのサポートを有効にする
@EnableAutoConfiguration 自動構成をオンにする

実際、Enableアノテーションの最下層は@Importアノテーションによって実現され、@ Importアノテーションは必要なBeanをSpringコンテナーに注入します。

次のように、@ Importアノテーションを使用してBeanを注入する方法は3つあります。

  1. 構成クラスに基づく
  2. ImportSelectorインターフェースに基づく
  3. 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

おすすめ

転載: blog.csdn.net/zzti_erlie/article/details/114917271