Spring Boot

Spring Boot

pom.xml

父依赖

主要管理项目的资源过滤及插件

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.3.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

父项目还有一个父项目,这个才是真正管理springboot应用里所有依赖版本的地方,springboot的版本控制中心

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.3.3.RELEASE</version>
</parent>

以后我们导入依赖默认是不需要写版本的,但是如果导入的包没有在以来中管理,就需要手动配置版本

启动器 spring-boot-starter

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

spring-boot-starter-xxx: 就是springboot的场景启动器;

spring-boot-starter-web: 帮我们导入了web模块正常与逆行所以来的组件;

SpringBoot将所有的功能场景都抽取出来,做成一个个的starter(启动器),只需要在项目主引入这些starter即可,所有相关依赖都会导入进来, 我们需要什么功能就到处对应的启动器即可; 未来也可以自定义自己的 starter;

主启动类

@SpringBootApplication  //标注这是一个springBoot的应用类
public class Springboot02WebApplication {

	public static void main(String[] args) {
        //以为是启动了一个方法,没想到是启动了一个服务tomcat
		SpringApplication.run(Springboot02WebApplication.class, args);
	}

}

@SpringBootApplication

作用: 标注这个类是springboot的主配置类, 运行这个类的main方法来启动springboot

点入层次结构如下:

@SpringBootConfiguration//标注这是一个springboot的配置类
|
|___@Configuration//这是一个配置类,对应spring的XML配置文件
    |
	|___@Component//这是一个组件,被注入spring中, 说明启动类本身也是spring的一个组件
    
@ComponentScan//它对应XML配置中的元素,自动扫描并加载符合条件的组件或者bean,将它定义加载到IOC容器
    
@EnableAutoConfiguration//开启自动配置功能, 加了它自动配置才能生效
|
|___@AutoConfigurationPackage//自动配置包
	|
	|___@Import(AutoConfigurationPackages.Registrar.class)//spring底层注解,给容器导入一个组件
    	//Registrar.class 作用: 将主启动类的所在包以及包下面所有子包里面的所有组件扫描到spring容器
|
|___@Import(AutoConfigurationImportSelector.class)//导入一个自动配置导入选择器
  1. AutoConfigurationImportSelector : 自动配置导入选择器, 点入查看源码
//获取候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    //这里的getSpringFactoriesLoaderFactoryClass()方法
    //返回的就是我们最开始看的 启动自动导入配置文件的 注解类 EnableAutoConfiguration
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());
    return configurations;
}
  1. 这里又调用了SpringFactoriesLoader类的静态方法,进入SpringFactoriesLoader.loadFactoryNames()
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
		String factoryTypeName = factoryType.getName();
        //这里调用了loadSpringFactories方法
		return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
	}
  1. 继续点击进入loadSpringFactories()方法
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
    //获取classLoader, 我们返回可以看到这里得到的就是 EnableAutoConfiguration 注解类本身
    MultiValueMap<String, String> result = cache.get(classLoader);
    //去获取一个资源"META-INF/spring.factories"
 	Enumeration<URL> urls = (classLoader != null ?classLoader.getResources("META-INF/spring.factories") :ClassLoader.getSystemResources("META-INF/spring.factories"));
    result = new LinkedMultiValueMap<>();
    
    //将读取到的资源遍历, 封装成为一个 Properties
    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;
}
  1. 发现多次出现spring.factories

在这里插入图片描述

WebMvcAutoConfiguration

我们在上面的自动配置类中打开一个.可以看到这些都是JavaConfig配置类,而且都注入了一些bean
在这里插入图片描述

所以自动配置的实现是从classpath中搜寻所有的META-INF/spring.factories配置文件,并将其对应的org.springframwork.boot.autoconfigure.包下的配置项,通过反射实例化对应标注了@Configuration的JavaConfig形式的IOC容器配置类,然后将这些都汇总成为一个实例并加载到IOC容器中.

结论:

  1. SptingBoot在启动的时候从类路径下的MATE-INF/spring.factories中获取EnableAutoConfiguration指定的值

  2. 将这些值作为自动配置类导入容器,自动配置类就生效,帮我们进行自动配置工作

  3. 整个J2EE的整体解决方案和自动配置都在sprigboot-autoconfigure的jar包中

  4. 他会给容器中导入非常多的自动配置类(xxxAutoConfiguration),就是给容器中导入这个场景需要的所有组件,并配置好这个组件

  5. 有了自动配置类,免去了我们手动编写配置注入功能组件等的工作

SpringApplication

他启动了一个服务

@SpringBootApplication
public class Springboot02WebApplication {
	public static void main(String[] args) {
		SpringApplication.run(Springboot02WebApplication.class, args);
	}
}

SpringApplication.run

SpringApplication类主要做了一下四件事:

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
   this.resourceLoader = resourceLoader;
   Assert.notNull(primarySources, "PrimarySources must not be null");
   this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //推断应用类型是普通的项目还是web项目
   this.webApplicationType = WebApplicationType.deduceFromClasspath();
    //查找并加载所有可用初始化容器,设置到initializers属性中
   setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    //找出所有的应用程序监听器,设置到listeners属性值
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //推断并设置main方法的定义类,找到运行的主类
   this.mainApplicationClass = deduceMainApplicationClass();
}

run方法流程分析
在这里插入图片描述

自动配置原理

//表示这是一个配置类,可以编写的配置文件一样,也可以给容器中添加组件
@Configuration(proxyBeanMethods = false)
//启动指定类的ConfigurationProperties功能
	//进入这个ServerProperties类查看,将配置文件中对应的值和ServerProperties绑定起来
	//并把ServerProperties加入到IOC容器中
@EnableConfigurationProperties(ServerProperties.class)
//Spring底层@Conditional注解
	//根据不同的条件判断,如果满足指定条件,整个配置类里面的配置就会生效
	//这里的意思就是判断当前应用是否是Web应用,如果是,则配置类生效
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
//判断当前项目中有没有这个类CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器
@ConditionalOnClass(CharacterEncodingFilter.class)
//判断配置文件中是否存在某个配置:server.servlet.encoding.enabled
	//即使不存在,判断也是成立的matchIfMissing
	//即使我们配置文件中不配置server.servlet.encoding.enabled=true也是默认生效的
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
	//它已经和SpringBoot的配置文件映射了
	private final Encoding properties;
	//只有一个有参构造器的情况下,参数的值就会从容器中拿
	public HttpEncodingAutoConfiguration(ServerProperties properties) {
		this.properties = properties.getServlet().getEncoding();
	}

    //给容器添加一个组件,这个组件的某些值需要从properties中获取
	@Bean
	@ConditionalOnMissingBean//判断容器中没有这个组件
	public CharacterEncodingFilter characterEncodingFilter() {
		CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
		filter.setEncoding(this.properties.getCharset().name());
		filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
		filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
		return filter;
	}
    //......
}

一句话总结:根据当前不同的条件判断,决定这个配置类是否生效

  • 一但这个配置类生效,这个配置类就会给容器中添加各种组件

  • 这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的

  • 所有在配置文件中能配置的属性都是在xxxProperties类在封装着

  • 配置文件能配置什么就可以参照某个功能对应的这个属性类

    //从配置文件中获取指定的值和bean的属性进行绑定
    @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
    public class ServerProperties {
     //......   
    }
    

精髓

  1. SpringBoot启动会加载大量的自动配置类

  2. 我们看我们需要的功能有没有在springBoot中默认写好的自动配置类中

  3. 我们再看这个自动配置类中到底配置了哪些组件;只要我们要用的组件存在其中,我们就不需要手动配置了

  4. 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性.我们只需要在配置文件中指定这些属性的值即可

    xxxAutoConfiguration:自动配置类,给容器中添加组件

    xxxProperties:封装配置文件中相关属性

了解:@Conditional

自动配置类必须在一定的条件下才能生效

@Condational派生注解(Spring注解版原生的@Condational)

作用: 必须是@Conditional指定的条件成立,才给容器中添加组件,配置里面的所有内容才会生效

在这里插入图片描述

那么多自动配置类,必须在一定的条件下才能生效;也就是说,我们加在了那么多配置类,但不是所有的都生效了

我们怎么知道哪些自动配置类生效了?

可以通过开启debug=true的属性,来让控制台打印自动配置报告,这样我们可以很方便的知道哪些自动配置类生效

#开启SpringBoot的调试类
debug=true

Positive matches:(自动配置类启用的正匹配)

Negative matches:(没有启动,没有匹配成功的自动配置类:负配置)

Unconditional classes:(没有条件的类)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值