GVKun编程网logo

Spring Boot 的自动配置,到底是怎么做到?(spring boot自动化配置)

23

本文将介绍SpringBoot的自动配置,到底是怎么做到?的详细情况,特别是关于springboot自动化配置的相关信息。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉

本文将介绍Spring Boot 的自动配置,到底是怎么做到?的详细情况,特别是关于spring boot自动化配置的相关信息。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关于DIY一个Spring Boot的自动配置、Idea 打包maven项目 以及spring boot 的自动配置、Spring Boot 中自定义 SpringMVC 配置,到底继承谁?、Spring Boot 关闭特定的自动配置的知识。

本文目录一览:

Spring Boot 的自动配置,到底是怎么做到?(spring boot自动化配置)

Spring Boot 的自动配置,到底是怎么做到?(spring boot自动化配置)


链接:juejin.im/post/5b679fbc5188251aad213110

SpringBoot 的故事从一个面试题开始

Spring Boot、Spring MVC 和 Spring 有什么区别?

先来个 SpringBoot 的启动结构图

分开描述各自的特征

Spring 框架就像一个家族,有众多衍生产品例如 boot、security、jpa等等。但他们的基础都是Spring 的ioc和 aop,ioc 提供了依赖注入的容器, aop解决了面向横切面的编程,然后在此两者的基础上实现了其他延伸产品的高级功能。

Spring MVC提供了一种轻度耦合的方式来开发web应用。它是Spring的一个模块,是一个web框架。通过Dispatcher Servlet, ModelAndView 和 View Resolver,开发web应用变得很容易。解决的问题领域是网站应用程序或者服务开发——URL路由、Session、模板引擎、静态Web资源等等。

Spring Boot实现了自动配置,降低了项目搭建的复杂度。它主要是为了解决使用Spring框架需要进行大量的配置太麻烦的问题,所以它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具。同时它集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用(out-of-the-box)。

Tips:关注微信公众号:Java后端,每日技术博文推送。

所以,用最简练的语言概括就是

. Spring 是一个“引擎”;
. Spring MVC 是基于Spring的一个 MVC 框架;
. Spring Boot 是基于Spring4的条件注册的一套快速开发整合包。

SpringBoot到底是怎么做到自动配置的?

从代码里看项目SpringBoot的项目启动类只有一个注解@SpringBootApplication和一个run方法。

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
直接看@SpringBootApplication的代码:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    Class<?>[] exclude() default {};

    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    String[] excludeName() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackages"
    )
    String[] scanBasePackages() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackageClasses"
    )
    Class<?>[] scanBasePackageClasses() default {};
}
@SpringBootApplication:包含了@SpringBootConfiguration(打开是@Configuration),@EnableAutoConfiguration,@ComponentScan注解。

@Configuration

JavaConfig形式的Spring Ioc容器的配置类使用的那个@Configuration,SpringBoot社区推荐使用基于JavaConfig的配置形式,所以,这里的启动类标注了@Configuration之后,本身其实也是一个IoC容器的配置类。
对比一下传统XML方式和config配置方式的区别:

XML声明和定义配置方式

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
  xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-3.0.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
  ">
  <bean id="app" class="com..." />

用一个过滤器举例,JavaConfig的配置方式是这样

@Configuration
public class DruidConfiguration {
    @Bean
    public FilterRegistrationBean statFilter(){
        //创建过滤器
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
        //设置过滤器过滤路径
        filterRegistrationBean.addUrlPatterns("/*");
        //忽略过滤的形式
        filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return filterRegistrationBean;
    }
}
任何一个标注了@Configuration的Java类定义都是一个JavaConfig配置类。
任何一个标注了@Bean的方法,其返回值将作为一个bean定义注册到Spring的IoC容器,方法名将默认成该bean定义的id。

@ComponentScan

@ComponentScan对应XML配置中的元素,@ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中。
我们可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。
注:所以SpringBoot的启动类最好是放在rootpackage下,因为默认不指定basePackages。

@EnableAutoConfiguration

核心内容)看英文意思就是自动配置,概括一下就是,借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}
里面最关键的是@Import(EnableAutoConfigurationImportSelector.class),借助EnableAutoConfigurationImportSelector,@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。该配置模块的主要使用到了SpringFactoriesLoader。

SpringFactoriesLoader详解

SpringFactoriesLoader为Spring工厂加载器,该对象提供了loadFactoryNames方法,入参为factoryClass和classLoader即需要传入工厂类名称和对应的类加载器,方法会根据指定的classLoader,加载该类加器搜索路径下的指定文件,即spring.factories文件,传入的工厂类为接口,而文件中对应的类则是接口的实现类,或最终作为实现类。
public abstract class SpringFactoriesLoader {
    //...
    public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {
        ...
    }
    public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        ....
    }
}
所以文件中一般为如下图这种一对多的类名集合,获取到这些实现类的类名后,loadFactoryNames方法返回类名集合,方法调用方得到这些集合后,再通过反射获取这些类的类对象、构造方法,最终生成实例。
下图有助于我们形象理解自动配置流程(盗个图)

AutoConfigurationImportSelector

继续上面讲的AutoConfigurationImportSelector.class。该类主要关注selectImports方法
public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.filter(configurations, autoConfigurationMetadata);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return StringUtils.toStringArray(configurations);
        }
    }
该方法在springboot启动流程——bean实例化前被执行,返回要实例化的类信息列表。如果获取到类信息,spring可以通过类加载器将类加载到jvm中,现在我们已经通过spring-boot的starter依赖方式依赖了我们需要的组件,那么这些组件的类信息在select方法中就可以被获取到。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }
方法中的getCandidateConfigurations方法,其返回一个自动配置类的类名列表,方法调用了loadFactoryNames方法,查看该方法
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }
自动配置器会跟根据传入的factoryClass.getName()到项目系统路径下所有的spring.factories文件中找到相应的key,从而加载里面的类。我们就选取这个mybatis-spring-boot-autoconfigure下的spring.factories文件
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
进入org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration中,又是一堆注解
@org.springframework.context.annotation.Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnBean({DataSource.class})
@EnableConfigurationProperties({MybatisProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class})
public class MybatisAutoConfiguration
{
  private static final Logger logger = LoggerFactory.getLogger(MybatisAutoConfiguration.class);
  private final MybatisProperties properties;
  private final Interceptor[] interceptors;
  private final ResourceLoader resourceLoader;
  private final DatabaseIdProvider databaseIdProvider;
  private final List<ConfigurationCustomizer> configurationCustomizers;
. @Spring的Configuration是一个通过注解标注的springBean,. @ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class})这个注解的意思是:当存在SqlSessionFactory.class, SqlSessionFactoryBean.class这两个类时才解析MybatisAutoConfiguration配置类,否则不解析这一个配置类。我们需要mybatis为我们返回会话对象,就必须有会话工厂相关类. @CondtionalOnBean(DataSource.class):只有处理已经被声明为bean的dataSource. @ConditionalOnMissingBean(MapperFactoryBean.class)这个注解的意思是如果容器中不存在name指定的bean则创建bean注入,否则不执行 以上配置可以保证sqlSessionFactory、sqlSessionTemplate、dataSource等mybatis所需的组件均可被自动配置,@Configuration注解已经提供了Spring的上下文环境,所以以上组件的配置方式与Spring启动时通过mybatis.xml文件进行配置起到一个效果。
只要一个基于SpringBoot项目的类路径下存在SqlSessionFactory.class, SqlSessionFactoryBean.class,并且容器中已经注册了dataSourceBean,就可以触发自动化配置 ,意思说我们 只要在maven的项目中加入了mybatis所需要的若干依赖,就可以触发自动配置 ,但引入mybatis原生依赖的话,每集成一个功能都要去修改其自动化配置类,那就得不到开箱即用的效果了。所以Spring-boot为我们提供了统一的starter可以直接配置好相关的类,触发自动配置所需的依赖(mybatis)如下:
<dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
因为maven依赖的传递性,我们只要依赖starter就可以依赖到所有需要自动配置的类,实现开箱即用的功能。也体现出Springboot简化了Spring框架带来的大量XML配置以及复杂的依赖管理,让开发人员可以更加关注业务逻辑的开发。

- End -


Maven系列教程  点击--> Maven技术干货连载目录 跳转


MyBatis系列教程  点击--> MyBatis技术干货连载目录 跳转


JVM调优总结系列教程  点击--> JVM调优技术干货连载目录 跳转





, 

本文分享自微信公众号 - 程序员书单(CoderBooklist)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

DIY一个Spring Boot的自动配置

DIY一个Spring Boot的自动配置

按:最近公众号文章主要是整理一些老文章,以个人CSDN上的博客为主,也会穿插一些新的技术点。


在上篇博客初识Spring Boot框架中我们初步见识了SpringBoot的方便之处,很多小伙伴可能也会好奇这个Spring Boot是怎么实现自动配置的,那么今天我就带小伙伴我们自己来实现一个简单的Spring Boot 自动配置的案例,看看这一切到底是怎么发生的。
假设我的需求是这样的:当我的项目中存在某个类的时候,系统自动为我配置该类的Bean,同时,我这个Bean的属性还可以在application.properties中进行配置,OK,就这样一个需求,我们来看看怎么实现。

  1. 新建starter的Maven项目

我这里以IntelliJ IDEA创建Project为例,其实很简单,创建一个Maven项目,但是注意创建的时候选择quickstart,步骤如下:




OK,这样我们就创建好一个Project了。
2.添加依赖

由于我们要使用Spring Boot的自动配置功能,所以在工程创建成功之后首先要添加Spring Boot自身的自动配置作为依赖,如下:

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
      <version>1.4.2.RELEASE</version>
    </dependency>

3.属性配置

@ConfigurationProperties(prefix = "hello")
public class HelloServiceProperties {
    private static final String MSG = "world";
    private String msg = MSG;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

这里就是一个简单的类,和上篇博客中我们提到的 类型安全的属性获取是一致的,这里属性的值我们可以在application.properties中来直接设置,如果不设置的话默认为world。
4.判断依据类

public class HelloService {
    private String msg;
    public String sayHello(){
        return "hello " + msg;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

我们一会的例子就是根据这个类是否存在来创建这个类的Bean,当然这个类也可以是第三方类库。
5.自动配置类

@Configuration
@EnableConfigurationProperties(HelloServiceProperties.class)
@ConditionalOnClass(HelloService.class)
@ConditionalOnProperty(prefix = "hello",value = "enable",matchIfMissing = true)
public class HelloServiceAutoConfiguration {
    @Autowired
    private HelloServiceProperties helloServiceProperties;
    @Bean
    public HelloService helloService() {
        HelloService helloService = new HelloService();
        helloService.setMsg(helloServiceProperties.getMsg());
        return helloService;
    }
}

这里@ConditionalOnClass注解主要是用来判断HelloService这个类在路径中是否存在,在存在且容器中没有该类的Bean的情况下系统会自动配置需要的Bean,@ConditionalOnProperty注解则表示指定的属性要满足的条件,在helloService方法中我们则使用了HelloServiceProperties提供的参数。
6.注册配置

在resources目录下新建META-INF目录,然后在META-INF目录下创建spring.factories文件,文件内容如下,表示设置自动配置类的位置,若有多个配置类用”,”隔开即可。:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.sang.HelloServiceAutoConfiguration

正常情况下我们按步骤一创建出来的Project是没有resources这个文件夹的,在IntelliJ IDEA这个工具中,我们需要先创建一个directory,然后将之设置为resources root即可,设置方式如下:选中resources目录右键单击—》Mark Directory as—》Resource Root。
7.在项目中使用

OK,经过上面几个步骤我们的自动配置功能就算死写好了,接下来我们要在自己的项目中来使用它了,正常情况下做好自动配置类之后我们需要将之上传到
maven 私服上然后直接在项目中引用,也可以将之安装到本地库,这里我选择后者的一个简化方式,直接创建Module来引用这个自动配置Module(如果小伙伴是用STS或者MyEclipse之类的开发工具直接创建新工程然后添加引用类库即可)。
创建Module方式很简单,选中刚才的Project右键单击,New一个Module,这个Module是一个SpringBoot项目(不清楚怎么创建SpringBoot项目可以查看这篇文章初识Spring Boot框架),创建成功之后选择新建的Module按F4打开Module设置,然后选择右边的加号添加依赖,如下:

然后在新建Module的pom.xml文件中添加如下依赖:

<dependency>
            <groupId>org.sang</groupId>
            <artifactId>org.sang.mystarter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

实际上就是我们刚刚创建的自动配置文件的坐标。然后新Module的入口类中添加如下代码:

@Autowired
    private HelloService helloService;

    @RequestMapping("/")
    public String index(){
        return helloService.sayHello();
    }

使用刚刚创建的HelloService,如果需要我们可以在application.properties中添加如下配置:

hello.msg = 卖花担上看桃李, 拍酒楼头听管弦。

运行Module,然后在浏览器中访问,结果如下:

.

OK,这就是一个简单的自定义自动配置类。

本案例下载地址:

本案例GitHub地址  https://github.com/lenve/JavaEETest/tree/master/Test19-MyStarter

以上。

参考资料:
《JavaEE开发的颠覆者 Spring Boot实战》第六章


本文分享自微信公众号 - 江南一点雨(a_javaboy)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

Idea 打包maven项目 以及spring boot 的自动配置

Idea 打包maven项目 以及spring boot 的自动配置

1.打包maven项目

1. 选中Java项目工程名称,在菜单中选择 File->project structure... (快捷键Ctrl+Alt+Shift+S)。

2.在弹出的窗口中左侧选中"Artifacts",点击"+"选择jar,然后选择"from modules with dependencies"。

3.在配置窗口中配置"Main Class"。选择“Main Class”后配置“Directory for META-INF/MAINFEST.MF”,本文中选择的项目根目录,配置完成后如下图所示,点击OK进入下一步。

4.在弹出的窗体中选中"Build On make "(make 项目的时候会自动输出jar)

 5.以上的步骤就完成了编译时生成Jar包的配置,然后在菜单中选择Build->make project 。

 

6.build success 后,去该项目的out文件夹内查找本项目的jar包

OK,jar打好,下面才是重头戏:

首先说下这个jar包的用处:自动获取当前项目的属性值(仅是测试,功能、业务性不强)

 

接下来,如何实现呢? 这里要了解spring boot条件注解这个概念,有如下注解形式:

                                      

@ConditionalOnBean 当容器里有指定的Bean的条件下                                                                                         
@ConditionalOnClass   当类路径下有指定的class的条件下
@ConditionalOnExpression 基于SpEL表达式作为判断条件
@ConditionalOnJava 基于jvm版本作为判断条件
@ConditionalOnJndi 在JNDI存在的条件下查找指定的位置
@ConditionalOnMissingBean 当容器里没有指定Bean的情况下
@ConditionalOnMissingClass 当类路径下没有指定的类的情况下
@ConditionalOnNotWebApplication 当前项目不是web项目的情况下  
@ConditionalOnProperty 指定的属性是否有指定的值
@ConditionalOnResource 类路径下是否有指定的资源
@ConditionalOnSingleCandidate 当指定的Bean在容器中只有一个,或者虽然有多个但是指定首选的Bean
@ConditionalOnWebApplication 当前项目是web项目的条件下

接下来,用标红的注解,做个实例吧

首先是jar源的情况:基于spring boot框架,实现类型安全读取属性值的功能,比较简单,主要是整个流程能否顺利走通,最终看到想要的效果,这就要

智者见智仁者见仁了,不废话,燥起来。

基本的组织结构,拣重点  点一下

HelloServiceAutoConfiguration

复制代码

1 package com.wm.auto;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
 5 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 6 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 7 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 8 import org.springframework.context.annotation.Bean;
 9 import org.springframework.context.annotation.Configuration;
10 
11 
12 @Configuration
13 @EnableConfigurationProperties(HelloServiceProperties.class)
14 @ConditionalOnClass(HelloService.class)
15 @ConditionalOnProperty(prefix = "hello",value ="enabled",matchIfMissing = true)
16 public class HelloServiceAutoConfiguration {
17     @Autowired
18     private HelloServiceProperties helloServiceProperties;
19 
20     @Bean
21     @ConditionalOnMissingBean(HelloService.class)
22     public HelloService helloService(){
23         HelloService helloService=new HelloService();
24         helloService.setMsg(helloServiceProperties.getMsg());
25         return helloService;
26     }
27 }

复制代码

此处上面的判断条件,判断HelloService Bean是否存在,若不存在,就创建一个。

对了,还有如何做到类型安全读取配置文件的属性值的

HelloServiceProperties

复制代码

1 package com.wm.auto;
 2 
 3 import org.springframework.boot.context.properties.ConfigurationProperties;
 4 
 5 
 6 @ConfigurationProperties(prefix="hello")
 7 public class HelloServiceProperties {
 8     private  static final String MSG="world";
 9     private  String msg=MSG;
10 
11     public String getMsg() {
12         return msg;
13     }
14 
15     public void setMsg(String msg) {
16         this.msg = msg;
17     }
18 
19 }

复制代码

spring.factories   这个是个重点,是告诉引用此jar包的项目,声明了有哪些自动配置,若有多个配置,需用“,”隔开,此处的“\”是为了换行后仍然能读到属性。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.wm.auto.HelloServiceAutoConfiguration

接下来就可以打包了,这个过程中,遇到了个问题:使用mvn install  打包到maven的本地仓库后,引用该jar的项目是由gradle构建的,用了若干方法始终无法被正常使用,

若某位大神 遇到过,并解决了,清指出问题的原因,不胜感激。

最后就是引用jar包的项目介绍:

复制代码

1 package com.boot;
 2 
 3 import com.boot.properties.AuthorSetting;
 4 import com.wm.auto.HelloService;
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.boot.SpringApplication;
 7 import org.springframework.boot.autoconfigure.SpringBootApplication;
 8 import org.springframework.web.bind.annotation.RequestMapping;
 9 import org.springframework.web.bind.annotation.RestController;
10 
11 @RestController
12 @SpringBootApplication
13 public class Application {
14 
15     @Autowired
16     public AuthorSetting authorSetting;
17 
18     @Autowired
19     public HelloService helloService;
20 
21     @RequestMapping("/")
22     public String index() {
23         return authorSetting.getName() + authorSetting.getAge() + "Hello Spring Boot";
24     }
25 
26     @RequestMapping("/auto-info")
27     public String autoString() {
28         return helloService.getMsg();
29     }
30 
31     public static void main(String[] args) {
32         SpringApplication.run(Application.class, args);
33     }
34 }

复制代码

 至此 完成,看效果

 

 

Spring Boot 中自定义 SpringMVC 配置,到底继承谁?

Spring Boot 中自定义 SpringMVC 配置,到底继承谁?

用过 Spring Boot 的小伙伴都知道,我们只需要在项目中引入 spring-boot-starter-web 依赖,SpringMVC 的一整套东西就会自动给我们配置好,但是,真实的项目环境比较复杂,系统自带的配置不一定满足我们的需求,往往我们还需要结合实际情况自定义配置。

自定义配置就有讲究了,由于 Spring Boot 的版本变迁,加上这一块本身就有几个不同写法,很多小伙伴在这里容易搞混,今天松哥就来和大家说一说这个问题。

概览

首先我们需要明确,跟自定义 SpringMVC 相关的类和注解主要有如下四个:

  • WebMvcConfigurerAdapter

  • WebMvcConfigurer

  • WebMvcConfigurationSupport

  • @EnableWebMvc

这四个中,除了第四个是注解,另外三个两个类一个接口,里边的方法看起来好像都类似,但是实际使用效果却大不相同,因此很多小伙伴容易搞混,今天松哥就来和大家聊一聊这个问题。

WebMvcConfigurerAdapter

我们先来看 WebMvcConfigurerAdapter,这个是在 Spring Boot 1.x 中我们自定义 SpringMVC 时继承的一个抽象类,这个抽象类本身是实现了 WebMvcConfigurer 接口,然后抽象类里边都是空方法,我们来看一下这个类的声明:

public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {
//各种 SpringMVC 配置的方法
}

再来看看这个类的注释:

/**
* An implementation of {@link WebMvcConfigurer} with empty methods allowing
* subclasses to override only the methods they''re interested in.
* @deprecated as of 5.0 {@link WebMvcConfigurer} has default methods (made
* possible by a Java 8 baseline) and can be implemented directly without the
* need for this adapter
*/

这段注释关于这个类说的很明白了。同时我们也看到,从 Spring5 开始,由于我们要使用 Java8,而 Java8 中的接口允许存在 default 方法,因此官方建议我们直接实现 WebMvcConfigurer 接口,而不是继承 WebMvcConfigurerAdapter 。

也就是说,在 Spring Boot 1.x 的时代,如果我们需要自定义 SpringMVC 配置,直接继承 WebMvcConfigurerAdapter 类即可。

WebMvcConfigurer

根据上一小节的解释,小伙伴们已经明白了,WebMvcConfigurer 是我们在 Spring Boot 2.x 中实现自定义配置的方案。

WebMvcConfigurer 是一个接口,接口中的方法和 WebMvcConfigurerAdapter 中定义的空方法其实一样,所以用法上来说,基本上没有差别,从 Spring Boot 1.x 切换到 Spring Boot 2.x ,只需要把继承类改成实现接口即可。

松哥在之前的案例中 (40 篇原创干货,带你进入 Spring Boot 殿堂!),凡是涉及到自定义 SpringMVC 配置的地方,也都是通过实现 WebMvcConfigurer 接口来完成的。

WebMvcConfigurationSupport

前面两个都好理解,还有一个 WebMvcConfigurationSupport ,这个又是干什么用的呢?

松哥之前有一篇文章中用过这个类,不知道小伙伴们有没有留意,就是下面这篇:

  • 纯 Java 代码搭建 SSM 环境

这篇文章我放弃了 Spring 和 SpringMVC 的 xml 配置文件,转而用 Java 代替这两个 xml 配置。那么在这里我自定义 SpringMVC 配置的时候,就是通过继承 WebMvcConfigurationSupport 类来实现的。在 WebMvcConfigurationSupport 类中,提供了用 Java 配置 SpringMVC 所需要的所有方法。我们来看一下这个方法的摘要:

有一点眼熟,可能有小伙伴发现了,这里的方法其实和前面两个类中的方法基本是一样的。

在这里首先大家需要明确的是,WebMvcConfigurationSupport 类本身是没有问题的,我们自定义 SpringMVC 的配置是可以通过继承 WebMvcConfigurationSupport 来实现的。但是继承 WebMvcConfigurationSupport 这种操作我们一般只在 Java 配置的 SSM 项目中使用,Spring Boot 中基本上不会这么写,为什么呢?

小伙伴们知道,Spring Boot 中,SpringMVC 相关的自动化配置是在 WebMvcAutoConfiguration 配置类中实现的,那么我们来看看这个配置类的生效条件:

@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
}

我们从这个类的注解中可以看到,它的生效条件有一条,就是当不存在 WebMvcConfigurationSupport 的实例时,这个自动化配置才会生生效。因此,如果我们在 Spring Boot 中自定义 SpringMVC 配置时选择了继承 WebMvcConfigurationSupport,就会导致 Spring Boot 中 SpringMVC 的自动化配置失效。

Spring Boot 给我们提供了很多自动化配置,很多时候当我们修改这些配置的时候,并不是要全盘否定 Spring Boot 提供的自动化配置,我们可能只是针对某一个配置做出修改,其他的配置还是按照 Spring Boot 默认的自动化配置来,而继承 WebMvcConfigurationSupport 来实现对 SpringMVC 的配置会导致所有的 SpringMVC 自动化配置失效,因此,一般情况下我们不选择这种方案。

在 Java 搭建的 SSM 项目中 (纯 Java 代码搭建 SSM 环境),因为本身就没什么自动化配置,所以我们使用了继承 WebMvcConfigurationSupport。

@EnableWebMvc

最后还有一个 @EnableWebMvc 注解,这个注解很好理解,它的作用就是启用 WebMvcConfigurationSupport。我们来看看这个注解的定义:

/**
* Adding this annotation to an {@code @Configuration} class imports the Spring MVC
* configuration from {@link WebMvcConfigurationSupport}, e.g.:

可以看到,加了这个注解,就会自动导入 WebMvcConfigurationSupport,所以在 Spring Boot 中,我们也不建议使用 @EnableWebMvc 注解,因为它一样会导致 Spring Boot 中的 SpringMVC 自动化配置失效。

总结

不知道上面的解释小伙伴有没有看懂?我再简单总结一下:

  1. Spring Boot 1.x 中,自定义 SpringMVC 配置可以通过继承 WebMvcConfigurerAdapter 来实现。

  2. Spring Boot 2.x 中,自定义 SpringMVC 配置可以通过实现 WebMvcConfigurer 接口来完成。

  3. 如果在 Spring Boot 中使用继承 WebMvcConfigurationSupport 来实现自定义 SpringMVC 配置,或者在 Spring Boot 中使用了 @EnableWebMvc 注解,都会导致 Spring Boot 中默认的 SpringMVC 自动化配置失效。

  4. 在纯 Java 配置的 SSM 环境中,如果我们要自定义 SpringMVC 配置,有两种办法,第一种就是直接继承自 WebMvcConfigurationSupport 来完成 SpringMVC 配置,还有一种方案就是实现 WebMvcConfigurer 接口来完成自定义 SpringMVC 配置,如果使用第二种方式,则需要给 SpringMVC 的配置类上额外添加 @EnableWebMvc 注解,表示启用 WebMvcConfigurationSupport,这样配置才会生效。换句话说,在纯 Java 配置的 SSM 中,如果你需要自定义 SpringMVC 配置,你离不开 WebMvcConfigurationSupport ,所以在这种情况下建议通过继承 WebMvcConfigurationSupport 来实现自动化配置。

不知道小伙伴们有没有看懂呢?有问题欢迎留言讨论。


1、一键部署 Spring Boot 到远程 Docker 容器,就是这么秀!
2、完结撒花!129 集 21 个小时,松哥自制的 Spring Boot2 系列视频教程杀青啦!
3、40 篇原创干货,带你进入 Spring Boot 殿堂!
4、Spring Boot 中的同一个 Bug,竟然把我坑了两次!
5、Spring Boot 支持 Https 有那么难吗?
6、一个野生程序员的自我修养
7、干货 | 鸟瞰 MySQL,唬住面试官!
8、Spring Boot 修改静态资源一定要重启项目才会生效吗?未必!
9、Spring Boot 跨域,JSONP 太 low,试试 CORS 怎么样?


喜欢就点个 "在看" 呗 ^_^

本文分享自微信公众号 - 江南一点雨(a_javaboy)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与 “OSC 源创计划”,欢迎正在阅读的你也加入,一起分享。

Spring Boot 关闭特定的自动配置

Spring Boot 关闭特定的自动配置

Spring Boot 关闭特定的自动配置

    当我们使用springBoot时,有些自动配置我们不想使用的话,可以利用@SpringBootApplication注解中的exculde参数实现

例如:@SpringBootApplication(exculde={DataSourceAutoConfiguration.class})

关于Spring Boot 的自动配置,到底是怎么做到?spring boot自动化配置的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于DIY一个Spring Boot的自动配置、Idea 打包maven项目 以及spring boot 的自动配置、Spring Boot 中自定义 SpringMVC 配置,到底继承谁?、Spring Boot 关闭特定的自动配置等相关内容,可以在本站寻找。

本文标签:

上一篇【云原生】springboot 项目打包部署 docker 镜像(springboot项目打包成docker镜像)

下一篇宁静的POST响应的“最佳实践”(宁静的反应)