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-bootspring-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 之下。

注意,
① 这里是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
另外,还有一类文件:xxxProperties.class。这些文件都是 @ConfigurationProperties classes 。
在 @Configuration classes上可以使用 @EnableConfigurationProperties 进行 @ConfigurationProperties classes 的注入。 -- 也可以在@Configuration classes内部使用@Bean,略麻烦。

SpringBoot自动化配置之一:SpringBoot内部的一些自动化配置原理相关推荐

  1. 6 华为交换机 路由配置_华为路由、交换机基础配置指令

    华为路由.交换机基础配置指令 一.华为路由器交换机配置命令:计算机命令 PCAlogin:root:使用root用户 password:linux:口令是linux #shutdown -h now: ...

  2. SpringBoot自动化配置之一:SpringBoot内部的一些自动化配置入门介绍

    springboot用来简化Spring框架带来的大量XML配置以及复杂的依赖管理,让开发人员可以更加关注业务逻辑的开发. 比如不使用springboot而使用SpringMVC作为web框架进行开发 ...

  3. springboot项目中的注解 启动项目的方式 解决spring的bean.xml配置不生效 spring的基础JDBC配置

    依赖 创建一个 Spring Boot 工程时,可以继承自一个 spring-boot-starter-parent ,也可以不继承 先来看 parent 的基本功能有哪些? 定义了 Java 编译版 ...

  4. React + Springboot + Quartz,从0实现Excel报表自动化

    一.项目背景 企业日常工作中需要制作大量的报表,比如商品的销量.销售额.库存详情.员工打卡信息.保险报销.办公用品采购.差旅报销.项目进度等等,都需要制作统计图表以更直观地查阅.但是报表的制作往往需要 ...

  5. springboot 添加拦截器之后中文乱码_springboot中配置了拦截器后,拦截器无效的解决方案之一...

    springboot的启动类xxxApplication不能扫描到拦截器配置类,可加上@ComponentScan(basePackages={"com.maya.common"} ...

  6. SpringBoot(十三)-- 不同环境下读取不同配置

    一.场景: 在开发过程中 会使用 开发的一套数据库,测试的时候 又会使用测试的数据库,生产环境中 又会切换到生产环境中.常用的方式是 注释掉一些配置,然后释放一下配置.SpringBoot提供了在不同 ...

  7. properties类_受不了springboot的yml和properties配置,我扩展出了groovy配置

    文中代码地址:https://github.com/gaohanghbut/groovy-configuration 起因 Springboot支持yml和properties两种方式的配置,不知道有 ...

  8. springboot 启动后打印_SpringBoot实战(五):配置健康检查与监控

    强烈推荐一个大神的人工智能的教程:http://www.captainbed.net/zhanghan [前言] 众所周知,系统预警是一件十分重要的事情,系统一旦出现宕机很有可能许多真金白银就进去了: ...

  9. springboot系列六、springboot配置错误页面及全局异常

    springboot系列六.springboot配置错误页面及全局异常 参考文章: (1)springboot系列六.springboot配置错误页面及全局异常 (2)https://www.cnbl ...

最新文章

  1. JavaScript DOM 高级程序设计读书笔记二
  2. css_position
  3. 【LeetCode1046】最后一块石头的重量(堆heap)
  4. ES启动异常:max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
  5. python可变对象与不可变对象_python 可变对象与不可变对象
  6. java cl 規格_Java JavaCL類代碼示例
  7. 时区之痒 - 从手机GPS模块获取的时间,真的是北京时间么?
  8. 毕设题目:Matlab手写或印刷数字字母识别
  9. SSM框架整合_1MyBatis搭建
  10. 快速入门(完整):Python练手经典实例100个 (让你的Python技能点全亮)
  11. VS2015卸载经过
  12. 关于sublime text4 和Google Chrome 的live reload插件
  13. linux 中hadoop相关命令学习
  14. Caused by: java.lang.IllegalStateException: Process 9461 exceeded cursor quota 100, will kill it
  15. 培养使用计算机的良好道德规范,浅谈如何提高学生学习信息技术的兴趣
  16. 读书笔记2014第6本:《The Hunger Games》
  17. Mstar 6A628 ubuntu 14.04 server Android 开发环境搭建
  18. 洛谷1852 BZOJ2144 跳跳棋 思维题
  19. greenplum创建外部表笔记-readable篇
  20. python plt图片保存emf类型_matplotlib---保存图片出现的问题

热门文章

  1. 如何在WPF中调用Winform控件
  2. Android使用addView动态加载布局文件
  3. Sql Server Management Studio 18 打开闪退问题
  4. leetcode练习
  5. ES6 必须要用的数组Filter() 方法,不要再自己循环遍历了!!!
  6. Spring源码学习:day2
  7. U启动安装原版Win7系统教程
  8. 正则表达式-我在学习过程中研究过的
  9. 关于Vmware下NAT模式物理机无法ping通虚拟机但是可以上网的解决方法
  10. html 简单 在线编辑器 ie ff,一款垃圾中的极品HTML编辑器(兼容IE OR FF)