@Enable***注解的原理与使用

摘要:我们在开发中,会经常用到@Enable***开头的这种注解,来自动导入一些框架配置的默认的bean,进入注解源码,会发现这些注解类上都会有一个@Import(****.class)注解,这些注解是怎么实现的呢?

Import导入,又分为三种方式,分别为:

1.直接导入配置类

2.根据条件选择配置类

3.动态注册Bean

下面,通过示例,进入源码,分析一下这三种导入方式:


1.直接导入配置类


以@EnableScheduling为例,看源码:

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

}
发现有@Import导入了一个SchedulingConfiguration类,我们追一下源码:

package org.springframework.scheduling.annotation;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.scheduling.config.TaskManagementConfigUtils;

/**
 * {@code @Configuration} class that registers a {@link ScheduledAnnotationBeanPostProcessor}
 * bean capable of processing Spring's @{@link Scheduled} annotation.
 *
 * 

This configuration class is automatically imported when using the * {@link EnableScheduling @EnableScheduling} annotation. See * {@code @EnableScheduling}'s javadoc for complete usage details. * * @author Chris Beams * @since 3.1 * @see EnableScheduling * @see ScheduledAnnotationBeanPostProcessor */ @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(); } }

解读一下注释,看看此类的作用:

为@Scheduled注解注册一个能被spring管理的名为:ScheduledAnnotationBeanPostProcessor的bean,当使用@EnableScheduling注解时,这个注解类会自动被导入


2.根据条件选择配置类


以@EnableAsync注解为例,看源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {省略....}

发现有@Import导入了一个AsyncConfigurationSelector类,我们追一下源码:

package org.springframework.scheduling.annotation;

import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.AdviceModeImportSelector;

/**
 * Selects which implementation of {@link AbstractAsyncConfiguration} should be used based
 * on the value of {@link EnableAsync#mode} on the importing {@code @Configuration} class.
 *
 * @author Chris Beams
 * @since 3.1
 * @see EnableAsync
 * @see ProxyAsyncConfiguration
 */
public class AsyncConfigurationSelector extends AdviceModeImportSelector {

	private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
			"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";

	/**
	 * {@inheritDoc}
	 * @return {@link ProxyAsyncConfiguration} or {@code AspectJAsyncConfiguration} for
	 * {@code PROXY} and {@code ASPECTJ} values of {@link EnableAsync#mode()}, respectively
	 */
	@Override
	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;
		}
	}

}
这个类的父父类是ImportSelector,其实是一个选择器,这个ImportSelector接口中只有一个方法
String[] selectImports(AnnotationMetadata importingClassMetadata);
AsyncConfigurationSelector类中重写了这个选择方法,根据不同的参数(adviceMode,我理解为框架建议的类型),会返回不同的配置类:

若adviceMode为PORXY,则返回ProxyAsyncConfiguration这个配置类。
若activeMode为ASPECTJ,则返回AspectJAsyncConfiguration配置类。


3.动态注册Bean


以@EnableAspectJAutoProxy为例,查看源码:

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

	/**
	 * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
	 * to standard Java interface-based proxies. The default is {@code false}.
	 */
	boolean proxyTargetClass() default false;

	/**
	 * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
	 * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
	 * Off by default, i.e. no guarantees that {@code AopContext} access will work.
	 * @since 4.3.1
	 */
	boolean exposeProxy() default false;

}
此类导入了AspectJAutoProxyRegistrar类,这个类实现了父类的registerBeanDefinitions()方法,此方法根据给定的注解定义来动态注册bean。



4.@Configuration源码分析


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

	/**
	 * Explicitly specify the name of the Spring bean definition associated
	 * with this Configuration class. If left unspecified (the common case),
	 * a bean name will be automatically generated.
	 * 

The custom name applies only if the Configuration class is picked up via * component scanning or supplied directly to a {@link AnnotationConfigApplicationContext}. * If the Configuration class is registered as a traditional XML bean definition, * the name/id of the bean element will take precedence. * @return the suggested component name, if any (or empty String otherwise) * @see org.springframework.beans.factory.support.DefaultBeanNameGenerator */ String value() default ""; }



@ Configuration注解的源码中其实是没什么内容的。我们看一下这段注解的意思:

显示的指定配置文件中定义的spring bean的名字,一般情况下,如果未显示的指明,将会自动生成一个bean的名字;

自定义名称,仅在配置类通过组件扫描或者由程序上下文直接给出时,才可以使用;

如果配置类是以xml的形式定义的,那xml中定义的bean名字将优先起作用;

此接口将会返回框架建议的组件名称,如果有的话,否则返回空字符串。


5.常用注解


@EnableAspectJAutoProxy
@EnableAspectJAutoProxy注解 激活Aspect自动代理,开启对AspectJ自动代理的支持。

@EnableAsync
@EnableAsync注解开启异步方法的支持。

@EnableScheduling
@EnableScheduling注解开启计划任务的支持。

@EnableWebMVC
@EnableWebMVC注解用来开启Web MVC的配置支持,也就是写Spring MVC时的时候会用到。

@EnableConfigurationProperties
@EnableConfigurationProperties注解是用来开启对@ConfigurationProperties注解配置Bean的支持。

@EnableJpaRepositories
@EnableJpaRepositories注解开启对Spring Data JPA Repostory的支持。

@EnableTransactionManagement
@EnableTransactionManagement注解开启注解式事务的支持,注解@EnableTransactionManagement通知Spring,@Transactional注解的类被事务的切面包围。这样@Transactional就可以使用了。

@EnableCaching
@EnableCaching注解开启注解式的缓存支持

你可能感兴趣的:((5)...面试,(4)...java基础)