摘要:我们在开发中,会经常用到@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 "";
}
显示的指定配置文件中定义的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注解开启注解式的缓存支持