Spring Boot自动配置源码-阿里云开发者社区

开发者社区> edwardsbean> 正文

Spring Boot自动配置源码

简介: <div class="markdown_views"> <h3 id="springboot初始化上下文环境">SpringBoot初始化上下文环境</h3> <p>SpringBoot会从<code>META-INF/spring.factories</code>文件中加载Initializers,Auto Configure</p> <p>Initializers用于
+关注继续查看

SpringBoot初始化上下文环境

SpringBoot会从META-INF/spring.factories文件中加载Initializers,Auto Configure

Initializers用于加载配置(Environment)
Auto Configure用于自动配置类

如果是web类型的工程,SpringBoot会创建EmbeddedWebApplicationContext上下文 -> 使用createEmbeddedServletContainer方法创建内嵌的servlet服务容器( 由工厂类EmbeddedServletContainerFactory -> getEmbeddedServletContainer()创建Servlet容器, ->initialize() 同时进行容器初始化及运行 )

容器类EmbeddedServletContainer控制着内嵌服务器的生命周期以及配置.

加载AutoConfiguration

AutoConfiguration初始化对应的实例

我们来看下Mongo的AutoConfiguration,如下:

@Configuration
@ConditionalOnClass(MongoClient.class)
@EnableConfigurationProperties(MongoProperties.class)
@ConditionalOnMissingBean(type = "org.springframework.data.mongodb.MongoDbFactory")
public class MongoAutoConfiguration {

    @Autowired
    private MongoProperties properties;

    @Autowired(required = false)
    private MongoClientOptions options;

    @Autowired
    private Environment environment;

    private MongoClient mongo;

    @PreDestroy
    public void close() {
        if (this.mongo != null) {
            this.mongo.close();
        }
    }

    @Bean
    @ConditionalOnMissingBean
    public MongoClient mongo() throws UnknownHostException {
        this.mongo = this.properties.createMongoClient(this.options, this.environment);
        return this.mongo;
    }

}

Mongo的AutoConfiguration将会在用户引入Mongo相关包时,并且没有自定义MongoDbFactory时被激活,同时配置文件(application.properties之类的)将注入到MongoProperties中.MongoProperties类由@ConfigurationProperties标注:

@ConfigurationProperties(prefix = "spring.data.mongodb")
public class MongoProperties {

    /**
     * Default port used when the configured port is {@code null}.
     */
    public static final int DEFAULT_PORT = 27017;

    /**
     * Mongo server host.
     */
    private String host;
    //...省略...
    //根据配置创建MongoClient
        public MongoClient createMongoClient(MongoClientOptions options,
            Environment environment) throws UnknownHostException {
        try {
            if (hasCustomAddress() || hasCustomCredentials()) {
                if (options == null) {
                    options = MongoClientOptions.builder().build();
                }
                List<MongoCredential> credentials = null;
                if (hasCustomCredentials()) {
                    String database = this.authenticationDatabase == null
                            ? getMongoClientDatabase() : this.authenticationDatabase;
                    credentials = Arrays.asList(MongoCredential.createMongoCRCredential(
                            this.username, database, this.password));
                }
                String host = this.host == null ? "localhost" : this.host;
                int port = determinePort(environment);
                return new MongoClient(Arrays.asList(new ServerAddress(host, port)),
                        credentials, options);
            }
            // The options and credentials are in the URI
            return new MongoClient(new MongoClientURI(this.uri, builder(options)));
        }
        finally {
            clearPassword();
        }
    }

可以看到MongoClient最终由MongoAutoConfiguration调用MongoProperties的createMongoClient()方法创建.通过标注@Bean将MongoClient发布到Spring容器中.

如果用户已经用@Bean自定义了一个MongoClient,那么Mongo AutoConfig就不会做去初始化MongoClient,配置文件中的配置也就不生效了.

Embedded Tomcat初始化过程

内嵌式Tomcat通过Tomcat类创建并配置的,我们可以看看Spring是如何包装的,使用工厂类TomcatEmbeddedServletContainerFactory -> getEmbeddedServletContainer() :

@Override
    public EmbeddedServletContainer getEmbeddedServletContainer(
            ServletContextInitializer... initializers) {
        //通常创建内嵌Tomcat时的流程,使用Tomcat类
        Tomcat tomcat = new Tomcat();
        File baseDir = (this.baseDirectory != null ? this.baseDirectory
                : createTempDir("tomcat"));
        tomcat.setBaseDir(baseDir.getAbsolutePath());
        Connector connector = new Connector(this.protocol);
        tomcat.getService().addConnector(connector);
        //用户可以通过这个接口做额外配置
        customizeConnector(connector);
        tomcat.setConnector(connector);
        tomcat.getHost().setAutoDeploy(false);
        tomcat.getEngine().setBackgroundProcessorDelay(-1);
        for (Connector additionalConnector : this.additionalTomcatConnectors) {
            tomcat.getService().addConnector(additionalConnector);
        }
        prepareContext(tomcat.getHost(), initializers);
        return getTomcatEmbeddedServletContainer(tomcat);
    }

Spring使用EmbeddedServletContainer包装了Tomcat,封装了内嵌容器的生命周期.

所有用户通过工厂类EmbeddedServletContainerFactory配置容器,例如:application.properties中的server.port=8099,
带有@ConfigurationProperties注解的ServerProperties,自动注入了application.properties中关于server.*的配置.

由于ServerProperties实现了EmbeddedServletContainerCustomizer接口,ServerProperties通过该接口的方法,对EmbeddedServletContainerFactory进行配置:

        if (getPort() != null) {
            container.setPort(getPort());
        }
        if (getAddress() != null) {
            container.setAddress(getAddress());
        }
        if (getContextPath() != null) {
            container.setContextPath(getContextPath());
        }
        if (getDisplayName() != null) {
            container.setDisplayName(getDisplayName());
        }
        if (getSession().getTimeout() != null) {
            container.setSessionTimeout(getSession().getTimeout());
        }
        if (getSsl() != null) {
            container.setSsl(getSsl());
        }
        if (getJspServlet() != null) {
            container.setJspServlet(getJspServlet());
        }
        if (getCompression() != null) {
            container.setCompression(getCompression());
        }

除了配置文件方式,我们还可以:

    @Bean
    public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
        factory.addConnectorCustomizers(connector -> {
            Http11NioProtocol protocol = ((Http11NioProtocol) connector.getProtocolHandler());
            connector.setPort(8989);
            protocol.setConnectionTimeout(10000);
        });
        return factory;
    }

直接自己创建工厂类,并实现addConnectorCustomizers接口中的customizer.这部分会覆盖配置文件的配置,在TomcatEmbeddedServletContainerFactory的getEmbeddedServletContainer() -> customizeConnector() 中会调用我们自定义的customizer:

        for (TomcatConnectorCustomizer customizer : this.tomcatConnectorCustomizers) {
            customizer.customize(connector);
        }

如果用户没有自定义EmbeddedServletContainerFactory的话,EmbeddedServletContainerAutoConfiguration就默认初始化一个.

    @Configuration
    @ConditionalOnClass({ Servlet.class, Tomcat.class })
    @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
    public static class EmbeddedTomcat {

        @Bean
        public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
            return new TomcatEmbeddedServletContainerFactory();
        }

    }

Reference

http://geowarin.github.io/understanding-spring-boot.html
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-troubleshoot-auto-configuration
http://blog.csdn.net/liaokailin/article/category/5765237

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
springboot自动配置原理
springboot自动配置原理从main函数说起 一切的开始要从SpringbootApplication注解说起。 @SpringBootApplicationpublic class MyBootApplication { public static void main(String[] args) { SpringApplication.
714 0
直播源码怎样搭建直播系统LNMP环境——PHP配置
前面两篇内容我们聊过了直播平台搭建前需要准备的内容,一切准备就绪之后就要进入正式的搭建部署环节了,本篇就先简单介绍下LNMP环境下的PHP配置。
2668 0
idea配置SpringBoot热部署之自动Build
一、pom.xml文件导入所需依赖文件 SpringBoot热部署插件 org.springframework.boot spring-boot-devtools true runtime 二、pom.xml文件build标签进行修改如下 该插件由Maven提供,它会自动使用当前运行mvn命令的JDK去编译Java源代码。
1062 0
运维调试记录:Ubuntu下通过PPA方式安装Java 8并自动配置环境变量
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhaobryant/article/details/51125246 Install OpenJDK 8 in Ubuntu: For 14.
810 0
spring源码学习之:xml标签扩展配置例子
在很多情况下,我们需要为系统提供可配置化支持,简单的做法可以直接基于Spring的标准Bean来配置,但配置较为复杂或者需要更多丰富控制的 时候,会显得非常笨拙。一般的做法会用原生态的方式去解析定义好的xml文件,然后转化为配置对象,这种方式当然可以解决所有问题,但实现起来比较繁琐, 特别是是在配置非常复杂的时候,解析工作是一个不得不考虑的负担。
1495 0
spring源码学习之:xml配置文件标签自定义
Spring框架从2.0版本开始,提供了基于Schema风格的XML扩展机制,允许开发者扩展最基本的spring配置文件(一 般是classpath下的spring.xml)。试想一下,如果我们直接在spring.xml中加入一个自定义标签,会发生什么呢?spring框架启动的时候会报错,因为spring根本不认识我们自定义的& lt;mytag>,这样对spring.xml的校验就会失败,最终结果就是框架不能启动。
1553 0
VB源码升级后的几幅截图-VBIDE嵌入窗体、代码资源自动加入
用了整整两天的时间终于完成了功能上的升级,但多国语言版和数据库的加密还不知什么时间能做完,所以一时还不能发布,不过作为“内部人员”倒是可以先用为快:) 一、把原图标进行了修改,可以适应系统背景色了,图标也另做了几个,比以前漂亮多了 二、把智能查询和智能定位都做成了VB IDE嵌入窗体了,同时也把代码资源管理的功能也添加进来了,可以方便的添加代码资源,同时也很方便的加入到当前工程(直接添加,新建模块,新建类等等多种方式添加)中去。
577 0
+关注
98
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载