通常我们启动一个springboot项目会在启动方法中增加@SpringBootApplicatoin注解,该注解中包含了@EnableAutoConfiguration

@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 { /**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {}; /**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {}; /**
* Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
* for a type-safe alternative to String-based package names.
* @return base packages to scan
* @since 1.3.0
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {}; /**
* Type-safe alternative to {@link #scanBasePackages} for specifying the packages to
* scan for annotated components. The package of each class specified will be scanned.
* <p>
* Consider creating a special no-op marker class or interface in each package that
* serves no purpose other than being referenced by this attribute.
* @return base packages to scan
* @since 1.3.0
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {}; }

那么@EnableAutoConfiguration是如何自动起作用的呢。我们先来看看@EnableAutoConfiguration的定义

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; /**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {}; /**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {}; }

我们看看EnableAutoConfiguration的注释定义:

Enable auto-configuration of the Spring Application Context, attempting to guess and
* configure beans that you are likely to need. Auto-configuration classes are usually
* applied based on your classpath and what beans you have defined.

大概的意思是:容器尝试猜测你想配置的bean,然后自动加载。

很欣喜的发现了@EnableAutoConfiguration里面引用了@Import(AutoConfigurationImportSelector.class),直觉看起来像这个AutoConfigurationImportSelector里面引入了我们那些自动配置(数据源、拦截器)的类。

我们来看看AutoConfigurationImportSelector的定义:

public class AutoConfigurationImportSelector
implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware, Ordered

原来AutoConfigurationImportSelector类实现了org.springframework.context.annotation.DeferredImportSelector

那么实现了该类的public String[] selectImports(AnnotationMetadata annotationMetadata)后,spring在解析bean的时候,就会自动调用该方法来加载拓展类,也就是selectImports方法返回的名称列表来加载类。

很容易起想到selectImports里面就返回了AutoEnableConfiguration的那些数据源、拦截器配置的类。!

接下来看看selectImports的具体实现:

    @Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
//从org.springframework.boot.autoconfigure.AutoConfigurationMetadataLoader的loadMetadata加载要自动配置的资源数据
        AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this
.beanClassLoader);
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(
autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

看下AutoConfigurationMetadataLoader的源码看,可以看到默认加载的自动配置的路径为:/META-INF/spring-autoconfigure-metadata.properteis。

final class AutoConfigurationMetadataLoader {
//默认加载自动配置的文件位置
protected static final String PATH = "META-INF/"
+ "spring-autoconfigure-metadata.properties"; private AutoConfigurationMetadataLoader() {
} public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
return loadMetadata(classLoader, PATH);
} 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 loadMetadata(properties);
}
catch (IOException ex) {
throw new IllegalArgumentException(
"Unable to load @ConditionalOnClass location [" + path + "]", ex);
}
} static AutoConfigurationMetadata loadMetadata(Properties properties) {
return new PropertiesAutoConfigurationMetadata(properties);
} /**
* {@link AutoConfigurationMetadata} implementation backed by a properties file.
*/
private static class PropertiesAutoConfigurationMetadata
implements AutoConfigurationMetadata { private final Properties properties; PropertiesAutoConfigurationMetadata(Properties properties) {
this.properties = properties;
} @Override
public boolean wasProcessed(String className) {
return this.properties.containsKey(className);
} @Override
public Integer getInteger(String className, String key) {
return getInteger(className, key, null);
} @Override
public Integer getInteger(String className, String key, Integer defaultValue) {
String value = get(className, key);
return (value != null) ? Integer.valueOf(value) : defaultValue;
} @Override
public Set<String> getSet(String className, String key) {
return getSet(className, key, null);
} @Override
public Set<String> getSet(String className, String key,
Set<String> defaultValue) {
String value = get(className, key);
return (value != null) ? StringUtils.commaDelimitedListToSet(value)
: defaultValue;
} @Override
public String get(String className, String key) {
return get(className, key, null);
} @Override
public String get(String className, String key, String defaultValue) {
String value = this.properties.getProperty(className + "." + key);
return (value != null) ? value : defaultValue;
} } }

可以看到配置的默认加载的配载类有如下,这些类都被@Confiration注解,并且都自动创建了一些@Bean来使用组件的特性,通过这些自动创建的bean来代替我们系统中手动声明bean,达到加快开发效率的效果。

[org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration, org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration, org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration, org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration, org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration, org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration, org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration, org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration, org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration, org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration, org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration, org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration, org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration, org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration, org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration, org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration, org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration, org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration, org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration, org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration, org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration]

至此,springboot自动加载配置的原理也分析完毕。

springboot的@EnableAutoConfiguration起作用的原理的更多相关文章

  1. 007 SpringBoot的@EnableAutoConfiguration注解

    一:原理 1. 首先Spring Boot项目中都会如下启动类: @SpringBootApplication public class Application { public static voi ...

  2. SpringBoot:配置文件及自动配置原理

    西部开源-秦疆老师:基于SpringBoot 2.1.6 的博客教程 秦老师交流Q群号: 664386224 未授权禁止转载!编辑不易 , 转发请注明出处!防君子不防小人,共勉! SpringBoot ...

  3. if __name__ == 'main': 的作用和原理

    if __name__ == 'main': 功能 一个python的文件有两种使用的方法,第一是直接作为脚本执行,第二是import到其他的python脚本中被调用(模块重用)执行. if __na ...

  4. 【原创】uC/OS 中LES BX,DWORD PTR DS:_OSTCBCur的作用及原理

    LES BX, DWORD PTR DS:_OSTCBCur ;OSTCBCur->OSTCBStkPtr = SS:SP!!! ], SS ;将当前SS(栈的基地址)寄存器值存放至当前任务控制 ...

  5. synchronized与volatile的区别及各自的作用、原理(学习记录)

    synchronized与volatile的区别,它们的作用及原理? 说到两者的区别,先要了解锁提供的两种特性:互斥(mutual exclusion) 和可见性(visibility). 互斥:即一 ...

  6. EnableAutoConfiguration注解的工作原理(org.springframework.boot.autoconfigure.EnableAutoConfiguration=core.bean.MyConfig)

    EnableAutoConfiguration注解的工作原理(org.springframework.boot.autoconfigure.EnableAutoConfiguration=core.b ...

  7. volatile关键字的作用、原理

    在只有双重检查锁,没有volatile的懒加载单例模式中,由于指令重排序的问题,我确实不会拿到两个不同的单例了,但我会拿到"半个"单例. 而发挥神奇作用的volatile,可以当之 ...

  8. 面试题:volatile关键字的作用、原理

    在只有双重检查锁,没有volatile的懒加载单例模式中,由于指令重排序的问题,我确实不会拿到两个不同的单例了,但我会拿到“半个”单例. 而发挥神奇作用的volatile,可以当之无愧的被称为Java ...

  9. JAVA基础加强(张孝祥)_类加载器、分析代理类的作用与原理及AOP概念、分析JVM动态生成的类、实现类似Spring的可配置的AOP框架

    1.类加载器 ·简要介绍什么是类加载器,和类加载器的作用 ·Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader ...

随机推荐

  1. luogu题解 P3709 【大爷的字符串题】

    题目链接: https://www.luogu.org/problemnew/show/P3709 思路: 首先我是没读懂题目的,浏览了讨论区的dalao发现才知道就是求区间众数的出现次数. 然后肯定 ...

  2. JVM学习笔记(一):Java虚拟机和虚拟机内存区域

    为什么Java程序需要运行在虚拟机上 因为Java在设计之初的跨平台特性,我们知道Java程序是运行在Java虚拟机上的.如果你要问为什么Java程序要运行在虚拟机上,我可以反问你几个问题. 为什么买 ...

  3. mysql的锁机制,以及乐观锁,悲观锁,以及热点账户余额问题

    mysql的简单锁机制. myisam 1.只支持表级锁,所以经常更新的表结构不适宜用. 2.select也会产生锁表 innodb 1.支持事务,行级锁,表级锁,执行行级锁的前提是sql语句的索引有 ...

  4. Centos 7.0 界面

    执行:systemctl get-default //显示默认的界面方式 multi-user.target //命令行界面 graphical.target //图形化界面 执行:systemctl ...

  5. 08-【jsp重点】

    jsp的四个作用域和9个内置对象 jsp内置对象[重点]:pageContext.request.session.application.response.out.page.exception.con ...

  6. cubase 使用冻结功能 节省电脑资源

  7. 阿里云-docker安装rabbitmq及无法访问主页

    一.下载最新的rabbitmq docker pull rabbitmq 二.下载完以后启动容器 docker run -d -p 5672:5672 -p 15672:15672 --name my ...

  8. UVa156 Ananagrams(映射map)

    Ananagrams 题目 Most crossword puzzle fans are used to anagrams--groups of words with the same letters ...

  9. TCP_Wrappers应用层防火墙

    TCP_Wrappers是一个工作在应用层的安全工具,它只能针对某些具体的应用或者服务起到一定的防护作用.比如说ssh.telnet.FTP等服务的请求,都会先受到TCP_Wrappers的拦截. T ...

  10. k8s部署ingress-nginx

    ingress-nginx的部署方式有多种,本文介绍nodeport方式和hostnetwork方式: 一.nodeport方式 1.下载mandatory.yaml文件:https://raw.gi ...