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

摘要:
Spring boot用于简化Spring框架带来的大量XML配置和复杂的依赖关系管理,以便开发人员更加关注业务逻辑的开发。接下来,让我们分析一下为什么在将Spring-bootstarter freemarker依赖项添加到Spring-boot之后,Spring-MVC会自动构造一个freemarker ViewResolver?在分析之前,让我们先看看maven配置并查看父配置:<parent><groupId>org。弹簧框架。boot</groupId><artifactId>spring boot start part</artifactId><version>1.3.5.RELEASE</version></part>spring bootstart part的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锂。

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
SpringBoot自动化配置之一:SpringBoot内部的一些自动化配置入门介绍第1张

如上图,内部的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等等。

包括了这些包:

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

spring-boot-autoconfigure定义了很多自动配置的类,比如jpa,solr,redis,elasticsearch、mongo、freemarker、velocity,thymeleaf等等自动配置的类。

SpringBoot自动化配置之一:SpringBoot内部的一些自动化配置入门介绍第3张

以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<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 {

        @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的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 之下,该包中的内容如下:
SpringBoot自动化配置之一:SpringBoot内部的一些自动化配置入门介绍第4张
从上图中可以清楚的看到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内部的一些自动化配置入门介绍》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Mysql常见报错解决方法centos 安装 apache2.4下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Struts 2.x仍然明显落后于时代。 Struts 2.x这一类老牌Web MVC开发框架仅能用于开发瘦客户端应用,无法用来开发对于交互体验要求更高的应用。

后来我在工作中陆续使用过Struts 1.x和Struts 2.x。我曾经把一个开源的基于Struts 1.x的自助式广告联盟应用移植到Spring MVC,还基于Struts 2.x做过网站开发。Struts 1.x的主要问题是框架的侵入性太大,不利于代码重用和单元测试。Struts 2.x确实进步很大,完全基于POJO,学习曲线低了很多,还支持零配置(...

Spring框架系列(五)--Spring AOP以及实现用户登录权限控制

背景:   当需要为多个不具有继承关系的对象引入一个公共行为,例如日志、权限验证、事务等功能时。如果使用OOP,需要为每个Bean引入这些公共 行为。会产生大量重复代码,并且不利用维护,AOP就是为了解决这个问题。 AOP:   就是上面的解释,可以理解一种思想,不是Java独有的,作用是对方法进行拦截处理或增强处理。而在Java中我们使用Spring...

spring-session之一:简介、使用及实现原理

一、背景 http session(企业)一直都是我们做集群时需要解决的一个难题,我们知道HttpSession是通过Servlet容器创建和管理的,像Tomcat/Jetty都是保存在内存中的。而如果我们把web服务器搭建成分布式的集群,然后利用LVS或Nginx做负载均衡,那么来自同一用户的Http请求将有可能被分发到两个不同的web站点中去。那么问题...

微服务技术选型之路

    本文以笔者个人经历讲述关于微服务方面的技术选型和相关知识点。微服务模式的项目从初建到上线部署应用,每一个环节都会涉及到相当多的技术细节(上线后的性能调优更需要)。本文着重介绍一套微服务搭建流程中面临的一些技术选型,战略性的技术方案及相关技术的简要介绍,不做每一项技术的深入说明。  微服务简介     微服务是指开发一个单个小型的但有业务功能的服务,...

带你一行一行分析SpringBoot原码解析

一.说明  1.本次源码解析是基于2.3.3.RELEASE版本的  2.本文主要分析Spring的自动配置 二.原码分析 1.创建一个普通的springboot项目如下:  只有一个配置文件和一个启动类。 配置文件中只配了一个redis,配置其他组件都行,这里以redis为例展开说明自动注入。 2.打开启动类 对于springboot来说,最强大的地...

eclipse+maven+ssm框架搭建

eclipse+maven+ssm框架 0、系统环境 1)Windows 10 企业版 2)JDK 1.8.0_131 3)Eclipse Java EE IDE for Web Developers  Version: Neon.3 Release (4.6.3) 4)Tomcat 8.5 1、maven下载及配置 maven的下载地址:http:...