您的位置:首页 > 编程语言 > Java开发

SpringBoot ——自动配置原理浅析

2018-01-17 15:46 901 查看
SpringBoot的功能之所以强大,离不开它的自动配置这一大特色。但估计很多人只是知其然而不知其所以然。下面本人对自动配置原理做一个分析:

在使用SpringBoot时我们通过引入不同的Starter,就自动地应用其相应的自动配置。这是由于每个Starter都会引一个相应xxx--autoconfigure.jar,并且在这个jar的META-INF/spring.factories文件中有类似如下的配置:

      org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

      org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

也就是通过org.springframework.boot.autoconfigure.EnableAutoConfiguration这个为 key引入自动配置类。这个自动类就会以代码的方式去完成以前Spring的xml配置文件做的事。

现在的关键问题就是,Spring的容器是如何知道这个自动配置类的存在的呢?带着这个问题,我们来跟踪SpringBoot启动类的实例run方法,先列出方法源码:

public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}


其实整个过程的秘密全在上面这段代码中体现出来了,只不过隐藏的比较深而已。现在呢,我就直接通过通俗的方式先把这个秘密直接告诉大家,各位听好了,同是别忘了结合上面的源码自行理解:

其实上面这段有两个方法是和Spring容器发现这个自动配置类有关的

1. 在这个 prepareContext(context, environment, listeners, applicationArguments,printedBanner)

//方法中完成了SpringBoot 的main方法中的启动类在Spring容器中的注册,并且是以源的方式进行注册。也就是相当于告诉spring容器,这个启动类就相当于是以前的xml文件了,然后你 spring容器就看着办吧。



2. refreshContext(context);

//这个就是初始化 Spring容器,并实例化容器中注册的Bean,自然也就会对SpringBoot 的main方法中的启动类进行解析,肯定不会放过启动类上的那些注解的,这样一来,[b]启动类上的 注解 @EnableAutoConfiguration肯定没的跑了,通过对@EnableAutoConfiguration 上刑,它很快就会招了,首先看[b]@EnableAutoConfiguration的源码:[/b][/b]

@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.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 注解里面还藏着一个 @Import(EnableAutoConfigurationImportSelector.class) ,然后再看EnableAutoConfigurationImportSelector的类图:

[b]

[/b]

[b]原来 org.springframework.context.annotation.ImportSelector 才是这个组织的背后的头啊,[/b]

public interface ImportSelector {

/**
* Select and return the names of which class(es) should be imported based on
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
*/
String[] selectImports(AnnotationMetadata importingClassMetadata);

}


[b]通过跟踪 refreshContext方法,Spring容器在初始化容器和实化化bean的时候会对 [b][b]ImportSelector 的接口实例做一些特殊照顾的,其实我们都能想到,肯定会调用它的实现类的方法的,而我们现在通过分析[b]EnableAutoConfigurationImportSelector类,这个类被弃用了,也就是它的父类 AutoConfigurationImportSelector在起作用 ,AutoConfigurationImportSelector类就是完成到各个jar中找 META-INF/spring.factories文件,并加载其中配置key为[b]org.springframework.boot.autoconfigure.EnableAutoConfiguration的类的。[/b][/b][/b][/b][/b]

[b][b][b][b][b]至此,一切真相大白,欲知更细的细节,请听下回分解。[/b][/b][/b][/b][/b]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: