Различные варианты использования @Import в Spring и интерфейса ImportAware

Spring

@Импортировать аннотацию

@ImportАннотации предоставляются и в XML<import/>Эквивалентная функциональность элемента, которая реализует один или несколько импортированных классов конфигурации.@ImportТо есть его можно использовать в классе или в качестве мета-аннотации.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

	/**
	 * {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
	 * or regular component classes to import.
	 */
	Class<?>[] value();

}

В аннотации только одинvalue();. Поддержка импорта@ConfigurationАннотированный класс конфигурации, реализующийImportSelectorкласс, реализация интерфейсаImportBeanDefinitionRegistrarкласс интерфейса и обычный@componentДобрый.

Использовать как мета-аннотацию

@ImportМожет использоваться как мета-аннотация, которую можно найти в@ImportНаследование инкапсулирует слой. Насколько я понимаю, это не будет раскрывать детали моей внутренней реализации внешнему миру (используя сторону).

Например: напр.@EnableAspectJAutoProxyаннотация.

@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

@EnableAspectJAutoProxyдолжна быть@ImportЭта мета-аннотация отмечает, что мы (программисты), используя@EnableAspectJAutoProxyЧтобы открыть AspectJAutoProxy и нижний слой Spring через@ImportПредставляем соответствующую конфигурацию для достижения класса.

Импортировать класс, реализующий интерфейс ImportSelector.

Давайте взглянемImportSelectorинтерфейс, который имеет только один метод:

public interface ImportSelector {
	String[] selectImports(AnnotationMetadata importingClassMetadata);
}

ImportSelector, селектор ввода. Этот интерфейс используется для выбора классов конфигурации для импорта в зависимости от заданных условий.

Например: напр.@EnableTransactionManagementаннотация.

@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

существует@EnableTransactionManagementиспользуется в аннотации@Import(TransactionManagementConfigurationSelector.class)аннотация, котораяTransactionManagementConfigurationSelectorкласс реализованImportSelectorинтерфейс.

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY:
				return new String[] {AutoProxyRegistrar.class.getName(),
						ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {
						TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
			default:
				return null;
		}
	}
}

Внутренняя логика реализации метода также очень проста, т.е.AdviceModeИмпортируйте различные классы конфигурации для реализации управления транзакциями.

Импортировать класс, реализующий интерфейс ImportBeanDefinitionRegistrar.

ImportBeanDefinitionRegistrarВ интерфейсе тоже только один метод:

public interface ImportBeanDefinitionRegistrar {
	void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}

Этот интерфейс позволяет нам регистрировать дополнительные аннотации по запросу на основе заданных метаданных аннотаций.BeanDefinition.

Например: напр.@EnableAspectJAutoProxyаннотация.

@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

@EnableAspectJAutoProxyАннотация представляетAspectJAutoProxyRegistrar.classкласс, этот класс реализованImportBeanDefinitionRegistrarинтерфейс.

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	@Override
	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);
			}
		}
	}
}

registerBeanDefinitionsпозвонил вAopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);метод, этот метод проходит вBeanDefinitionRegistry registryзарегистрирован вBeanDefinition. зарегистрированBeanDefinitionПосле этого Spring создаст экземпляр Bean, чтобы получить роль AspectJAutoProxy.

Импортировать класс @Configuration

этот раз@ImportНаиболее распространенным является способ использования. Мы можем разделить класс конфигурации, а затем импортировать соответствующую конфигурацию по мере необходимости в программу.

Например: напр.@EnableRetryаннотация. Используйте эту аннотацию, чтобы включить функцию повтора.

@EnableAspectJAutoProxy(proxyTargetClass = false)
@Import(RetryConfiguration.class)
public @interface EnableRetry {

Он импортируется внутрьRetryConfigurationЭтот класс конфигурации.

Интерфейс ImportAware

ImportAwareИнтерфейс требуется и@ImportИспользуется вместе. существует@ImportПри использовании в качестве мета-аннотации передать@ImportЕсли импортированный класс конфигурации реализованImportAwareИнтерфейс может получить конфигурацию данных, импортированную в интерфейс класса конфигурации. Это немного запутанно, давайте перейдем непосредственно к коду.

Например:@EnableAsyncаннотация.

@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
//AsyncConfigurationSelector源码
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;
		}
	}
}

Использовать по умолчаниюAdviceModeзаPROXY, импортныйProxyAsyncConfigurationДобрый.

@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {

	@Bean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public AsyncAnnotationBeanPostProcessor asyncAdvisor() {
		Assert.notNull(this.enableAsync, "@EnableAsync annotation metadata was not injected");
		AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
		Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
		if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) {
			bpp.setAsyncAnnotationType(customAsyncAnnotation);
		}
		if (this.executor != null) {
			bpp.setExecutor(this.executor);
		}
		if (this.exceptionHandler != null) {
			bpp.setExceptionHandler(this.exceptionHandler);
		}
		bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
		bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
		return bpp;
	}
}

существуетProxyAsyncConfigurationизasyncAdvisorметод получения@EnableAsyncНекоторые настройки по значению, например:this.enableAsync.getBoolean("proxyTargetClass"),this.enableAsync.<Integer>getNumber("order").

this.enableAsyncэто его родительский классAbstractAsyncConfigurationхарактеристики.AbstractAsyncConfigurationДостигнутоImportAwareинтерфейс, так что вы можете получить@EnableAsyncинформация о.

// AbstractAsyncConfiguration#setImportMetadata 源码
public void setImportMetadata(AnnotationMetadata importMetadata) {
	this.enableAsync = AnnotationAttributes.fromMap(
			importMetadata.getAnnotationAttributes(EnableAsync.class.getName(), false));
	if (this.enableAsync == null) {
		throw new IllegalArgumentException(
				"@EnableAsync is not present on importing class " + importMetadata.getClassName());
	}
}

Может быть, этот пример немного сложен, есть немного более простой пример:EnableRedisHttpSession. В связи с этим читатели могут просмотреть исходный код для отладки и изучения.


Спасибо, что обратите внимание на общественное число WeChat:

Corder小黑