3Spring Boot 运行原理,自动配置

来源:互联网 发布:郑智化IT 编辑:程序博客网 时间:2024/06/05 16:20

启动流程

我们可以先看看这段代码发生了什么事情

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. SpringApplication.run(App.class, args);  


在创建SpringApplication的时候初始化了一些ApplicationContextApplicationListener

主要通过getSpringFactoriesInstances方法来实现


上面的SpringFactoriesLoader.loadFactoryNames方法看这里


下面我们可以查看下spring.factories文件,spring-boot-autoconfigure spring-bootjar包中都有


我们可以先看看Spring-boot里面的文件


SpringApplication创建,初始化了上述的 Application ContextApplication Listeners


通过spring.factories文件拿到一系列的ContextListener之后 执行run方法

run方法会从spring.factories文件中获取到run listener,然后在spirng boot 执行到各个阶段时执行Listener事件和Context事件

所以,所谓的SpringApplicationRunListeners实际上就是在SpringApplication对象的run方法执行的不同阶段,去执行一些操作,并且这些操作是可配置的。

Spring boot总共有这些事件类型


Spring 事件体系

http://blog.csdn.net/caihaijiang/article/details/7460888


看下createAndRefreshContext方法


applyInitializers方法其中

DelegatingApplicationContextInitializer读取context.initializer.classes配置,这些类都是实现了ApplicationContextInitializer接口的类,读取之后执行initialize方法,所以我们在这里可以自己扩展一些东西

 

这里有一些listenercontext的功能图


这里面代码看的晕乎乎的,都不知道理解的对不对,希望不会对你们产生误导

参考资料

http://blog.csdn.net/liaokailin/article/category/5765237

http://zhaox.github.io/java/2016/03/22/spring-boot-start-flow

http://blog.csdn.net/u011179993/article/details/51475732


自动配置

Spring Boot关于自动配置的源码在spring-boot-autoconfigure.


上面的这些东西主要是靠condition包下面的注解来根据不同的条件自动创建Bean


这些注解都是组合了@Conditional元注解,只是使用了不同的条件

 

我们可以查看下@ConditionalOnWebApplication这个注解


这个注解使用的条件是OnWebApplicationCondition这个类

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package org.springframework.boot.autoconfigure.condition;  
  2.   
  3. import org.springframework.context.annotation.Condition;  
  4. import org.springframework.context.annotation.ConditionContext;  
  5. import org.springframework.core.Ordered;  
  6. import org.springframework.core.annotation.Order;  
  7. import org.springframework.core.type.AnnotatedTypeMetadata;  
  8. import org.springframework.util.ClassUtils;  
  9. import org.springframework.util.ObjectUtils;  
  10. import org.springframework.web.context.WebApplicationContext;  
  11. import org.springframework.web.context.support.StandardServletEnvironment;  
  12.   
  13. /** 
  14.  * {@link Condition} that checks for the presence or absence of 
  15.  * {@link WebApplicationContext}. 
  16.  * 
  17.  * @author Dave Syer 
  18.  * @see ConditionalOnWebApplication 
  19.  * @see ConditionalOnNotWebApplication 
  20.  */  
  21. @Order(Ordered.HIGHEST_PRECEDENCE + 20)  
  22. class OnWebApplicationCondition extends SpringBootCondition {  
  23.   
  24.     private static final String WEB_CONTEXT_CLASS = "org.springframework.web.context."  
  25.             + "support.GenericWebApplicationContext";  
  26.   
  27.     @Override  
  28.     public ConditionOutcome getMatchOutcome(ConditionContext context,  
  29.             AnnotatedTypeMetadata metadata) {  
  30.         boolean webApplicationRequired = metadata  
  31.                 .isAnnotated(ConditionalOnWebApplication.class.getName());  
  32.            //判断是否是web环境,并获取结果  
  33.         ConditionOutcome webApplication = isWebApplication(context, metadata);  
  34.              
  35.         if (webApplicationRequired && !webApplication.isMatch()) {  
  36.             return ConditionOutcome.noMatch(webApplication.getMessage());  
  37.         }  
  38.   
  39.         if (!webApplicationRequired && webApplication.isMatch()) {  
  40.             return ConditionOutcome.noMatch(webApplication.getMessage());  
  41.         }  
  42.   
  43.         return ConditionOutcome.match(webApplication.getMessage());  
  44.     }  
  45.   
  46.     private ConditionOutcome isWebApplication(ConditionContext context,  
  47.             AnnotatedTypeMetadata metadata) {  
  48.            //判断GenericWebApplicationContext是否在类路径中  
  49.         if (!ClassUtils.isPresent(WEB_CONTEXT_CLASS, context.getClassLoader())) {  
  50.             return ConditionOutcome.noMatch("web application classes not found");  
  51.         }  
  52.           //容器中是否有名为session的scope  
  53.         if (context.getBeanFactory() != null) {  
  54.             String[] scopes = context.getBeanFactory().getRegisteredScopeNames();  
  55.             if (ObjectUtils.containsElement(scopes, "session")) {  
  56.                 return ConditionOutcome.match("found web application 'session' scope");  
  57.             }  
  58.         }  
  59.           //当前容器的enviroment是否为StandardServletEnviroment  
  60.         if (context.getEnvironment() instanceof StandardServletEnvironment) {  
  61.             return ConditionOutcome  
  62.                     .match("found web application StandardServletEnvironment");  
  63.         }  
  64.           //当前容器的resourceLoader是否是WebApplicationContext  
  65.         if (context.getResourceLoader() instanceof WebApplicationContext) {  
  66.             return ConditionOutcome.match("found web application WebApplicationContext");  
  67.         }  
  68.   
  69.         return ConditionOutcome.noMatch("not a web application");  
  70.     }  
  71.   
  72. }  

最终通过ConditionOutcome返回是否web项目,还有判断结果


自定义starter pom

自己实现一个简单的例子,当某个类存在的时候,自动配置这个Bean,并且可以讲这个属性在application.properties中配置

 

新建一个maven项目

Pom.xml

[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  2.   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  3.   <modelVersion>4.0.0</modelVersion>  
  4.   
  5.   <groupId>com.ibigsea</groupId>  
  6.   <artifactId>spring-boot-starter-hello</artifactId>  
  7.   <version>0.0.1-SNAPSHOT</version>  
  8.   <packaging>jar</packaging>  
  9.   
  10.   <name>spring-boot-starter-hello</name>  
  11.   <url>http://maven.apache.org</url>  
  12.   
  13.   <properties>  
  14.     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
  15.   </properties>  
  16.   
  17.   <dependencies>  
  18.     <dependency>  
  19.       <groupId>org.springframework.boot</groupId>  
  20.       <artifactId>spring-boot-autoconfigure</artifactId>  
  21.       <version>1.3.3.RELEASE</version>  
  22.     </dependency>  
  23.   </dependencies>  
  24. </project>  

Hello.Java

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.ibigsea.spring_boot_starter_hello;  
  2.   
  3. /** 
  4.  * 通过application.properties的hello.msg来配置,默认为world 
  5.  * @author bigsea 
  6.  * 
  7.  */  
  8. public class Hello {  
  9.       
  10.     private String msg;  
  11.   
  12.     public String sayHello() {  
  13.         return "hello " + msg;  
  14.     }  
  15.       
  16.     public String getMsg() {  
  17.         return msg;  
  18.     }  
  19.   
  20.     public void setMsg(String msg) {  
  21.         this.msg = msg;  
  22.     }  
  23.       
  24. }  

HelloProperties.java

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.ibigsea.spring_boot_starter_hello;  
  2.   
  3. import org.springframework.boot.context.properties.ConfigurationProperties;  
  4.   
  5. /** 
  6.  * 属性配置,Spring boot 自身的自动配置 
  7.  * @author bigsea 
  8.  * 
  9.  */  
  10. @ConfigurationProperties(prefix="hello")  
  11. public class HelloProperties {  
  12.       
  13.     private static final String MSG = "world";  
  14.       
  15.     private String msg = MSG ;  
  16.   
  17.     public String getMsg() {  
  18.         return msg;  
  19.     }  
  20.   
  21.     public void setMsg(String msg) {  
  22.         this.msg = msg;  
  23.     }  
  24.       
  25.       
  26. }  

HelloAutoConfiguration.java

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.ibigsea.spring_boot_starter_hello;  
  2.   
  3. import org.springframework.beans.factory.annotation.Autowired;  
  4. import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;  
  5. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;  
  6. import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;  
  7. import org.springframework.boot.context.properties.EnableConfigurationProperties;  
  8. import org.springframework.context.annotation.Bean;  
  9. import org.springframework.context.annotation.Configuration;  
  10.   
  11. @Configuration  
  12. @EnableConfigurationProperties(HelloProperties.class)//开启属性注入,通过@autowired注入  
  13. @ConditionalOnClass(Hello.class)//判断这个类是否在classpath中存在  
  14. //当设置hello=enabled的情况下,如果没有设置则默认为true,即条件符合  
  15. @ConditionalOnProperty(prefix="hello", value="enabled", matchIfMissing = true)  
  16. public class HelloAutoConfiguration {  
  17.       
  18.     @Autowired  
  19.     private HelloProperties helloProperties;  
  20.       
  21.     @Bean//使用java配置方式配置这个类  
  22.     @ConditionalOnMissingBean(Hello.class)//容器中如果没有Hello这个类,那么自动配置这个Hello  
  23.     public Hello hello() {  
  24.         Hello hello = new Hello();  
  25.         hello.setMsg(helloProperties.getMsg());  
  26.         return hello;  
  27.     }  
  28.       
  29. }  

并且要添加spring.factories

[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. # Auto Configure  
  2. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\  
  3. com.ibigsea.spring_boot_starter_hello.HelloAutoConfiguration  

整个项目结构


好了,到这里我们就完成了一个starter项目了,下面自己测试下

Pom.xml

[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  2.   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  3.   <modelVersion>4.0.0</modelVersion>  
  4.   
  5.   <groupId>com.ibigsea</groupId>  
  6.   <artifactId>test-starter</artifactId>  
  7.   <version>0.0.1-SNAPSHOT</version>  
  8.   <packaging>jar</packaging>  
  9.   
  10.   <name>test-starter</name>  
  11.   <url>http://maven.apache.org</url>  
  12.   
  13.     <properties>  
  14.         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
  15.         <boot.version>1.3.3.RELEASE</boot.version>  
  16.     </properties>  
  17.   
  18.     <dependencies>  
  19.         <dependency>  
  20.             <groupId>com.ibigsea</groupId>  
  21.             <artifactId>spring-boot-starter-hello</artifactId>  
  22.             <version>0.0.1-SNAPSHOT</version>  
  23.         </dependency>  
  24.         <dependency>  
  25.             <groupId>org.springframework.boot</groupId>  
  26.             <artifactId>spring-boot-starter-web</artifactId>  
  27.             <version>${boot.version}</version>  
  28.         </dependency>  
  29.         <dependency>  
  30.             <groupId>org.springframework.boot</groupId>  
  31.             <artifactId>spring-boot-starter-test</artifactId>  
  32.             <version>${boot.version}</version>  
  33.             <scope>test</scope>  
  34.         </dependency>  
  35.     </dependencies>  
  36. </project>  

App.java

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.ibigsea.test_starter;  
  2.   
  3. import org.springframework.beans.factory.annotation.Autowired;  
  4. import org.springframework.boot.SpringApplication;  
  5. import org.springframework.boot.autoconfigure.SpringBootApplication;  
  6. import org.springframework.web.bind.annotation.RequestMapping;  
  7. import org.springframework.web.bind.annotation.RestController;  
  8.   
  9. import com.ibigsea.spring_boot_starter_hello.Hello;  
  10.   
  11.   
  12. @SpringBootApplication   
  13. @RestController  
  14. public class App {  
  15.       
  16.     @Autowired  
  17.     private Hello hello;  
  18.       
  19.     @RequestMapping("/")  
  20.     public String index() {  
  21.         return hello.sayHello();  
  22.     }  
  23.       
  24.     public static void main(String[] args) {  
  25.         SpringApplication.run(App.class, args);  
  26.     }  
  27. }  

application.properties

[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. hello.msg=bigsea  

运行结果





开启dubug模式 可以看到自动配置信息



0 0
原创粉丝点击