现在企业后端很多都是用springboot。
springboot比传统我们使用的SSM框架开发便捷很多。
我们在理解springboot的时候,不要把它当成一个新的框架,它其实是默认了很多框架的使用方式,就像Maven整合了所有的Jar包,springboot整合了所有的框架。我们需要使用哪一个框架,只需要在Maven中导入相应的starter(启动器)即可。
所以我们得出springboot的优点在于:
(1)它为所有spring开发者更快的入门
(2)开箱即用,提供各种默认配置来简化项目配置
(3)内嵌式服务容器简化WEB项目
(4)没有冗余代码生成和XML配置要求
springboot开发简单最注重要的一个原因就是它的自动配置原理!!!
在这里,我们重点来根据源码来理解一下这个过程。
(1) pom.xml(Maven)
我们直到,一个项目的了解,我们要从它的Maven,也就是pom.xml中去看它导入了什么包。
打开pom.xml,我们首先可以看到:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/>
</parent>
点进去,我们会发现:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.0.RELEASE</version>
</parent>
这里才是真正管理springboot里面所有依赖版本的地方,是springboot的整个大脑。
除此之外,在这个pom.xml配置文件下,我们会发现很多springboot-boot-starter-xxx这些配置我们叫做启动器,有很多这样的启动器。其实是springboot把很多场景都提取出来,比如,mybatis,web,…,你的项目需要什么场景,你就导入什么starter(启动器)即可。
(2)主启动类
启动一个springboot项目,我们通常要在主动类底下启动,即:
package com.lpd;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//说明这是一个springboot的项目
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
//通过反射机制,加载.class文件。
//注意:这里其实是启动了一个服务。
SpringApplication.run(DemoApplication.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 {
(1)@springbootConfiguration
标注在某个类上说明这个类是主配置类,springboot就应该运行这个类的main方法来启动springboot应用,我们可以继续点开它的源码,会发现@Configuration,我们直到,这注解是实现配置文件的功能。
(2)@ComponentScan
这个也是比较重要的一个注解,它对应xml配置中的元素,主要作用是自动扫描并加载符合条件的组件(bean),将这个bean定义加载到IOC容器中。
(3)@EnableAutoConfiguration
这是开启自动配置功能的主要组件。我们家下来详细看下这个配置!
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//自动配置包
@AutoConfigurationPackage
//给容器导入一个组件:导入AutoConfigurationImportSelector.class
//AutoConfigurationImportSelector.class:自动配置导入选择器
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
在这个源码中,最重要的就是这个AutoConfigurationImportSelector.class,中文名是自动配置导入选择器,那么到底会导入哪些配置的选择器呢?我们进入这个源码来看下:
这个类底下有这么一个方法:
//获取候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//在这里我们调用了springFactoriesLoader类的静态方法loadFactoryNames
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
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;
}
我们点击springFactoriesLoader的源码进去,我们会看到:
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
我们会发现有这么一个常量,它对应的是一个地址
我们再返回点击看下loadFactoryNames()方法底下的源码,我们会看到:
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
我们看到:
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
这两行代码,我们要从后面这个地方加载文件,我们点开FACTORIES_RESOURCE_LOCATION,我们会看到:
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
还是指向这个地址!!!
我们会发现,自动配置类一直加载的都是META-INF/spring.factories这个类,我们全局搜索它,会发现这个文件位于这里:
原来自动配置类中自动配置到项目中的文件都是在这里啊!
springboot启动的时候会从类路径META-INF/SPRING.FACTORIES中获取EnableAutoConfiguration指定的值。
接下来,我们去看下这个文件底下到底是什么?
(3)spring.factories
我截取了一小段,大家看下:
我们会发现,这个包底下全是XXXXAutoConfiguration这些类,springboot会将所有我们在项目中出现的场景全部集中到这里,如果需要使用哪一个场景,在pom.xml文件中导入相应的starter即可,那么我们知道spring.factories这个包底下的文件并不是都会生效的,我们怎么查看这个类是否生效呢?我们可以点开进去看:
比如,我们启动一个项目,里面没有开启RSocketRequesterAutoConfiguration这个场景:`
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.rsocket;
import io.rsocket.RSocketFactory;
import io.rsocket.transport.netty.server.TcpServerTransport;
import reactor.netty.http.server.HttpServer;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.messaging.rsocket.RSocketRequester;
import org.springframework.messaging.rsocket.RSocketStrategies;
/**
* {@link EnableAutoConfiguration Auto-configuration} for
* {@link org.springframework.messaging.rsocket.RSocketRequester}. This auto-configuration
* creates {@link org.springframework.messaging.rsocket.RSocketRequester.Builder}
* prototype beans, as the builders are stateful and should not be reused to build
* requester instances with different configurations.
*
* @author Brian Clozel
* @since 2.2.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ RSocketRequester.class, RSocketFactory.class, HttpServer.class, TcpServerTransport.class })
@AutoConfigureAfter(RSocketStrategiesAutoConfiguration.class)
public class RSocketRequesterAutoConfiguration {
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
public RSocketRequester.Builder rSocketRequesterBuilder(RSocketStrategies strategies) {
return RSocketRequester.builder().rsocketStrategies(strategies);
}
}
我们会发现**@conditionalOnClass**这个注解底下的文件都是报红的,这代表没有这个场景。‘
所以我们了解到@conditionalOnClass这个注解,用来判断是否导入了某个场景!
这时候,我突然想到一个问题,我们通常会在application.aml/和application.properties这个配置文件下配置我们项目的一下配置,那么这和这个自动导入类有什么关联吗?
在这里,我们了解到还有一个很重要的注解,我们开启一个导入了WEB的项目,我们在spring.factories这个包下点开WebMvcAutoConfiguration这个类:
@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
@Order(0)
我们会发现一个注解叫做**@EnableConfigurationProperties**,这个类底下的.class文件就是和application.aml/和application.properties进行交互,进行我们项目的自定义配置。
以上就是我对spriingboot自动装配一些简单的理解,希望有朋友看到我的文章后,如果发现有错,请与我交流下,谢谢!!!