SpringBoot自动化配置之一:SpringBoot内部的一些自动化配置原理
springboot用来简化Spring框架带来的大量XML配置以及复杂的依赖管理,让开发人员可以更加关注业务逻辑的开发。
比如不使用springboot而使用SpringMVC作为web框架进行开发的时候,需要配置相关的SpringMVC配置以及对应的依赖,比较繁琐;而使用springboot的话只需要以下短短的几行代码就可以使用SpringMVC,可谓相当地方便:
@RestControllerclassApp {@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 classFreeMarkerAutoConfiguration {private static final Log logger =LogFactory.getLog(FreeMarkerAutoConfiguration.class);@AutowiredprivateApplicationContext applicationContext;@AutowiredprivateFreeMarkerProperties properties;@PostConstruct//构造之后调用的方法,组要检查模板位置是否存在public voidcheckTemplateLocationExists() {if (this.properties.isCheckTemplateLocation()) {TemplateLocation templatePathLocation= null;List<TemplateLocation> locations = new ArrayList<TemplateLocation>();for (String templateLoaderPath : this.properties.getTemplateLoaderPath()) {TemplateLocation location= newTemplateLocation(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 classFreeMarkerConfiguration {@AutowiredprotectedFreeMarkerProperties properties;protected voidapplyProperties(FreeMarkerConfigurationFactory factory) {factory.setTemplateLoaderPaths(this.properties.getTemplateLoaderPath());factory.setPreferFileSystemAccess(this.properties.isPreferFileSystemAccess());factory.setDefaultEncoding(this.properties.getCharsetName());Properties settings= newProperties();settings.putAll(this.properties.getSettings());factory.setFreemarkerSettings(settings);}}@Configuration@ConditionalOnNotWebApplication//非Web项目的自动配置public static class FreeMarkerNonWebConfiguration extendsFreeMarkerConfiguration {@Bean@ConditionalOnMissingBeanpublicFreeMarkerConfigurationFactoryBean freeMarkerConfiguration() {FreeMarkerConfigurationFactoryBean freeMarkerFactoryBean= newFreeMarkerConfigurationFactoryBean();applyProperties(freeMarkerFactoryBean);returnfreeMarkerFactoryBean;}}@Configuration//自动配置的类@ConditionalOnClass(Servlet.class) //需要运行在Servlet容器下@ConditionalOnWebApplication //需要在Web项目下public static class FreeMarkerWebConfiguration extendsFreeMarkerConfiguration {@Bean@ConditionalOnMissingBean(FreeMarkerConfig.class)publicFreeMarkerConfigurer freeMarkerConfigurer() {FreeMarkerConfigurer configurer= newFreeMarkerConfigurer();applyProperties(configurer);returnconfigurer;}@Beanpublicfreemarker.template.Configuration freeMarkerConfiguration(FreeMarkerConfig configurer) {returnconfigurer.getConfiguration();}@Bean@ConditionalOnMissingBean(name= "freeMarkerViewResolver") //没有配置freeMarkerViewResolver这个bean的话,会自动构造一个freeMarkerViewResolver@ConditionalOnProperty(name = "spring.freemarker.enabled", matchIfMissing = true) //配置文件中开关开启的话,才会构造publicFreeMarkerViewResolver freeMarkerViewResolver() {//构造了freemarker的ViewSolver,这就是一开始我们分析的为什么没有设置ViewResolver,但是最后却还是存在的原因FreeMarkerViewResolver resolver = newFreeMarkerViewResolver();this.properties.applyToViewResolver(resolver);returnresolver;}} }
freemarker对应的配置类:
@ConfigurationProperties(prefix = "spring.freemarker") //使用配置文件中以spring.freemarker开头的配置 public class FreeMarkerProperties extendsAbstractTemplateViewResolverProperties {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 之下。
- DispatcherServletAutoConfiguration.class
- EmbeddedServletContainerAutoConfiguration.class
- ErrorMvcAutoConfiguration.class
- GsonHttpMessageConvertersConfiguration.class
- HttpEncodingAutoConfiguration.class
- HttpMessageConvertersAutoConfiguration.class
- JacksonHttpMessageConvertersConfiguration.class
- MultipartAutoConfiguration.class
- ServerPropertiesAutoConfiguration.class
- WebClientAutoConfiguration.class
- WebMvcAutoConfiguration.class
SpringBoot自动化配置之一:SpringBoot内部的一些自动化配置原理相关推荐
- 6 华为交换机 路由配置_华为路由、交换机基础配置指令
华为路由.交换机基础配置指令 一.华为路由器交换机配置命令:计算机命令 PCAlogin:root:使用root用户 password:linux:口令是linux #shutdown -h now: ...
- SpringBoot自动化配置之一:SpringBoot内部的一些自动化配置入门介绍
springboot用来简化Spring框架带来的大量XML配置以及复杂的依赖管理,让开发人员可以更加关注业务逻辑的开发. 比如不使用springboot而使用SpringMVC作为web框架进行开发 ...
- springboot项目中的注解 启动项目的方式 解决spring的bean.xml配置不生效 spring的基础JDBC配置
依赖 创建一个 Spring Boot 工程时,可以继承自一个 spring-boot-starter-parent ,也可以不继承 先来看 parent 的基本功能有哪些? 定义了 Java 编译版 ...
- React + Springboot + Quartz,从0实现Excel报表自动化
一.项目背景 企业日常工作中需要制作大量的报表,比如商品的销量.销售额.库存详情.员工打卡信息.保险报销.办公用品采购.差旅报销.项目进度等等,都需要制作统计图表以更直观地查阅.但是报表的制作往往需要 ...
- springboot 添加拦截器之后中文乱码_springboot中配置了拦截器后,拦截器无效的解决方案之一...
springboot的启动类xxxApplication不能扫描到拦截器配置类,可加上@ComponentScan(basePackages={"com.maya.common"} ...
- SpringBoot(十三)-- 不同环境下读取不同配置
一.场景: 在开发过程中 会使用 开发的一套数据库,测试的时候 又会使用测试的数据库,生产环境中 又会切换到生产环境中.常用的方式是 注释掉一些配置,然后释放一下配置.SpringBoot提供了在不同 ...
- properties类_受不了springboot的yml和properties配置,我扩展出了groovy配置
文中代码地址:https://github.com/gaohanghbut/groovy-configuration 起因 Springboot支持yml和properties两种方式的配置,不知道有 ...
- springboot 启动后打印_SpringBoot实战(五):配置健康检查与监控
强烈推荐一个大神的人工智能的教程:http://www.captainbed.net/zhanghan [前言] 众所周知,系统预警是一件十分重要的事情,系统一旦出现宕机很有可能许多真金白银就进去了: ...
- springboot系列六、springboot配置错误页面及全局异常
springboot系列六.springboot配置错误页面及全局异常 参考文章: (1)springboot系列六.springboot配置错误页面及全局异常 (2)https://www.cnbl ...
最新文章
- JavaScript DOM 高级程序设计读书笔记二
- css_position
- 【LeetCode1046】最后一块石头的重量(堆heap)
- ES启动异常:max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
- python可变对象与不可变对象_python 可变对象与不可变对象
- java cl 規格_Java JavaCL類代碼示例
- 时区之痒 - 从手机GPS模块获取的时间,真的是北京时间么?
- 毕设题目:Matlab手写或印刷数字字母识别
- SSM框架整合_1MyBatis搭建
- 快速入门(完整):Python练手经典实例100个 (让你的Python技能点全亮)
- VS2015卸载经过
- 关于sublime text4 和Google Chrome 的live reload插件
- linux 中hadoop相关命令学习
- Caused by: java.lang.IllegalStateException: Process 9461 exceeded cursor quota 100, will kill it
- 培养使用计算机的良好道德规范,浅谈如何提高学生学习信息技术的兴趣
- 读书笔记2014第6本:《The Hunger Games》
- Mstar 6A628 ubuntu 14.04 server Android 开发环境搭建
- 洛谷1852 BZOJ2144 跳跳棋 思维题
- greenplum创建外部表笔记-readable篇
- python plt图片保存emf类型_matplotlib---保存图片出现的问题