javascript
SpringBoot自动化配置之一:SpringBoot内部的一些自动化配置原理
springboot用來簡化Spring框架帶來的大量XML配置以及復雜的依賴管理,讓開發人員可以更加關注業務邏輯的開發。
比如不使用springboot而使用SpringMVC作為web框架進行開發的時候,需要配置相關的SpringMVC配置以及對應的依賴,比較繁瑣;而使用springboot的話只需要以下短短的幾行代碼就可以使用SpringMVC,可謂相當地方便:
@RestController class App {@RequestMapping("/")String home() {"hello"} }其中maven配置如下:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.3.5.RELEASE</version> </parent> <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency> </dependencies>我們以使用SpringMVC并且視圖使用freemarker為例,分析springboot內部是如何解析freemarker視圖的。
如果要在springboot中使用freemarker視圖框架,并且使用maven構建項目的時候,還需要加入以下依賴:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId><version>1.3.5.RELEASE</version> </dependency>這個spring-boot-starter-freemarker依賴對應的jar包里的文件如下:
META-INF ├── MANIFEST.MF ├── maven │ └── org.springframework.boot │ └── spring-boot-starter-freemarker │ ├── pom.properties │ └── pom.xml └── spring.provides如上圖,內部的pom.xml里需要的依賴如下:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId> </dependency> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId> </dependency> <dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId> </dependency>我們可以看到這個spring-boot-starter-freemarker依賴內部并沒有freemarker的ViewResolver,而是僅僅加入了freemarker的依賴,還有3個依賴,分別是spring-boot-starter、spring-boot-starter-web和spring-context-support。
接下來我們來分析一下為什么在springboot中加入了freemarker的依賴spring-boot-starter-freemarker后,SpringMVC自動地構造了一個freemarker的ViewResolver?
在分析之前,首先我們先看下maven配置,看到了一個parent配置:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.3.5.RELEASE</version> </parent>這個spring-boot-starter-parent的pom文件在http://central.maven.org/maven2/org/springframework/boot/spring-boot-starter-parent/1.3.5.RELEASE/spring-boot-starter-parent-1.3.5.RELEASE.pom?里。
它內部也有一個parent:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>1.3.5.RELEASE</version><relativePath>../../spring-boot-dependencies</relativePath> </parent>這個spring-boot-dependencies的pom文件在http://central.maven.org/maven2/org/springframework/boot/spring-boot-dependencies/1.3.5.RELEASE/spring-boot-dependencies-1.3.5.RELEASE.pom,內部有很多依賴。
比如spring-boot-starter-web、spring-boot-starter-websocket、spring-boot-starter-data-solrspring-boot-starter-freemarker等等,基本上所有的依賴都在這個parent里。
我們的例子中使用了parent依賴里的兩個依賴,分別是spring-boot-starter-web和spring-boot-starter-freemarker。
其中spring-boot-starter-web內部依賴了spring的兩個spring web依賴:spring-web和spring-webmvc。
spring-boot-starter-web內部還依賴spring-boot-starter,這個spring-boot-starter依賴了spring核心依賴spring-core;還依賴了spring-boot和spring-boot-autoconfigure這兩個。
spring-boot定義了很多基礎功能類,像運行程序的SpringApplication,Logging系統,一些tomcat或者jetty這些EmbeddedServlet容器,配置屬性loader等等。
包括了這些包:
spring-boot-autoconfigure定義了很多自動配置的類,比如jpa,solr,redis,elasticsearch、mongo、freemarker、velocity,thymeleaf等等自動配置的類。
以freemarker為例,看一下它的自動化配置類:
@Configuration // 使用Configuration注解,自動構造一些內部定義的bean @ConditionalOnClass({ freemarker.template.Configuration.class,FreeMarkerConfigurationFactory.class }) // 需要freemarker.template.Configuration和FreeMarkerConfigurationFactory這兩個類存在在classpath中才會進行自動配置 @AutoConfigureAfter(WebMvcAutoConfiguration.class) // 本次自動配置需要依賴WebMvcAutoConfiguration這個配置類配置之后觸發。這個WebMvcAutoConfiguration內部會配置很多Wen基礎性的東西,比如RequestMappingHandlerMapping、RequestMappingHandlerAdapter等 @EnableConfigurationProperties(FreeMarkerProperties.class) // 使用FreeMarkerProperties類中的配置 public class FreeMarkerAutoConfiguration {private static final Log logger = LogFactory.getLog(FreeMarkerAutoConfiguration.class);@Autowiredprivate ApplicationContext applicationContext;@Autowiredprivate FreeMarkerProperties properties;@PostConstruct // 構造之后調用的方法,組要檢查模板位置是否存在public void checkTemplateLocationExists() {if (this.properties.isCheckTemplateLocation()) {TemplateLocation templatePathLocation = null;List<TemplateLocation> locations = new ArrayList<TemplateLocation>();for (String templateLoaderPath : this.properties.getTemplateLoaderPath()) {TemplateLocation location = new TemplateLocation(templateLoaderPath);locations.add(location);if (location.exists(this.applicationContext)) {templatePathLocation = location;break;}}if (templatePathLocation == null) {logger.warn("Cannot find template location(s): " + locations+ " (please add some templates, "+ "check your FreeMarker configuration, or set "+ "spring.freemarker.checkTemplateLocation=false)");}}}protected static class FreeMarkerConfiguration {@Autowiredprotected FreeMarkerProperties properties;protected void applyProperties(FreeMarkerConfigurationFactory factory) {factory.setTemplateLoaderPaths(this.properties.getTemplateLoaderPath());factory.setPreferFileSystemAccess(this.properties.isPreferFileSystemAccess());factory.setDefaultEncoding(this.properties.getCharsetName());Properties settings = new Properties();settings.putAll(this.properties.getSettings());factory.setFreemarkerSettings(settings);}}@Configuration@ConditionalOnNotWebApplication // 非Web項目的自動配置public static class FreeMarkerNonWebConfiguration extends FreeMarkerConfiguration {@Bean@ConditionalOnMissingBeanpublic FreeMarkerConfigurationFactoryBean freeMarkerConfiguration() {FreeMarkerConfigurationFactoryBean freeMarkerFactoryBean = new FreeMarkerConfigurationFactoryBean();applyProperties(freeMarkerFactoryBean);return freeMarkerFactoryBean;}}@Configuration // 自動配置的類@ConditionalOnClass(Servlet.class) // 需要運行在Servlet容器下@ConditionalOnWebApplication // 需要在Web項目下public static class FreeMarkerWebConfiguration extends FreeMarkerConfiguration {@Bean@ConditionalOnMissingBean(FreeMarkerConfig.class)public FreeMarkerConfigurer freeMarkerConfigurer() {FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();applyProperties(configurer);return configurer;}@Beanpublic freemarker.template.Configuration freeMarkerConfiguration(FreeMarkerConfig configurer) {return configurer.getConfiguration();}@Bean@ConditionalOnMissingBean(name = "freeMarkerViewResolver") // 沒有配置freeMarkerViewResolver這個bean的話,會自動構造一個freeMarkerViewResolver@ConditionalOnProperty(name = "spring.freemarker.enabled", matchIfMissing = true) // 配置文件中開關開啟的話,才會構造public FreeMarkerViewResolver freeMarkerViewResolver() {// 構造了freemarker的ViewSolver,這就是一開始我們分析的為什么沒有設置ViewResolver,但是最后卻還是存在的原因FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();this.properties.applyToViewResolver(resolver);return resolver;}} }freemarker對應的配置類:
@ConfigurationProperties(prefix = "spring.freemarker") // 使用配置文件中以spring.freemarker開頭的配置 public class FreeMarkerProperties extends AbstractTemplateViewResolverProperties {public static final String DEFAULT_TEMPLATE_LOADER_PATH = "classpath:/templates/"; // 默認路徑public static final String DEFAULT_PREFIX = ""; // 默認前綴public static final String DEFAULT_SUFFIX = ".ftl"; // 默認后綴 ...}下面是官網上的freemarker配置:
# FREEMARKER (FreeMarkerAutoConfiguration) spring.freemarker.allow-request-override=false # Set whether HttpServletRequest attributes are allowed to override (hide) controller generated model attributes of the same name. spring.freemarker.allow-session-override=false # Set whether HttpSession attributes are allowed to override (hide) controller generated model attributes of the same name. spring.freemarker.cache=false # Enable template caching. spring.freemarker.charset=UTF-8 # Template encoding. spring.freemarker.check-template-location=true # Check that the templates location exists. spring.freemarker.content-type=text/html # Content-Type value. spring.freemarker.enabled=true # Enable MVC view resolution for this technology. spring.freemarker.expose-request-attributes=false # Set whether all request attributes should be added to the model prior to merging with the template. spring.freemarker.expose-session-attributes=false # Set whether all HttpSession attributes should be added to the model prior to merging with the template. spring.freemarker.expose-spring-macro-helpers=true # Set whether to expose a RequestContext for use by Spring's macro library, under the name "springMacroRequestContext". spring.freemarker.prefer-file-system-access=true # Prefer file system access for template loading. File system access enables hot detection of template changes. spring.freemarker.prefix= # Prefix that gets prepended to view names when building a URL. spring.freemarker.request-context-attribute= # Name of the RequestContext attribute for all views. spring.freemarker.settings.*= # Well-known FreeMarker keys which will be passed to FreeMarker's Configuration. spring.freemarker.suffix= # Suffix that gets appended to view names when building a URL. spring.freemarker.template-loader-path=classpath:/templates/ # Comma-separated list of template paths. spring.freemarker.view-names= # White list of view names that can be resolved.所以說一開始我們加入了一個spring-boot-starter-freemarker依賴,這個依賴中存在freemarker的lib,滿足了FreeMarkerAutoConfiguration中的ConditionalOnClass里寫的freemarker.template.Configuration.class這個類存在于classpath中。
所以就構造了FreeMarkerAutoConfiguration里的ViewResolver,這個ViewResolver被自動加入到SpringMVC中。
同樣地,如果我們要使用velocity模板,springboot內部也有velocity的自動配置類VelocityAutoConfiguration,原理是跟freemarker一樣的。
其他:
Mybatis的autoconfigure是Mybatis提供的springboot的自動配置模塊,由于springboot官方沒有提供mybatis的自動化配置模塊,所以mybatis自己寫了這么一個模塊,觀察它的源碼,發現基本上跟freemarker的autoconfigure模塊一樣,只需要構造對應的實例即可。
總結:
springboot內部提供了很多自動化配置的類,這些類會判斷classpath中是否存在自己需要的那個類,如果存在則會自動配置相關的配置,否則就不會自動配置。
如果我們需要使用一些框架,只需要加入依賴即可,這些依賴內部是沒有代碼的,只是一些對應框架需要的lib,有了這些lib就會觸發自動化配置,于是就能使用框架了。
這一點跟當時看springmvc的時候對response進行json或xml渲染的原理相同。springmvc中的requestmapping注解加上responsebody注解后會返回xml或者json,如果依賴中加入jackson依賴就會轉換成json,如果依賴中加入xstream依賴就會轉換成xml。當然,前提是springmvc中有了這兩種依賴的HttpMessageConverter代碼,這個HttpMessageConverter代碼就相當于springboot中的各種AutoConfiguration。
Spring Boot提供的自動配置
Spring Boot提供的自動配置都是位于包?org.springframework.boot.autoconfigure?之下。
注意, ① 這里是Spring Boot提供的,而非第三方(如MyBatis-Spring-Boot-Starter)提供的。 ② 不包含Spring Boot Actuator部分的。?Spring Boot的自動配置類可以通過autoconfig report查看,需要開啟?--debug?或?-Debug?;蛘咴?Actuator 項目的autoconfig 端點查看。 這里先從Web開始學習
由于Spring Boot的web Starter集成了Spring MVC,而非其他,所以實際上提供的Web自動配置為Spring MVC的自動配置。 Spring MVC的自動配置在包?org.springframework.boot.autoconfigure.web?之下,該包中的內容如下:
?
從上圖中可以清楚的看到Spring Boot為Spring MVC提供了哪些自動配置:
- DispatcherServletAutoConfiguration.class
- EmbeddedServletContainerAutoConfiguration.class
- ErrorMvcAutoConfiguration.class
- GsonHttpMessageConvertersConfiguration.class
- HttpEncodingAutoConfiguration.class
- HttpMessageConvertersAutoConfiguration.class
- JacksonHttpMessageConvertersConfiguration.class
- MultipartAutoConfiguration.class
- ServerPropertiesAutoConfiguration.class
- WebClientAutoConfiguration.class
- WebMvcAutoConfiguration.class
總結
以上是生活随笔為你收集整理的SpringBoot自动化配置之一:SpringBoot内部的一些自动化配置原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 阿维塔 12 通过工信部申报:品牌首款中
- 下一篇: 荣耀X50已经正式开售 配5800mAh