文章目录
- 2.1 核心运行原理
- 2.2 @EnableAutoConfiguration
- 2.3 AutoConfigurationImportSelector
- 2.3.1 @Import
- 2.3.2 ImportSelector&DeferedImportSelector接口
- 2.3.3 AutoConfigurationImportSelector功能概述
- AutoConfigurationMetadataLoader#loadMetadata
- getAutoConfigurationEntry
- isEnabled(AnnotationMetadata metadata)
- getAttributes(AnnotationMetadata metadata)
- getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes)
- removeDuplicates(List<T> list)
- getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes)
- checkExcludedClasses(List<String> configurations, Set<String> exclusions)
- filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata)
- fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions)
- 2.4 @Conditional注解
2.1 核心运行原理
springboot通过@EnableAutoConfiguration注解开启自动配置,加载spring.factories中注册的各种Autoconfiguration自动配置类,当某个AutoConfiguration类满足其注解@Conditional指定的生效条件时,则实例化该AutoConfiguration类中定义的Bean,并把这些Bean注册到Spring容器中,就可以完成依赖框架的自动配置。
2.2 @EnableAutoConfiguration
2.2.1 入口类和@SpringBootApplication
入口类
以下为springboot应用的常规入口类,形式上非常简单,类上面仅使用了@SpringBootApplication注解,在main方法中,指定入口类作为SpringApplication#run方法的运行参数,就可以启动springboot应用
@SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
@SpringBootApplication
该注解是springboot应用的核心注解,它里面组合了@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
// @Alias注解:该注解用于桥接到其它注解,该注解的属性中制定了所桥接的注解类
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {}; // 指定排除的自动配置类
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {}; // 指定排除的自动配置类类名
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {}; // 指定扫描的基础包
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {}; // 指定扫描的基础类
@AliasFor(annotation = Configuration.class)
boolean proxyBeanMethods() default true; // 是否生成配置类的代理类, 代理@Bean方法强制从spring容器中获取
}
我们刚学springboot的时候,就被“告知”:入口类所在的包及其子包中的组件将会被扫描。这也是要将入口类放在顶级package下的原因(如果放在比较低的层级,那么上级包的类或同级所在包的类无法扫描到),那么为什么呢?因为@SpringBootApplication注解上有个@ComponentScan注解,默认情况下,我们并没有指定任何扫描的基础包,而在ComponentScanAnnotationParser处理这个@ComponentScan注解的时候,获取到如果没有设置任何扫描的信息,那么就获取注解所标注的类所在的包作为扫描的基础包,因而基础包及其下面定义的组件都会被扫描到。我们可以,@SpringBootApplication(scanBasePackages = “com.zzhua.test”)桥接到@ComponentScan注解中的值,那么就只会com.将zzhua.test作为基础包扫描。
2.2.2 @EnableAutoConfiguration注解解析
@EnableAutoConfiguration
该注解是由@SpringBootApplication注解组合而引入的,用于开启自动配置,它会根据类路径上是否有引入指定的包中的类,尝试猜测并配置项目中可能需要的bean。所以也可以使用该注解提供的exclude等方法,排除某些自动配置。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage // 被该注解标记的类所在的包会作为自动配置基础包(比如扫描一些Entity啥的)
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; // 是否开启自动配置(通过env设置)
Class<?>[] exclude() default {}; // 排除指定的类
String[] excludeName() default {}; // 排除指定名字的类
}
2.3 AutoConfigurationImportSelector
该类在@EnableAutoConfiguration注解中被@Import(AutoConfigurationImportSelector.class)组合而引入
2.3.1 @Import
该注解用于向spring容器中导入组件,在源码中很多@EnableXXX也是基于该注解实现的
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
// 用来导入:
// 1. @Configuration标注的类
// 2. 实现了ImportSelector或DeferedImportSelector接口的子类
// 3. 实现了ImportBeanDefinitionRegistrar接口的子类
// 4. 常规普通类(作为组件)
Class<?>[] value();
}
2.3.2 ImportSelector&DeferedImportSelector接口
public interface ImportSelector {
// 参数:包含了被@Import注解标注的类上的注解信息
// 返回值:返回的数组将都会作为spring容器的配置类,用于引入相关组件
String[] selectImports(AnnotationMetadata importingClassMetadata);
}
如果ImportSelector的实现类,还实现了EnvironmentAware、BeanFactoryAware、BeanClassLoaderAware、ResourceLoaderAware接口,那么这些接口的回调都会在selectImports方法执行之前被回调,这样就可以拿到相应的对象了。
区别
@DeferedImportSelector会在所有的@Configuration类加载完成之后再加载返回的配置类,而ImportSelector在加载完@Configuration类之前先去加载返回的配置类,并且DeferedImportSelector的加载顺序可以通过@Order注解或实现Order接口来指定,并且它还可以了新的getImportGroup()来跨DeferedImportSelector实现自定义@Configuration的加载顺序。
2.3.3 AutoConfigurationImportSelector功能概述
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 获取env配置的spring.boot.enableautoconfiguration值,如果未配置,默认为true
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS; // 如果关闭默认配置,直接返回空数组,即所有自动配置类都不会自动配置了
}
// 加载类路径下META-INF/spring-autoconfigure-metadata.properties文件的所有数据
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
// 【核心方法:获取所有的自动配置类】
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
// 返回所有自动配置类的数组
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
AutoConfigurationMetadataLoader#loadMetadata
static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
try {
// 获取所有的文件
Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path)
: ClassLoader.getSystemResources(path);
Properties properties = new Properties();
while (urls.hasMoreElements()) {
// 遍历文件,加载所有的属性
properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));
}
return new PropertiesAutoConfigurationMetadata(properties);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);
}
}
# 多个值,使用逗号分隔(分隔的作用在后面解析中处理)
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration.ConditionalOnClass=com.datastax.driver.core.Cluster,reactor.core.publisher.Flux,org.springframework.data.cassandra.core.ReactiveCassandraTemplate
加载元数据配置,通过加载类路径下,指定路径:META-INF/spring-autoconfigure-metadata.properties文件。加载此数据是为了后续过滤自动配置使用。SpringBoot使用一个Annotation的处理器来收集自动加载的条件,这些条件就可以配置在这个文件当中。Springboot会将收集好的自动配置类,根据此配置信息,使用加载的过滤器(默认配置了3种:OnBeanCondition、OnClassCondition、OnWebApplicationCondition,它们都继承了FilteringSpringBootCondition),再进行一次过滤(跟在自动配置类上添加这些@ConditionalOnClass作用是一样的)。目的就是为了减少@Configuratin类的数量,从而减少初始化bean的耗时。
getAutoConfigurationEntry
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
// 获取env中设置的spring.boot.enableautoconfiguration值, 是否开启默认自动配置
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 获取到@Import注解所标注的类上的所有注解,中的@EnableAutoConfiguratin注解的信息
// AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(EnableAutoConfiguration.class.getName(), true))
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 使用SpringFactoriesLoader加载META-INFO/spring.factories文件中的@EnableAutoConfiguratin注解所对应的值(即自动配置类)
// 具体的加载细节:https://www.processon.com/view/link/61f0c54ee0b34d616d516e16
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 使用LinkedHashset来对所有的自动配置类来个去重操作
configurations = removeDuplicates(configurations);
// 根据@EanbleAutoConfiguratin注解的exclude和excludeName以及env里的spring.autoconfigure.exclude来获取需要排除的自动配置类
// (初步过滤)
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 你如果要排除某个自动配置类, 但是这个自动配置类又没有被加载到, 就会抛异常
checkExcludedClasses(configurations, exclusions);
// 移除 要排除 的自动配置类
configurations.removeAll(exclusions);
// 检查配置类的注解是否符合spring.factories文件中AutoConfigurationImportFilter指定的注解检查条件, 如果不满足将会被移除掉
// (再次过滤)
configurations = filter(configurations, autoConfigurationMetadata);
// 获取到spring.factories文件中所配置的AutoConfigurationImportListener监听器, 组装AutoConfigurationImportEvent,
// 并回调监听器的onAutoConfigurationImportEvent方法以广播事件
fireAutoConfigurationImportEvents(configurations, exclusions);
// 简单封装
return new AutoConfigurationEntry(configurations, exclusions);
}
isEnabled(AnnotationMetadata metadata)
protected boolean isEnabled(AnnotationMetadata metadata) {
// 如果是 AutoConfigurationImportSelector类
if (getClass() == AutoConfigurationImportSelector.class) {
// 固定的值"spring.boot.enableautoconfiguration"
return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
}
// 非AutoConfigurationImportSelector类,全都返回true
return true;
}
getAttributes(AnnotationMetadata metadata)
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
// 找的注解就是 @EnableAutoConfiguration
String name = getAnnotationClass().getName();
// 提取@EnableAutoConfiguration注解的属性值, 封装到AnnotationAttributes(继承自LinkedHashMap)
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
+ " annotated with " + ClassUtils.getShortName(name) + "?");
return attributes;
}
protected Class<?> getAnnotationClass() {
// 找的注解就是 EnableAutoConfiguration
return EnableAutoConfiguration.class;
}
getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes)
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 使用SpringFactoriesLoader加载META-INF/spring.factories中@EnableAutoConfiguration注解全类名对应的值
// 具体的加载细节:https://www.processon.com/view/link/61f0c54ee0b34d616d516e16
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
// 找的注解就是 @EnableAutoConfiguration
return EnableAutoConfiguration.class;
}
removeDuplicates(List list)
protected final <T> List<T> removeDuplicates(List<T> list) {
// 仅仅用LinkedHashSet去重
return new ArrayList<>(new LinkedHashSet<>(list));
}
getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes)
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
Set<String> excluded = new LinkedHashSet<>();
// 那其实我们使用@SpringBootApplication注解, 并没有碰触到@EnableAutoConfiguration呀
// 那是怎么修改到exclude和excludeName的属性值呢?
// 前面提到了@SpringBootApplication注解的这两个属性使用了@AliasFor将属性桥接到@EnableAutoConfiguration了
// 获取@EnableAutoConfiguration注解的exclude属性
excluded.addAll(asList(attributes, "exclude"));
// 获取@EnableAutoConfiguration注解的excludeName属性
excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
// 从env中获取spring.autoconfigure.exclude对应要排除的自动配置类
excluded.addAll(getExcludeAutoConfigurationsProperty());
return excluded;
}
private List<String> getExcludeAutoConfigurationsProperty() {
if (getEnvironment() instanceof ConfigurableEnvironment) {
// 绑定器, 拿到env中的propertySource
// PropertyPlaceholderHelper用来解析"${x:y}"占位符
// ApplicationConversionService(ConversionService的实现)用来类型转换
Binder binder = Binder.get(getEnvironment());
// 获取固定的值:spring.autoconfigure.exclude
return binder.bind(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class).map(Arrays::asList)
.orElse(Collections.emptyList());
}
String[] excludes = getEnvironment().getProperty(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class);
return (excludes != null) ? Arrays.asList(excludes) : Collections.emptyList();
}
checkExcludedClasses(List configurations, Set exclusions)
private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) {
List<String> invalidExcludes = new ArrayList<>(exclusions.size());
// 遍历要排除的自动配置类
for (String exclusion : exclusions) {
// 如果这个类存在, 但是根本就不在自动配置类集合中,就会收集异常
if (ClassUtils.isPresent(exclusion, getClass().getClassLoader()) && !configurations.contains(exclusion)) {
invalidExcludes.add(exclusion);
}
}
// 将收集的异常抛出去
if (!invalidExcludes.isEmpty()) {
handleInvalidExcludes(invalidExcludes);
}
}
filter(List configurations, AutoConfigurationMetadata autoConfigurationMetadata)
private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
// 候选的自动配置类
String[] candidates = StringUtils.toStringArray(configurations);
// 记录每个自动配置类是否要跳过
boolean[] skip = new boolean[candidates.length];
// 是否要全部跳过
boolean skipped = false;
// getAutoConfigurationImportFilters使用SpringFactoriesLoader
// 加载spring.factories中AutoConfigurationImportFilter全类名所对应的过滤器,并实例化
// autoconfigure包中默认提供了3个filter,默认是OnBeanCondition、OnClassCondition、OnWebApplicationCondition
// 它们都继承自FilteringSpringBootCondition抽象类(可以认为这个抽象类的实现就是用来过滤springboot的自动配置类的)
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) { // 遍历过滤器
// 回调Aware接口, 设置BeanClassLoader、BeanFactory、Environment、ResourceLoader
invokeAwareMethods(filter);
// 使用过滤器对每个候选的自动配置类, 使用boolean数组记录是否匹配
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
if (!match[i]) { // 如果有不匹配的
skip[i] = true; // 标记要跳过此候选的自动配置类
candidates[i] = null; // 候选的自动配置类置为null
skipped = true; // 标记有要跳过的自动配置类
}
}
}
// 如果没有要跳过的自动配置类, 就返回全部的自动配置类
if (!skipped) {
return configurations;
}
// 最终要返回的 自动配置类 集合
List<String> result = new ArrayList<>(candidates.length);
for (int i = 0; i < candidates.length; i++) {
if (!skip[i]) { // 忽略要跳过的自动配置类
result.add(candidates[i]);
}
}
if (logger.isTraceEnabled()) {
int numberFiltered = configurations.size() - result.size();
logger.trace("Filtered " + numberFiltered + " auto configuration class in "
+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
}
return new ArrayList<>(result);
}
FilteringSpringBootCondition
@Override
public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
// 只是做一个报告, 无关紧要
ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);
// 抽象模板方法, 交给具体子类实现, 这里以OnClassCondition为例继续看看
ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
// 与自动配置类等长的boolean数组
boolean[] match = new boolean[outcomes.length];
// 只是做一个报告, 无关紧要
for (int i = 0; i < outcomes.length; i++) {
match[i] = (outcomes[i] == null || outcomes[i].isMatch());
if (!match[i] && outcomes[i] != null) {
logOutcome(autoConfigurationClasses[i], outcomes[i]);
if (report != null) {
report.recordConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]);
}
}
}
return match;
}
OnClassCondition
@Order(Ordered.HIGHEST_PRECEDENCE)
class OnClassCondition extends FilteringSpringBootCondition {
@Override
protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
AutoConfigurationMetadata autoConfigurationMetadata) {
// Split the work and perform half in a background thread if more than one
// processor is available. Using a single additional thread seems to offer the
// best performance. More threads make things worse.
if (Runtime.getRuntime().availableProcessors() > 1) {
return resolveOutcomesThreaded(autoConfigurationClasses, autoConfigurationMetadata);
}
else {
// 假设处理器只有一个, 走这边
// 自动配置类 和 由 spring-autoconfigure-metadata.properties文件加载的属性值AutoConfigurationMetadata
// 封装到了内部类的OutcomesResolver 解析器
OutcomesResolver outcomesResolver = new StandardOutcomesResolver(autoConfigurationClasses, 0,
autoConfigurationClasses.length, autoConfigurationMetadata, getBeanClassLoader());
// 那剩下就要看这个解析器的resolveOutcomes方法了
return outcomesResolver.resolveOutcomes();
}
}
}
private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, int start, int end,
AutoConfigurationMetadata autoConfigurationMetadata) {
ConditionOutcome[] outcomes = new ConditionOutcome[end - start];
for (int i = start; i < end; i++) {
// 遍历每个自动配置类
String autoConfigurationClass = autoConfigurationClasses[i];
// 忽略null
if (autoConfigurationClass != null) {
// 固定格式是: 自动配置类全类名.ConditionalOnClass
// 以上面的值, 到pring-autoconfigure-metadata.properties文件中找配置的值
// 比如说:org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration.ConditionalOnClass=com.rabbitmq.client.Channel,\
// org.springframework.amqp.rabbit.core.RabbitTemplate
String candidates = autoConfigurationMetadata.get(autoConfigurationClass, "ConditionalOnClass");
// 如果有配置这个值的话
// (所以如果要给自动配置类生效添加条件, 我们也可以往这个文件中写入对应的要求, 也可以自定义AutoConfigurationImportFilter的实现)
if (candidates != null) {
// 把配置的值传进去, 做条件判断
outcomes[i - start] = getOutcome(candidates);
}
}
}
return outcomes;
}
private ConditionOutcome getOutcome(String candidates) {
try {
// 语法是使用逗号隔开多个值, 如果没有逗号, 只需要判断一个就行了
if (!candidates.contains(",")) {
return getOutcome(candidates, this.beanClassLoader);
}
// 如果有逗号, 以逗号分隔, 挨个判断, 第一个不为null就表示已经有结果了, 立即返回
for (String candidate : StringUtils.commaDelimitedListToStringArray(candidates)) {
ConditionOutcome outcome = getOutcome(candidate, this.beanClassLoader);
if (outcome != null) {
return outcome;
}
}
}
catch (Exception ex) {
// We'll get another chance later
}
return null;
}
private ConditionOutcome getOutcome(String className, ClassLoader classLoader) {
// 不存在className的类, 就返回true
if (ClassNameFilter.MISSING.matches(className, classLoader)) {
// 因为条件是onClassCondition, 所以这里是不匹配的
return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
.didNotFind("required class").items(Style.QUOTE, className));
}
// null表示接着判断下一个
return null;
}
fireAutoConfigurationImportEvents(List configurations, Set exclusions)
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
// SpringFactoriesLoader加载AutoConfigurationImportListener全类名对应的所有实例
List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
// 如果AutoConfigurationImportListener集合不为空
if (!listeners.isEmpty()) {
// 封装事件对象
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
// 遍历所有的监听器
for (AutoConfigurationImportListener listener : listeners) {
// 回调Aware接口, 设置BeanClassLoader、BeanFactory、Environment、ResourceLoader
invokeAwareMethods(listener);
// 通知每个监听器
listener.onAutoConfigurationImportEvent(event);
}
}
}
2.4 @Conditional注解
2.4.1 @Conditional
spring4.0中定义的注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
// 所有的Condition都满足时, 对应标注的组件才会生效
Class<? extends Condition>[] value();
}
Condition接口
@FunctionalInterface
public interface Condition {
// 传入的2个参数, 作为条件判断的基础依据
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
ConditionContext
public interface ConditionContext {
// bean注册中心, 可以获取容器中是否定义了相关的bean
BeanDefinitionRegistry getRegistry();
// bean工厂, 可以获取容器中存在的bean
@Nullable
ConfigurableListableBeanFactory getBeanFactory();
// env环境配置, 可以获取配置信息
Environment getEnvironment();
// 资源加载器
ResourceLoader getResourceLoader();
// 类加载器
@Nullable
ClassLoader getClassLoader();
}
AnnotatedTypeMetadata
可以获取所标注的 类 或者 方法 上的所有注解信息,而无须加载对应的类(asm实现)
public interface AnnotatedTypeMetadata {
// 获取所有的注解
MergedAnnotations getAnnotations();
// 是否标注了指定注解名称的注解
boolean isAnnotated(String annotationName);
// 获取指定注解的所有数据
Map<String, Object> getAnnotationAttributes(String annotationName);
Map<String, Object> getAnnotationAttributes(String annotationName,
boolean classValuesAsString);
MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName);
}
例如:
@Component("s1")
@Service("s2")
public class Student {
static {
System.out.println("static executing...");
}
public Student() {
System.out.println("student cons...");
}
}
public class TestApp {
public static void main(String[] args) throws IOException {
SimpleMetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
MetadataReader stuMetadataReader = metadataReaderFactory.getMetadataReader("com.zzhua.test.Student");
boolean annotated = stuMetadataReader.getAnnotationMetadata().isAnnotated(Component.class.getName());
System.out.println(annotated);
Map<String, Object> annotationAttributes = stuMetadataReader.getAnnotationMetadata().getAnnotationAttributes(Component.class.getName());
System.out.println(annotationAttributes); // {value=s1}
MultiValueMap<String, Object> allAnnotationAttributes = stuMetadataReader.getAnnotationMetadata().getAllAnnotationAttributes(Component.class.getName());
System.out.println(allAnnotationAttributes); // {value=[s1, ]}
}
// 结果只输出了 true, 静态代码块并未执行, 说明这种方式下,
// spring是没有加载这个类的, 但是可以获取到类上面是否包含指定的注解
}
2.4.2 @Conditional衍生注解
由@Conditional注解衍生而来的注解,这些注解上都标注了@Conditinal注解,并且指定了Condition接口的实现类,当满足指定的条件时,被该注解标注的类才会生效。
@ConditionalOnBean 当容器中由指定bean时
@ConditionalOnMissingBean 当在容器中没有指定bean时
@ConditionalOnClass 当在类路径下有指定类时
@ConditionalOnMissingClass 当在类路径下没有有指定类时
@ConditionalOnProperty 当指定的属性有指定的值时
@ConditionalOnExpression 当spel表达式为true时
@ConditionalOnWebApplication 当在web容器时
...
以@ConditionalOnMissingBean 为例
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class) // 注意这里有个@Conditional注解, 并且有OnBeanCondition条件要满足
public @interface ConditionalOnMissingBean {
Class<?>[] value() default {};
String[] type() default {};
Class<?>[] ignored() default {};
String[] ignoredType() default {};
Class<? extends Annotation>[] annotation() default {};
String[] name() default {};
SearchStrategy search() default SearchStrategy.ALL;
Class<?>[] parameterizedContainer() default {};
}
OnBeanCondition
@Order(Ordered.LOWEST_PRECEDENCE)
class OnBeanCondition extends FilteringSpringBootCondition implements ConfigurationCondition {
@Override
public ConfigurationPhase getConfigurationPhase() {
return ConfigurationPhase.REGISTER_BEAN;
}
// 此方法用于重写FilteringSpringBootCondition抽象类中的方法
// 根据spring-autoconfigure-metadata.properties文件对自动配置类再次筛选
@Override
protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
AutoConfigurationMetadata autoConfigurationMetadata) {
//
}
// 该类同时处理: @ConditionalOnBean、
// @ConditionalOnSingleCandidate、
// @ConditionalOnMissingBean
// 这3个注解
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
ConditionMessage matchMessage = ConditionMessage.empty();
MergedAnnotations annotations = metadata.getAnnotations();
if (annotations.isPresent(ConditionalOnBean.class)) {
// ... 对@ConditionalOnBean注解的处理
}
if (metadata.isAnnotated(ConditionalOnSingleCandidate.class.getName())) {
// ... 对@ConditionalOnSingleCandidate注解的处理
}
// 如果 方法或类 上有@ConditionalOnMissingBean注解
if (metadata.isAnnotated(ConditionalOnMissingBean.class.getName())) {
// 封装到Spec中
Spec<ConditionalOnMissingBean> spec = new Spec<>(context, metadata, annotations,
ConditionalOnMissingBean.class);
// 从容器中根据@ConditionalOnMissingBean注解中的条件匹配
MatchResult matchResult = getMatchingBeans(context, spec);
// 如果根据条件找到了满足条件的bean, 那就是不匹配
if (matchResult.isAnyMatched()) {
String reason = createOnMissingBeanNoMatchReason(matchResult);
// 返回条件不满足
return ConditionOutcome.noMatch(spec.message().because(reason));
}
// 没有找到满足条件的bean信息
matchMessage = spec.message(matchMessage).didNotFind("any beans").atAll();
}
// 匹配
return ConditionOutcome.match(matchMessage);
}
// 省略...
}