Talk about the initial dependency and automatic configuration of SpringBoot

Start-up dependence

What is initial dependence

Before SpringBoot, what do we need to do if we want to use Spring to develop a web project?

First of all, we need to add Spring and SpringMVC framework dependencies, and sometimes need to consider the version compatibility between these dependencies. Our pom.xml file often looks like this.

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

Then, configure 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>

Then modify the custom controller 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>

With SpringBoot, we only need to inherit SpringBoot in the pom.xml file and introduce the initial dependencies of the web, and then add the startup class. By comparison, SpringBoot significantly simplifies a lot of configuration, allowing us to quickly build an application.

SpringBoot provides a lot of starters (start-up dependencies), these starters pre-package all jar packages related to common modules, and complete automatic configuration. Therefore, the initial dependency is essentially a Maven project object model, which defines transitive dependencies on other libraries. These combinations support a specific function, which allows us to not pay too much attention to the framework configuration during development, thereby simplifying development process.

Start-up dependency

SpringBoot provides nearly 50 starters. As mentioned above, to create a web project, we only need to add spring-boot-starter-web to the early pom file (the starter naming specification spring-boot-starter-xxx.jar provided by Spring) , The starter naming specification xxx-spring-boot-starter.jar provided by the third party), the naming of the starter often indicates the functions it can provide.

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

If the dependency does not specify the version number, SpringBoot will automatically associate it according to its own version number. If you need to specify a specific version number, just specify it through the element.

Override the dependencies introduced by the initial dependencies

Take spring-boot-starter-web as an example. Spring-boot-starter-web relies on the Jackson JSON library. If JSON is not used in your project, you can use maven elements to exclude it ( Does not rule out nor will there be any side effects), as follows:

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

In addition, if you want to use another version of Jackson instead of the one that comes with spring-boot-starter-web, you only need to add the actual dependencies to the pom.xml file, and maven will use the dependencies in the pom Override the transitive dependency introduced by starter.

Automatic configuration

SpringBoot's automatic configuration allows Spring to decide which configuration to use according to different situations during its operation. The implementation principle is to use Spring's conditional configuration. Conditional configuration allows configuration to exist in the application, but only when certain specific conditions are met. Will be used.

As we mentioned in the previous article, to start SpringBoot, a @SpringBootApplication annotated startup boot class is required. In addition to being the entry point of the application, this class also plays an important role in configuring SpringBoot. In the last article ("Three Ways to Take You to Create a New SpringBoot Project"), we briefly introduced @SpringBootApplication. This annotation is equivalent to using @Configuration, @EnableAutoConfiguration and @ComponentScan default properties at the same time, while @EnableAutoConfiguration is The key to automatic configuration, look at its source code:

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

Its core lies in @Import({AutoConfigurationImportSelector.class}). Those familiar with Spring know that @Import's role is to load components into the Spring container. Here is to add AutoConfigurationImportSelector to the Spring container. The selectImports method in the AutoConfigurationImportSelector class will call the getCandidateConfigurations method, which is implemented as follows:

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 will scan the META-INF/spring.factories files of all jar packages under the classpath, and take out all the values ​​in the spring.factories file whose key is EnableAutoConfiguration. These values ​​are the fully qualified names of the auto-configuration classes, and then load these classes through reflection Into the Spring container. Open the spring-boot-autoconfigure-2.4.1.RELEASE.jar/META-INF/spring.factories file and find EnableAutoConfiguration to take a look (only the first few lines are intercepted):

# 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,\
……

How are these auto-configuration classes enabled? Look at a simple DispatcherServletAutoConfiguration class and analyze its source code (only the first few lines are intercepted):

@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() {
    }

It is not difficult to see that this class is also decorated by many annotations, @Configuration indicates that this is a configuration class. The key to whether the configuration class is enabled is the @ConditionalOnClass annotation. In DispatcherServletAutoConfiguration, @ConditionalOnClass specifies that the configuration will only take effect when the DispatcherServlet class exists.

In addition, there are many @ConditionalOnXXX annotations (such as @ConditionalOnWebApplication, @ConditionalOnBean, etc.). These annotations are conditional annotations. The configuration class will only take effect if the conditions are met.

Guess you like

Origin blog.csdn.net/doubututou/article/details/111575847