?????????根据我们添加的jar包依赖,会?动将?些配置类的bean注册进ioc容器,我们可以 需要的地?使?@Autowired或者@Resource等注解来使?它。
原理:
- 收集spring开发者的编程习惯,整理开发过程使用的常用技术列表(技术集A)
- 收集常用技术(技术集A)的使用参数,整理开发过程中每个技术的常用设置列表(设置集B)
- 初始化springboot基础环境,加载用户自定义的bean和导入的其他坐标,形成初始化环境
- 将技术集A包含的所有技术都定义出来,在spring/springboot启动时默认全部加载
- 将技术集A中具有使用条件的技术约定出来,设置成按条件加载,由开发者决定是否使用该技术(与初始化环境比对)
- 将设置集B作为配置加载(约定大于配置),减少开发者配置工作量
- 开放设置集B的配置覆盖接口,由开发者根据自身需要决定是否覆盖默认配置
????????Spring Boot应?的启动??是@SpringBootApplication注解标注类中的main()?法,@SpringBootApplication : SpringBoot 应?标注在某个类上说明这个类 是 SpringBoot 的主配置类, SpringBoot 就应该运?这个类的 main() ?法启 动 SpringBoot 应?。
1 @SpringBootApplication
对@SpringBootApplication内部源码进?分析
@Target({ElementType.TYPE}) //注解的适?范围,Type表示注解可以描述在类、接?、注解或枚举中
@Retention(RetentionPolicy.RUNTIME)//表示注解的?命周期,Runtime运?时
@Documented//表示注解可以记录在javadoc中
@Inherited//表示可以被?类继承该注解
@SpringBootConfiguration// 标明该类为配置类
@EnableAutoConfiguration// 启动?动配置功
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
// 根据class来排除特定的类,使其不能加?spring容器,传?参数value类型是class类型。
@AliasFor(
annotation = EnableAutoConfiguration.class
)
Class<?>[] exclude() default {};
// 根据classname 来排除特定的类,使其不能加?spring容器,传?参数value类型是class的全类名字符串数组。
@AliasFor(
annotation = EnableAutoConfiguration.class
)
String[] excludeName() default {};
// 指定扫描包,参数是包名的字符串数组。
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackages"
)
String[] scanBasePackages() default {};
// 扫描特定的包,参数类似是Class类型数组。
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackageClasses"
)
Class<?>[] scanBasePackageClasses() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "nameGenerator"
)
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
?????????从上述可以看出,@SpringBootApplication注解是?个组合注解,前? 4 个是 注解的元数据信息, 我们主要看后? 3 个注解:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个核?注解。
2 @SpringBootConfiguration?
????????@SpringBootConfiguration : SpringBoot 的配置类,标注在某个类上,表 示这是?个 SpringBoot 的配置类。@SpringBootConfiguration注解源码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration// 配置类的作?等同于配置?件,配置类也是容器中的?个对象
@Indexed//加速springboot启动
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
?????????@SpringBootConfiguration注解内部有?个核?注解 @Configuration,该注解是Spring框架提供的,表示当前类为?个配置类(XML配置 ?件的注解表现形式),并可以被组件扫描器扫描。由此可?, @SpringBootConfiguration注解的作?与@Configuration注解相同,都是标识?个可 以被组件扫描器扫描的配置类,只不过@SpringBootConfiguration是被Spring Boot 进?了重新封装命名?已
3@EnableAutoConfiguration?
????????@EnableAutoConfiguration 的源码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage// ?动配置包
// Spring的底层注解@Import,给容器中导??个组件; 导?的组件是AutoConfigurationPackages.Registrar.class
@Import({AutoConfigurationImportSelector.class})
// 告诉SpringBoot开启?动配置功能,这样?动配置才能?效。
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
// 返回不会被导?到 Spring 容器中的类
Class<?>[] exclude() default {};
// 返回不会被导?到 Spring 容器中的类名
String[] excludeName() default {};
}
?????????Spring 中有很多以 Enable 开头的注解,其作?就是借助 @Import 来收集并注 册特定场景相关的 Bean ,并加载到 IOC 容器。
????????@EnableAutoConfiguration就是借助@Import来收集所有符合?动配置条件的bean 定义,并加载到IoC容器。
3.1@AutoConfigurationPackage
@AutoConfigurationPackage的源码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//设置当前配置所在的包作为扫描包,后续要针对当前的包进行扫描
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
????????@AutoConfigurationPackage :?动配置包,它也是?个组合注解,其中最重 要的注解是 @Import(AutoConfigurationPackages.Registrar.class) ,它 是 Spring 框架的底层注解,它的作?就是给容器中导?某个组件类,例如 @Import(AutoConfigurationPackages.Registrar.class) ,它就是 将 Registrar 这个组件类导?到容器中,可查看 Registrar 类中 registerBeanDefinitions?法:
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
// 将注解标注的元信息传?,获取到相应的包名
AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
}
?????????我们对 new PackageImport(metadata).getPackageName() 进?检索,看看 其结果 再看register?法
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
// 这?参数 packageNames 缺省情况下就是?个字符串,是使?了注解
// @SpringBootApplication 的 Spring Boot 应?程序??类所在的包
if (registry.containsBeanDefinition(BEAN)) {
// 如果该bean已经注册,则将要注册包名称添加进去
AutoConfigurationPackages.BasePackagesBeanDefinition beanDefinition = (AutoConfigurationPackages.BasePackagesBeanDefinition)registry.getBeanDefinition(BEAN);
beanDefinition.addBasePackages(packageNames);
} else {
//如果该bean尚未注册,则注册该bean,参数中提供的包名称会被设置到bean定义中去
registry.registerBeanDefinition(BEAN, new AutoConfigurationPackages.BasePackagesBeanDefinition(packageNames));
}
}
?????????AutoConfigurationPackages.Registrar这个类就??个事,注册?个 Bean ,这 个 Bean 就 是 org.springframework.boot.autoconfigure.AutoConfigurationPacka ges.BasePackages , @AutoConfigurationPackage 这个注解的类所在的包 路径,保存?动配置类以供之后的使?,?如给 JPA entity 扫描器?来扫描开发 ?员通过注解 @Entity 定义的 entity 类。
3.2 @Import(AutoConfigurationImportSelector.class)
????????@Import({AutoConfigurationImportSelector.class}) : 将 AutoConfigurationImportSelector 这个类导?到 Spring 容器 中, AutoConfigurationImportSelector 可以帮助 Springboot 应?将所有 符合条件的 @Configuration 配置都加载到当前 SpringBoot 创建并使?的 IOC 容器( ApplicationContext )中。
??????? 可以看到AutoConfigurationImportSelector 重点是实现了 DeferredImportSelector 接?Ordered接口和各种Aware 接?。
- 以Aware结尾的接?:以Aware结尾的接?提供了对应对象,例如实现BeanFactoryAware接口,就可以获得BeanFactory对象
public class CartoonCatAndMouse implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void play(){
//获取所有bean的名称
String[] beans = applicationContext.getBeanDefinitionNames();
for (String bean : beans) {
System.out.println(bean);
}
}
}
- Ordered接口:当前类在spring容器中的加载顺序
- DeferredImportSelector 接?:推迟导入选择器
??????? DeferredImportSelector接?继承了ImportSelector接?,ImportSelector接?又定义了一个新的接口Group,从Group的process方法看,因为是这是一个接口,所以从其实现类AutoConfigurationImportSelector看process方法。?
确定?动配置实现逻辑的???法:?
????????跟?动配置逻辑相关的???法在 DeferredImportSelectorGrouping DeferredImportSelectorGrouping 类 的 getImports getImports ?法处,因此我们就从 DeferredImportSelectorGrouping 类的 getImports ?法来开始分析
public Iterable<Entry> getImports() {
// 遍历DeferredImportSelectorHolder对象集合deferredImports,deferredImports集合装了各种ImportSelector,当然这?装的是AutoConfigurationImportSelector
Iterator var1 = this.deferredImports.iterator();
while(var1.hasNext()) {
ConfigurationClassParser.DeferredImportSelectorHolder deferredImport = (ConfigurationClassParser.DeferredImportSelectorHolder)var1.next();
// 【1】,利?AutoConfigurationGroup的process?法来处理?动配置的相关逻辑,决定导?哪些配置类(这个是我们分析的重点,?动配置的逻辑全在这了)
this.group.process(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getImportSelector());
}
// 【2】,经过上?的处理后,然后再进?选择导?哪些配置类
return this.group.selectImports();
}
????????标 【1】 处的的代码是我们分析的重中之重,?动配置的相关的绝?部分逻辑全在 这?了。那?this.group.process(deferredImport.getConfigurationClass().get Metadata(), deferredImport.getImportSelector()) ;主要做的事情就是在this.group 即 AutoConfigurationGroup对象的process?法中,传?的 AutoConfigurationImportSelector对象来选择?些符合条件的?动配置 类,过滤掉?些不符合条件的?动配置类。
注:
????????AutoConfigurationGroup:是AutoConfigurationImportSelector的内部类,主 要?来处理?动配置相关的逻辑,拥有process和selectImports?法,然后拥有 entries和autoConfigurationEntries集合属性,这两个集合分别存储被处理后的符 合条件的?动配置类;
????????AutoConfigurationImportSelector:承担?动配置的绝?部分逻辑,负责选择?些 符合条件的?动配置类;
????????metadata:标注在SpringBoot启动类上的@SpringBootApplication注解元数据 标【2】的this.group.selectImports的?法主要是针对前?的process?法处理后的 ?动配置类再进?步有选择的选择导?
分析?动配置的主要逻辑?
????????由上分析,跟?动配置逻辑相关的???法在AutoConfigurationImportSelector类的process?法中?
// 这??来处理?动配置类,?如过滤掉不符合匹配条件的?动配置类
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> {
return String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName());
});
// 【1】,调?getAutoConfigurationEntry?法得到?动配置类放?autoConfigurationEntry对象中
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector)deferredImportSelector).getAutoConfigurationEntry(annotationMetadata);
// 【2】,?将封装了?动配置类的autoConfigurationEntry对象装进autoConfigurationEntries集合
this.autoConfigurationEntries.add(autoConfigurationEntry);
Iterator var4 = autoConfigurationEntry.getConfigurations().iterator();
// 【3】,遍历刚获取的?动配置类
while(var4.hasNext()) {
String importClassName = (String)var4.next();
// 这?符合条件的?动配置类作为key,annotationMetadata作为值放进entries集合
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
????????上?代码中我们再来看标 【1】 的?法 getAutoConfigurationEntry ,这个? 法主要是?来获取?动配置类有关,承担了?动配置的主要逻辑。
// 获取符合条件的?动配置类,避免加载不必要的?动配置类从?造成内存浪费
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
// 获取是否有配置spring.boot.enableautoconfiguration属性,即是否配置@SpringBootApplication注解,默认返回true
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
// 获得@Congiguration标注的Configuration类即被审视introspectedClass的注解数据, ?如:@SpringBootApplication(exclude =FreeMarkerAutoConfiguration.class),将会获取到exclude = FreeMarkerAutoConfiguration.class和excludeName=""的两个注解数据
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
// 【1】得到spring.factories?件配置的所有?动配置类,即原理部分提到的技术集A全部加载
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
// 利?LinkedHashSet移除重复的配置类
configurations = this.removeDuplicates(configurations);
// 得到要排除的?动配置类,?如注解属性exclude的配置类@SpringBootApplication(exclude =
FreeMarkerAutoConfiguration.class),将会获取到exclude = FreeMarkerAutoConfiguration.class的注解数据
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
// 检查要被排除的配置类,因为有些不是?动配置类,故要抛出异常
this.checkExcludedClasses(configurations, exclusions);
// 【2】将要排除的配置类移除
configurations.removeAll(exclusions);
// 【3】因为从spring.factories?件获取的?动配置类太多,如果有些不必要的?动配置类都加载进内存,会造成内存浪费,因此这?需要进?过滤,注意这?会调?AutoConfigurationImportFilter的match?法来判断是否符合@ConditionalOnBean,@ConditionalOnClass或@ConditionalOnWebApplication,后?会重点分析?下
configurations = this.getConfigurationClassFilter().filter(configurations);
// 【4】获取了符合条件的?动配置类后,此时触发AutoConfigurationImportEvent事件,?的是告诉ConditionEvaluationReport条件评估报告器对象来记录符合条件的?动配置类,该事件什么时候会被触发?--> 在刷新容器时调?invokeBeanFactoryPostProcessors后置处理器时触发
this.fireAutoConfigurationImportEvents(configurations, exclusions);
// 【5】将符合条件和要排除的?动配置类封装进AutoConfigurationEntry对象,并返回
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
深?getCandidateConfigurations?法?
????????这个?法中有?个重要?法 loadFactoryNames ,这个?法是让 SpringFactoryLoader 去加载?些组件的名字。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 这个?法需要传?两个参数getSpringFactoriesLoaderFactoryClass()和getBeanClassLoader()
// getSpringFactoriesLoaderFactoryClass()这个?法返回的是EnableAutoConfiguration.class
// getBeanClassLoader()这个?法返回的是beanClassLoader(类加载器)
List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));
ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
继续点开 loadFactory ?法
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoader == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
//获取出?的键
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = (Map)cache.get(classLoader);
if (result != null) {
return result;
} else {
HashMap result = new HashMap();
try {
//如果类加载器不为null,则加载类路径下spring.factories?件,将其中设置的配置类的全路径信息封装 为Enumeration类对象
Enumeration urls = classLoader.getResources("META-INF/spring.factories");
//循环Enumeration类对象,根据相应的节点信息?成Properties对象,通过传?的键获取值,在将值切割为?个个?的字符串转化为Array,?法result集合中
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
String factoryTypeName = ((String)entry.getKey()).trim();
String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
String[] var10 = factoryImplementationNames;
int var11 = factoryImplementationNames.length;
for(int var12 = 0; var12 < var11; ++var12) {
String factoryImplementationName = var10[var12];
((List)result.computeIfAbsent(factoryTypeName, (key) -> {
return new ArrayList();
})).add(factoryImplementationName.trim());
}
}
}
result.replaceAll((factoryType, implementations) -> {
return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
});
cache.put(classLoader, result);
return result;
} catch (IOException var14) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
}
}
}
????????从代码中我们可以知道,在这个?法中会遍历整个ClassLoader中所有jar包下的 spring.factories?件。 spring.factories??保存着springboot的默认提供的?动配置类 。
????????AutoConfigurationEntry?法主要做的事情就是获取符合条件的?动配置类,避免加载不必要的?动配置类从?造成内存浪费。
AutoConfigurationEntry?法的作用:
- 从 spring.factories 配置?件中加载 EnableAutoConfiguration ?动 配置类);
- 若 @EnableAutoConfiguration 等注解标有要 exclude 的?动配置类,那 么再将这个?动配置类排除掉;
- 排除掉要 exclude 的?动配置类后,然后再调? filter ?法进?进?步的 过滤,再次排除?些不符合条件的?动配置类;
- 经过重重过滤后,此时再触发 AutoConfigurationImportEvent 事件,告 诉 ConditionEvaluationReport 条件评估报告器对象来记录符合条件的?动配 置类;
- 最后再将符合条件的?动配置类返回。
AutoConfigurationImportSelector 的 filter ?法:
List<String> filter(List<String> configurations) {
long startTime = System.nanoTime();
// 将从spring.factories中获取的?动配置类转出字符串数组
String[] candidates = StringUtils.toStringArray(configurations);
boolean skipped = false;
Iterator var6 = this.filters.iterator();
int i;
//拿到OnBeanCondition,OnClassCondition和OnWebApplicationCondition
// 然后遍历这三个条件类去过滤从spring.factories加载的?量配置类
while(var6.hasNext()) {
AutoConfigurationImportFilter filter = (AutoConfigurationImportFilter)var6.next();
// 判断各种filter来判断每个candidate(这?实质要通过candidate(?动配置类)拿到其标注的
// @ConditionalOnClass,@ConditionalOnBean和@ConditionalOnWebApplication??的注解值)是否匹配,
// 注意candidates数组与match数组??对应
boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);
// 遍历match数组,注意match顺序跟candidates的?动配置类??对应
for(i = 0; i < match.length; ++i) {
if (!match[i]) {
// 不匹配的将相应的?动配置类置空
candidates[i] = null;
// 标注skipped为true
skipped = true;
}
}
}
// 这?表示若所有?动配置类经过OnBeanCondition,OnClassCondition和OnWebApplicationCondition过滤后,全部都匹配的话,则全部原样返回
if (!skipped) {
return configurations;
} else {
// 建?result集合来装匹配的?动配置类
List<String> result = new ArrayList(candidates.length);
String[] var12 = candidates;
int var14 = candidates.length;
for(i = 0; i < var14; ++i) {
String candidate = var12[i];
// 若candidate不为null,则说明是符合条件的?动配置类,此时添加到result集合中
if (candidate != null) {
result.add(candidate);
}
}
// 打印?志
if (AutoConfigurationImportSelector.logger.isTraceEnabled()) {
int numberFiltered = configurations.size() - result.size();
AutoConfigurationImportSelector.logger.trace("Filtered " + numberFiltered + " auto configuration class in " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
}
// 最后返回符合条件的?动配置类
return result;
}
}
????????AutoConfigurationImportSelector AutoConfigurationImportSelector 的 filter ?法主要做的事情就是 调? AutoConfigurationImportFilter AutoConfigurationImportFilter 接?的 match ?法来判断每?个? 动配置类上的条件注解(若有的 话) @ConditionalOnClass , @ConditionalOnBean 或 @ConditionalOnWebApplication 是否满?条件,若满?,则返回true,说 明匹配,若不满?,则返回false说明不匹配。?
条件注解:
????????@Conditional是Spring4新提供的注解,它的作?是按照?定的条件进?判断,满? 条件给容器注册bean。
- @ConditionalOnBean:仅仅在当前上下?中存在某个对象时,才会实例化?个 Bean。
- @ConditionalOnClass:某个class位于类路径上,才会实例化?个Bean。
- @ConditionalOnExpression:当表达式为true的时候,才会实例化?个Bean。基 于SpEL表达式的条件判断。
- @ConditionalOnMissingBean:仅仅在当前上下?中不存在某个对象时,才会实例化?个Bean。
- @ConditionalOnMissingClass:某个class类路径上不存在的时候,才会实例化? 个Bean。
- @ConditionalOnNotWebApplication:不是web应?,才会实例化?个Bean。
- @ConditionalOnWebApplication:当项?是?个Web项?时进?实例化。
- @ConditionalOnNotWebApplication:当项?不是?个Web项?时进?实例化。
- @ConditionalOnProperty:当指定的属性有指定的值时进?实例化。
- @ConditionalOnJava:当JVM版本为指定的版本范围时触发实例化。
- @ConditionalOnResource:当类路径下有指定的资源时触发实例化。
- @ConditionalOnJndi:在JNDI存在的条件下触发实例化。
- @ConditionalOnSingleCandidate:当指定的Bean在容器中只有?个,或者有多 个但是指定了?选的Bean时触发实例化。
????????selectImports?法主要是针对经过排除掉exclude的和被 AutoConfigurationImportFilter接?过滤后的满?条件的?动配置类再进? 步排除exclude的?动配置类,然后再排序 。
总结:
- 先开发若干种技术的标准实现
- springboot启动时加载所有的技术实现对应的配置类
- 检测每个配置类的加载条件是否满足,并进行对应的初始化
- 切记是先加载所有的外部资源,然后根据初始环境进行条件比对
4.SpringBoot?动配置主要做了以下事情:
?1. 从spring.factories配置?件中加载?动配置类;
2. 加载的?动配置类中排除掉 @EnableAutoConfiguration注解的exclude属性指定的?动配置类;
3. 然后再?AutoConfigurationImportFilter接?去过滤?动配置类是 否符合其标注注解(若有标注的 话)@ConditionalOnClass , @ConditionalOnBean和 @ConditionalOnWebApplication的条件,若都符合的话则返回匹配结果;
4. 然后触发 AutoConfigurationImportEvent事件,告诉 ConditionEvaluationReport条件评估报告器对象来分别记录符合条件和exclude的?动配置类。
5. 最后spring再将最后筛选后的?动配置类导?IOC容器中
5.4@ComponentScan注解
????????主要是从定义的扫描路径中,找出标识了需要装配的类?动装配到spring 的bean容 器中。
????????常?属性如下:
- basePackages、value:指定扫描路径,如果为空则以@ComponentScan注解的类所在的包为基本的扫描路径
- basePackageClasses:指定具体扫描的类
- includeFilters:指定满?Filter条件的类
- excludeFilters:指定排除Filter条件的类?
????????includeFilters和excludeFilters 的FilterType可选:ANNOTATION=注解类型 默认、 ASSIGNABLE_TYPE(指定固定类)、ASPECTJ(ASPECTJ类型)、REGEX(正则表达式)、 CUSTOM(?定义类型),?定义的Filter需要实现TypeFilter接??
????????@ComponentScan的配置如下:?
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM,
classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes =
AutoConfigurationExcludeFilter.class) })
借助excludeFilters将TypeExcludeFillter及FilterType这两个类进?排除
????????当前@ComponentScan注解没有标注basePackages及value,所以扫描路径默认为 @ComponentScan注解的类所在的包为基本的扫描路径(也就是标注了 @SpringBootApplication注解的项?启动类所在的路径)
|