博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringBoot自动化配置之一:SpringBoot内部的一些自动化配置原理
阅读量:6198 次
发布时间:2019-06-21

本文共 11547 字,大约阅读时间需要 38 分钟。

springboot用来简化Spring框架带来的大量XML配置以及复杂的依赖管理,让开发人员可以更加关注业务逻辑的开发。

比如不使用springboot而使用SpringMVC作为web框架进行开发的时候,需要配置相关的SpringMVC配置以及对应的依赖,比较繁琐;而使用springboot的话只需要以下短短的几行代码就可以使用SpringMVC,可谓相当地方便:

@RestControllerclass App {  @RequestMapping("/")  String home() {    "hello"  }}

其中maven配置如下:

org.springframework.boot
spring-boot-starter-parent
1.3.5.RELEASE
org.springframework.boot
spring-boot-starter-web

我们以使用SpringMVC并且视图使用freemarker为例,分析springboot内部是如何解析freemarker视图的。

如果要在springboot中使用freemarker视图框架,并且使用maven构建项目的时候,还需要加入以下依赖:

org.springframework.boot
spring-boot-starter-freemarker
1.3.5.RELEASE

这个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里需要的依赖如下:

org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-web
org.freemarker
freemarker
org.springframework
spring-context-support

我们可以看到这个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配置:

org.springframework.boot
spring-boot-starter-parent
1.3.5.RELEASE

这个spring-boot-starter-parent的pom文件在 里。

它内部也有一个parent:

org.springframework.boot
spring-boot-dependencies
1.3.5.RELEASE
../../spring-boot-dependencies

这个spring-boot-dependencies的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 class FreeMarkerAutoConfiguration {    private static final Log logger = LogFactory            .getLog(FreeMarkerAutoConfiguration.class);    @Autowired    private ApplicationContext applicationContext;    @Autowired    private FreeMarkerProperties properties;    @PostConstruct // 构造之后调用的方法,组要检查模板位置是否存在    public void checkTemplateLocationExists() {        if (this.properties.isCheckTemplateLocation()) {            TemplateLocation templatePathLocation = null;            List
locations = new ArrayList
(); 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 { @Autowired protected 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 @ConditionalOnMissingBean public 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; } @Bean public 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提供的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
另外,还有一类文件:xxx
Properties.class。这些文件都是 
@ConfigurationProperties classes 。
在 
@Configuration classes上可以使用 
@EnableConfigurationProperties 进行 
@ConfigurationProperties classes 的注入。 -- 也可以在
@Configuration classes内部使用
@Bean,略麻烦。

转载地址:http://kbjca.baihongyu.com/

你可能感兴趣的文章
Visual Studio添加dll程序集引用操作步骤
查看>>
Linux系统VNC配置实践总结
查看>>
匿名函数的代码模式
查看>>
swat主流域文件(file.cio)参数详解——引自http://blog.sciencenet.cn/blog-922140-710636.html...
查看>>
马云成功的九大秘籍--这个真的值得学学!
查看>>
IE6不支持CSS的属性选择器
查看>>
怎么让一个div 悬浮在另一个div上
查看>>
回溯法 子集树和排序树
查看>>
根级别上的数据无效。 行 1,位置 1
查看>>
[Unity2D]实现背景的移动
查看>>
5天学会jaxws-webservice编程第一天
查看>>
不常用但很有用的git show 和 git blame
查看>>
SQLLoader2(导入EXCEL或csv格式的文件)
查看>>
微信公众平台开发(105) 分享到朋友圈和发送给好友
查看>>
[Leetcode] Regular Expression Matching
查看>>
sublime配置全攻略
查看>>
移动互联网实战--wifi定位和架构
查看>>
WorldWind源码剖析系列:数学引擎类MathEngine
查看>>
初学Flask(1)
查看>>
java基础复习 - 自动装箱
查看>>