springboot自动配置原理
Posted LDDXFS
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot自动配置原理相关的知识,希望对你有一定的参考价值。
Springboot自动配置原理:
主类 @SpringBootApplication 开启了自动配置
@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 { ... }
@Import(EnableAutoConfigurationImportSelector.class) 通过注解的方式实现把实例EnableAutoConfigurationImportSelector加入springIOC容器中,
EnableAutoConfigurationImportSelector实现了接口ImportSelector,并在其父类AutoConfigurationImportSelector中实现了ImportSelector定义的
org.springframework.context.annotation.ImportSelector#selectImports 【String[] selectImports(AnnotationMetadata importingClassMetadata)】),
selectImports返回了一系列的***AutoConfiguration配置类,例如org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,具体返回内容请查看动图一
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(EnableAutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { ... }
org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration 中通过注解 @ConditionalXXX 定义了创建bean的条件 ,
例如下面代码片段的 @ConditionalOnMissingBean(CharacterEncodingFilter.class)定义了当CharacterEncodingFilter类型的bean不存在才创建bean,当我们通过maven引入某个starter后(例如 spring-boot-starter-web),会匹配@Conditional定义的条件从而创建bean
@Configuration @EnableConfigurationProperties(HttpEncodingProperties.class) @ConditionalOnWebApplication @ConditionalOnClass(CharacterEncodingFilter.class) @ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true) public class HttpEncodingAutoConfiguration { private final HttpEncodingProperties properties; public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) { this.properties = properties; } @Bean @ConditionalOnMissingBean(CharacterEncodingFilter.class) public CharacterEncodingFilter characterEncodingFilter() { CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter(); filter.setEncoding(this.properties.getCharset().name()); filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST)); filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE)); return filter; } ... }
自动化配置类都有一个这样的注解@EnableConfigurationProperties ,例如 @EnableConfigurationProperties(HttpEncodingProperties.class) 来关联配置文件(application.yml或application.properties)的内容,可以打开这些类来看支持哪些配置项
一个简单的demo项目
下面贴出部分代码
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>lddxfs.springboot</groupId> <artifactId>springboot-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>springboot-demo</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.18.BUILD-SNAPSHOT</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!--<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> <!-- Provided --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.7</version> </dependency> <!-- <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency>--> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </repository> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> <pluginRepository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> </project>
入口类
package lddxfs.springboot.springbootdemo; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.transaction.annotation.EnableTransactionManagement; @SpringBootApplication @EnableTransactionManagement @MapperScan("lddxfs.springboot.springbootdemo.mapper") public class SpringbootDemoApplication { public static void main(String[] args) { SpringApplication.run(SpringbootDemoApplication.class, args); } }
yml
application: message: bootJSP spring: datasource: url: jdbc:mysql://localhost:3306/dubbostudy?useUnicode=true&characterEncoding=utf8 username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver mvc: view: prefix: /WEB-INF/jsp/ suffix: .jsp formcontent: putfilter: enabled: true http: encoding: charset: utf-8 force: true mybatis: mapper-locations: classpath*:mapper\\*.xml
使用外部tomcat运行(支持jsp)
package lddxfs.springboot.springbootdemo; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.support.SpringBootServletInitializer; /** * Author:lddxfs(lddxfs@qq.com;https://www.cnblogs.com/LDDXFS/) * Date:2018/10/24 * 使用外置tomcat */ public class DemoSpringBootServletInitializer extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(SpringbootDemoApplication.class); } }
监听器
package lddxfs.springboot.springbootdemo.web; /** * Author:lddxfs(lddxfs@qq.com;https://www.cnblogs.com/LDDXFS/) * Date:2018/10/24 */ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; /** * Author:lddxfs(lddxfs@qq.com;https://www.cnblogs.com/LDDXFS/) * Date:2018/10/23 */ public class DemoListener implements ServletContextListener, HttpSessionListener, HttpSessionAttributeListener { private static Logger log = LoggerFactory.getLogger(DemoListener.class); public DemoListener() { } // ------------------------------------------------------- // ServletContextListener implementation // ------------------------------------------------------- public void contextInitialized(ServletContextEvent sce) { /* This method is called when the servlet context is initialized(when the Web application is deployed). You can initialize servlet context related data here. */ log.info("容器启动了"); } public void contextDestroyed(ServletContextEvent sce) { /* This method is invoked when the Servlet Context (the Web application) is undeployed or Application Server shuts down. */ log.info("容器销毁了"); } // ------------------------------------------------------- // HttpSessionListener implementation // ------------------------------------------------------- public void sessionCreated(HttpSessionEvent se) { /* Session is created. */ log.info("Session创建了 sessionId:{}",se.getSession().getId()); } public void sessionDestroyed(HttpSessionEvent se) { /* Session is destroyed. */ log.info("Session销毁了 sessionId:{}",se.getSession().getId()); } // ------------------------------------------------------- // HttpSessionAttributeListener implementation // ------------------------------------------------------- public void attributeAdded(HttpSessionBindingEvent sbe) { /* This method is called when an attribute is added to a session. */ log.info("放入值到Session了 name:{}",sbe.getName()); } public void attributeRemoved(HttpSessionBindingEvent sbe) { /* This method is called when an attribute is removed from a session. */ log.info("Session移除值 name:{}",sbe.getName()); } public void attributeReplaced(HttpSessionBindingEvent sbe) { /* This method is invoked when an attibute is replaced in a session. */ log.info("Session修改值 name:{}",sbe.getName()); } }
过滤器
package lddxfs.springboot.springbootdemo.web; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; /** * Author:lddxfs(lddxfs@qq.com;https://www.cnblogs.com/LDDXFS/) * Date:2018/10/24 */ public class DemoFilter implements Filter { private static Logger log = LoggerFactory.getLogger(DemoFilter.class); @Override public void init(FilterConfig filterConfig) { log.info("DemoFilter.init()"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (request instanceof HttpServletRequest) { HttpServletRequest req = (HttpServletRequest) request; log.info("请求uri:{}", req.getRequestURI()); } chain.doFilter(request, response); } @Override public void destroy() { log.info("DemoFilter.destroy()"); } }
三大组件注册配置类
package lddxfs.springboot.springbootdemo.config; import lddxfs.springboot.springbootdemo.web.DemoFilter; import lddxfs.springboot.springbootdemo.web.DemoListener; import lddxfs.springboot.springbootdemo.web.DemoServlet; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletListenerRegistrationBean; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.HashSet; import java.util.Set; /** * Author:lddxfs(lddxfs@qq.com;https://www.cnblogs.com/LDDXFS/) * Date:2018/10/23 * web三大组件注册配置类 */ @Configuration public class WebBeanConfig { /** * 注册serlet * @return */ @Bean public ServletRegistrationBean servletRegistrationBean() { ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(); servletRegistrationBean.setServlet(new DemoServlet()); servletRegistrationBean.addUrlMappings("/testServletA"); return servletRegistrationBean; } /** * 注册filter * @return */ @Bean public FilterRegistrationBean filterRegistrationBean() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); filterRegistrationBean.setFilter(new DemoFilter()); filterRegistrationBean.setOrder(0); Set<String> urlPatterns = new HashSet<>(); urlPatterns.add("/*"); filterRegistrationBean.setUrlPatterns(urlPatterns); return filterRegistrationBean; } /** * 注册listener * @return */ @Bean public ServletListenerRegistrationBean servletListenerRegistrationBean() { ServletListenerRegistrationBean servletListenerRegistrationBean = new ServletListenerRegistrationBean(); servletListenerRegistrationBean.setListener(new DemoListener()); servletListenerRegistrationBean.setOrder(0); return servletListenerRegistrationBean; } }
异常处理
package lddxfs.springboot.springbootdemo.web; import lddxfs.springboot.springbootdemo.common.resutcode.Result; import org.springframework.boot.autoconfigure.web.DefaultErrorAttributes; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestAttributes; import java.util.LinkedHashMap; import java.util.Map; /** * Author:lddxfs(lddxfs@qq.com;https://www.cnblogs.com/LDDXFS/) * Date:2018/10/24 */ @Component public class DemoErrorAttribute extendsspringboot自动配置