这几天项目中用到Apollo
,顺便看一下源码,然后看到Apollo
再Spring中注册配置的类ApolloConfigRegistrar
,里面大致就是注册了一堆processor
然后这个ApolloConfigRegistrar
是通过@EnableApolloConfig
注解去Import的
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(ApolloConfigRegistrar.class)
public @interface EnableApolloConfig {
String[] value() default {ConfigConsts.NAMESPACE_APPLICATION};
int order() default Ordered.LOWEST_PRECEDENCE;
}
那这个@EnableApolloConfig
是通过什么加载到Spring
中的呢,然后我就在IDEA中搜了一下,发现并没有任何地方用到了这个注解,这就让我很奇怪了
然后我去翻了下@EnableWebMvc
注解的代码,然后就在@Configuration
注解中找到了如下的注释
<h2>Enabling built-in Spring features using {@code @Enable} annotations</h2>
Spring features such as asynchronous method execution, scheduled task execution,
annotation driven transaction management, and even Spring MVC can be enabled and
configured from {@code @Configuration}
classes using their respective "{@code @Enable}" annotations. See
{@link org.springframework.scheduling.annotation.EnableAsync @EnableAsync},
{@link org.springframework.scheduling.annotation.EnableScheduling @EnableScheduling},
{@link org.springframework.transaction.annotation.EnableTransactionManagement @EnableTransactionManagement},
{@link org.springframework.context.annotation.EnableAspectJAutoProxy @EnableAspectJAutoProxy},
and {@link org.springframework.web.servlet.config.annotation.EnableWebMvc @EnableWebMvc}
for details.
总结下来就一句话,就是Spring
会自动加载@Enable*的注解起到初始化配置的作用
那Spring是如何自动加载@Enable注解的呢
我自己写了一个@Enable注解dubug了一下,看了调用栈发现是ConfigurationClassParser
在做处理,仔细一看,其实是递归调用,找Import注解然后进行后续的配置处理
/**
* Recursively collect all declared {@code @Import} values. Unlike most
* meta-annotations it is valid to have several {@code @Import}s declared with
* different values; the usual process of returning values from the first
* meta-annotation on a class is not sufficient.
* <p>For example, it is common for a {@code @Configuration} class to declare direct
* {@code @Import}s in addition to meta-imports originating from an {@code @Enable}
* annotation.
* @param sourceClass the class to search
* @param imports the imports collected so far
* @param visited used to track visited classes to prevent infinite recursion
* @throws IOException if there is any problem reading metadata from the named class
*/
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
throws IOException {
if (visited.add(sourceClass)) {
for (SourceClass annotation : sourceClass.getAnnotations()) {
String annName = annotation.getMetadata().getClassName();
if (!annName.startsWith("java") && !annName.equals(Import.class.getName())) {
collectImports(annotation, imports, visited);
}
}
imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
}
}
其实是Import注解在发生作用,而不是@Enable注解
那不用@Enable注解也可以自动配置吗
答案是可以的
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(XXX.class)
public @interface EnableXXX {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(XXX.class)
public @interface DisableXXX {
}
上面2个注解都可以生效
PS:有Spring Boot的AutoConfig机制,就不需要搞这么麻烦的配置了,这个只是Spring Framework的一部分罢了