springboot-02-运行原理和自动装配原理

@SpringBootApplication运行原理分析

首先来看一下springboot项目的主启动类

@SpringBootApplication
public class Springboot01HelloworldApplication {
    
    

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

}

可以发现此类是由注解@SpringBootApplication标注的,要想研究自动装配原理,一层一层点进去查看源码即可。
点进去,可以看到以下内容。

在这里插入图片描述

核心是这三个注解

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
    
     @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

我们来一个一个看,首先看第一个@SpringBootConfiguration,点进去查看
在这里插入图片描述
他被@Configuration这个注解标记着,这个注解是spring中的注解,代表被标记类是一个配置类,然后再点进去。
在这里插入图片描述
可以看到被@Component标记着,代表着是一个组件,被spring管理着,到此这个注解结束了。

总结@SpringBootConfiguration:被标记类是一个配置类,并且是spring容器中的一个组件。

接下来看下一个注解@EnableAutoConfiguration,点进去一探究竟。
在这里插入图片描述
它里面又有两个核心注解:

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)

先看其中的一个@AutoConfigurationPackage,点进去
在这里插入图片描述
再往下一层点,点击Registrar进入查看
在这里插入图片描述

可以看到核心方法,点击上图中红框的方法PackageImports继续查看
在这里插入图片描述
可以看到参数是AutoConfigurationPackage.class.getName(),再点击AutoConfigurationPackage发现回到了@AutoConfigurationPackage注解
在这里插入图片描述
也就是说,@AutoConfigurationPackage的作用是将被此注解标记的类(主启动类)下的所有springboot自带的组件扫描到spring容器中。
至此@AutoConfigurationPackage扫描到了包,接下来就该是导入自动配置选择器@Import(AutoConfigurationImportSelector.class)
,点进去看看。
在这里插入图片描述
里面有一个selectImports方法,将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中。那么是怎么导入的呢?
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
通过一系列的点击,最后可以发现是通过这一文件spring.factories导入的,让我们来看看这文件里都有些什么。
在这里插入图片描述
看到了很多自动配置的文件;这就是自动配置根源所在!
点进一个看看
在这里插入图片描述
在这里插入图片描述
发现里面都是一个个的JavaConfig配置类,而且都注入了一些Bean(此方面实在spring中学习的)
总结@Import(AutoConfigurationImportSelector.class),自动配置真正实现是从classpath中搜寻所有的META-INF/spring.factories配置文件 ,并将其中对应的 org.springframework.boot.autoconfigure. 包下的配置项,通过反射实例化为对应标注了 @Configuration的JavaConfig形式的IOC容器配置类 , 然后将这些都汇总成为一个实例并加载到IOC容器中。
那么启动springboot时会将所有的自动配置组件都导入吗?答案:当然不是,是由一个注解控制的@ConditionalOnClass,如果在pom.xml导入了对应的启动器,则会在启动时自动配置此功能,否则爆红。
在这里插入图片描述

最后一个注解@ComponentScan组件扫描,它是将被标记的类(主启动类)的上一级目录(com.kuang)包下的所有带@Component标签(@Controller,@Service本质都是@Component)的类都封装成了beandefinition然后就注册到beanfactory当中。
这也就是代码要写在和主启动类同级的包下,以便可以被扫描到。

@ComponentScan和@EnableAutoConfiguration的不同点

1.两者虽然都能将带有注解的对象放入ioc容器中,但是它们扫描的范围是不一样的。@ComponentScan扫描的范围默认是它所在的包以及子包中所有带有注解的对象,@EnableAutoConfiguration扫描的范围默认是它所在类

2.它们作用的对象不一样,@EnableAutoConfiguration除了扫描本类带有的注解外,还会 借助@Import的支持,收集和注册依赖包中相关的bean定义,将这些bean注入到ioc容器中。在springboot中注入的bean有两部分组成,一部分是自己在代码中写的标注有@Controller,@service,@Respority等注解的业务bean,这一部分bean就由@ComponentScan将它们加入到ioc容器中,还有一部分是springboot自带的相关bean,可以将这部分bean看成是工具bean,这部分bean就是由@EnableAutoConfiguration负责加入到容器中。

3.@EnableAutoConfiguration可以单独启动springboot项目,而@ComponentScan是不能的。

总结:@SpringBootApplication

1.主启动类是一个配置类,且是一个组件被注入到容器中。
2.SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值(pom.xml指定),将这些指定的值完成自动配置,并将主启动类下的所有springboot自带的组件扫描到spring容器中。
3.自动扫描启动类同级包下的所有自己添加的组件,添加到容器中。

SpringApplication.run分析

分析该方法主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行;

SpringApplication类帮我们做了哪些事情?

1、推测web应用类型,是普通的项目还是Web项目,并赋值到属性webApplicationType

2、设置所有可用初始化器到List<ApplicationContextInitializer<?>> initializers属性中

3、设置所有监听器到List<ApplicationListener<?>> listeners属性中

4、 推断运行的主类,并赋值到属性mainApplicationClass

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

自动装配原理分析

我们以**HttpEncodingAutoConfiguration(Http编码自动配置)**为例解释自动配置原理;

//表示这是一个配置类,可以向容器中添加组件
@Configuration(proxyBeanMethods = false)
//自动装配时加载ServerProperties类的属性
@EnableConfigurationProperties(ServerProperties.class)
//判断是否是web应用,如果是,就生效
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
//判断是否存在CharacterEncodingFilter这个类,springmvc中的字符编码过滤器
@ConditionalOnClass(CharacterEncodingFilter.class)
//判断是否存在server.servlet.encoding.enabled这个属性
//如果不存在,判断也成立
@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;
	}
}	

总结:启动时根据条件判断是否加载这个配置类

  • 一旦加载这个配置类(xxxAutoConfiguration),这个配置类就会向容器中添加各种组件(@Bean)
  • 这些组件的属性是从对应的xxxProperties类中获取的,xxxProperties中的属性也可以通过配置文件修改的,也就是说,所有在配置文件中能配置的属性都是在xxxxProperties类中封装着

在这里插入图片描述
在这里插入图片描述

精髓

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

2、我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中;

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

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

xxxxAutoConfigurartion:自动配置类;给容器中添加组件

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

了解:@Conditional

了解完自动装配的原理后,我们来关注一个细节问题,自动配置类必须在一定的条件下才能生效;

@Conditional派生注解(Spring注解版原生的@Conditional作用)

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

在这里插入图片描述
可以通过启用 debug=true属性;来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效;

#开启springboot的调试类
debug=true

猜你喜欢

转载自blog.csdn.net/qq_42665745/article/details/114377831