漫谈一下 SpringBoot 的起步依赖和自动配置

起步依赖

什么是起步依赖

在没有SpringBoot之前,如果要使用Spring开发一个web工程,我们需要怎么做呢?

首先,我们需要添加Spring、SpringMVC的框架的依赖,有时还需要考虑这些依赖间的版本兼容性,我们pom.xml文件看起来往往是这样的。

<dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <scope>provided</scope>
    </dependency>

 </dependencies>

然后,配置web.xml。

<?xml version="1.0" encoding="UTF-8"?>

	<!-- SpringMVC的前端控制器 -->
	<servlet>

		<servlet-name>dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<!-- 设置自己定义的控制器xml文件 -->
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/my-servlet.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<!-- Spring MVC配置文件结束 -->

	<!-- 拦截设置 -->
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<!-- 由SpringMVC拦截所有请求 -->
		<url-pattern>/</url-pattern>
	</servlet-mapping>	

</web-app>

然后修改自定义的控制器xml。

<beans>	
	<!-- 把标记了@Controller注解的类转换为bean -->
	<context:component-scan base-package="com.mucfc" />
	<!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 -->

	<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
	<!-- 对模型视图名称的解析,即在模型视图名称添加前后缀 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
		p:prefix="/WEB-INF/views/" p:suffix=".jsp"/>

<beans>

而有了SpringBoot后我们只需要在pom.xml文件中继承SpringBoot并引入web的起步依赖,之后添加启动类即可。通过对比,SpringBoot明显简化了大量的配置,使得我们可以快速搭建一个应用。

SpringBoot提供了非常多的starter(起步依赖),这些starter预先打包好了与常用模块相关的所有jar包,并完成了自动配置。因此,起步依赖本质上是一个Maven项目对象模型,定义了对其他库的传递依赖,这些组合在一起支持某种特定功能,这就使得我们在开发时不必过多的关注框架配置,从而简化了开发过程。

使用起步依赖

SpringBoot提供了近50种starter,如上述说的创建一个web工程,我们只需要早pom文件中添加spring-boot-starter-web即可(Spring提供的starter命名规范spring-boot-starter-xxx.jar,第三方提供的starter命名规范xxx-spring-boot-starter.jar),starter的命名往往表明了其能提供的功能。

<dependencies>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
</dependencies>

如果依赖项没有指明版本号,SpringBoot会根据自己的版本号自动关联。如果需要指定特定的版本号,通过元素指定即可。

覆盖起步依赖引入的依赖

还是以spring-boot-starter-web为例,spring-boot-starter-web传递依赖了Jackson JSON库,如果你的项目中并不会用到JSON,你可以使用maven的元素将其排除即可(不排除也不会有任何副作用),如下:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
   <exclusions>
      <exclusion>
         <groupId>com.fasterxml.jackson.core</groupId>
         <artifactId>jackson-bom</artifactId>
      </exclusion>
   </exclusions>
</dependency>

另外,如果你想使用另一个版本的Jackson而不是spring-boot-starter-web中自带的,你只需要在pom.xml文件中添加实际要用的依赖即可,maven会使用pom中的依赖覆盖starter引入的传递依赖。

自动配置

SpringBoot的自动配置使得Spring在运行过程中可以根据不同情况决定使用哪个配置,其实现原理是利用了Spring的条件化配置,条件话配置允许配置存在与应用中,但是只有在满足某些特定条件时才会被使用。

扫描二维码关注公众号,回复: 12375912 查看本文章

上篇文章中我们提到过,要启动SpringBoot需要有一个@SpringBootApplication注解的启动引导类,该类除了是应用的入口,还有着配置SpringBoot的重要作用。上篇文章( 《三种方法带你新建一个SpringBoot项目》 )中,我们简单介绍了下@SpringBootApplication,该注解等同于同时使用@Configuration, @EnableAutoConfiguration 和 @ComponentScan默认属性的情况,而@EnableAutoConfiguration 则是自动配置的关键,看下其源码:

@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({AutoConfigurationImportSelector.class}),熟悉Spring的都知道@Import的作用是将组件加载到Spring容器中,这里是将AutoConfigurationImportSelector添加到Spring容器中。AutoConfigurationImportSelector类中的selectImports方法会调用进getCandidateConfigurations方法,该方法的实现如下:

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;
}

loadFactoryNames会扫描classpath下所有jar包的META-INF/spring.factories文件,将spring.factories文件中key为EnableAutoConfiguration的所有值取出,这些值就是自动配置类的全限定名,然后通过反射将这些类加载到Spring容器中。打开spring-boot-autoconfigure-2.4.1.RELEASE.jar/META-INF/spring.factories文件并找到EnableAutoConfiguration看一下(只截取前几行):

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
……

那这些自动配置类是如何被启用的呢?看个简单的DispatcherServletAutoConfiguration类,分析下其源码(只截取前几行):

@AutoConfigureOrder(-2147483648)
@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({DispatcherServlet.class})
@AutoConfigureAfter({ServletWebServerFactoryAutoConfiguration.class})
public class DispatcherServletAutoConfiguration {
    public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";
    public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration";

    public DispatcherServletAutoConfiguration() {
    }

不难看出该类也被很多注解修饰了,@Configuration表明这是一个配置类。该配置类是否被启用的关键是@ConditionalOnClass注解,在DispatcherServletAutoConfiguration中@ConditionalOnClass指定只有在DispatcherServlet类存在时该配置才会生效。

除此之外,还有好多@ConditionalOnXXX注解(如:@ConditionalOnWebApplication、@ConditionalOnBean等等),这些注解就是条件注解,只有在满足条件的情况下,配置类才会生效。

猜你喜欢

转载自blog.csdn.net/doubututou/article/details/111575847