发布网友 发布时间:2024-09-26 04:52
共1个回答
热心网友 时间:2024-11-19 12:32
SpringBoot自动配置的原理及实现/SpringBoot之@Import注解正确使用方式了解SpringBoot之@Import注解正确使用方式
SpringBoot的核心就是自动配置,自动配置又是基于条件判断来配置Bean。关于自动配置的源码在spring-boot-autoconfigure-2.0.3.RELEASE.jar
在通常需要我们在property中配置信息时,通常使用@ConfigurationProperties(pefix=“前缀”)注解的方式从配置文件中获取配置,如下:
application.yml中配置信息
访问url获取配置信息返回的值
如果把application.yml中的配置信息注释掉则默认使用default值,否则使用配置信息中的值,以上便是普通配置方式
SpringBoot运行原理
先看@SpringBootApplication
主要关注的几个注解如下
@SpringBootConfiguration:标记当前类为配置类
@EnableAutoConfiguration:开启自动配置
@ComponentScan:扫描主类所在的同级包以及下级包里的Bean
关键是@EnableAutoConfiguration
最关键的要属@Import(EnableAutoConfigurationImportSelector.class),借助**EnableAutoConfigurationImportSelector**,@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器:通过@Import(AutoConfigurationImportSelector.class)导入的配置功能,
AutoConfigurationImportSelector中的方法getCandidateConfigurations,得到待配置的class的类名集合,这个集合就是所有需要进行自动配置的类,而是是否配置的关键在于META-INF/spring.factories文件中是否存在该配置信息
打开,如下图可以看到所有需要配置的类全路径都在文件中,每行一个配置,多个类名逗号分隔,而\表示忽略换行
整个流程如上图所示
以SpringApplicationAdminJmxAutoConfiguration类来看其主要构成部分
都能看到各种各样的条件判断注解,满足条件时就加载这个Bean并实例化
此类的条件注解是:@ConditionalOnProperty
@ConditionalOnBean:当容器里有指定Bean的条件下
@ConditionalOnClass:当类路径下有指定的类的条件下
@ConditionalOnExpression:基于SpEL表达式为true的时候作为判断条件才去实例化
@ConditionalOnJava:基于JVM版本作为判断条件
@ConditionalOnJndi:在JNDI存在的条件下查找指定的位置
@ConditionalOnMissingBean:当容器里没有指定Bean的情况下
@ConditionalOnMissingClass:当容器里没有指定类的情况下
@ConditionalOnWebApplication:当前项目时Web项目的条件下
@ConditionalOnNotWebApplication:当前项目不是Web项目的条件下
@ConditionalOnProperty:指定的属性是否有指定的值
@ConditionalOnResource:类路径是否有指定的值
@ConditionalOnOnSingleCandidate:当指定Bean在容器中只有一个,或者有多个但是指定首选的Bean
这些注解都组合了@Conditional注解,只是使用了不同的条件组合最后为true时才会去实例化需要实例化的类,否则忽略
这种spring4.X带来的动态组合很容易后期配置,从而避免了硬编码,使配置信息更加灵活多变,同时也避免了不必要的意外异常报错。使用的人只要知道配置的条件即可也不用去阅读源码,方便快捷,这也是sprignboot快捷方式带来的好处
参考HttpEncodingAutoConfiguration配置信息如下
案例扩展
项目
需要实例化的服务类
配置信息对应的属性映射类,需要pom中加入spring-boot-starter依赖
自动配置文件
在创建如下路径文件src/main/resources/META-INF/spring.factories
必须是自动配置类的全路径
mvninstall该项目
创建一个springboot-mvc项目pom依赖上面的jar
/则返回当前服务的默认值
在applicaton.yml中加,重启刷新则会更新为如下信息
SpringBoot自动化配置关键组件关系图
mybatis-spring-boot-starter、spring-boot-starter-web等组件的META-INF文件下均含有spring.factories文件,自动配置模块中,SpringFactoriesLoader收集到文件中的类全名并返回一个类全名的数组,返回的类全名通过反射被实例化,就形成了具体的工厂实例,工厂实例来生成组件具体需要的bean。
在springboot中有时候需要控制配置类是否生效,可以使用@ConditionalOnProperty注解来控制@Configuration是否生效.
boot自动配置的原理SpringBoot是基于Spring开发的,是约定大于配置的核心思想。并且集成了大量的第三方库配置比如redis、mongoDB、jpa等。SpringBoot就相当于maven整合了所有jar包,SpringBoot整合了所有框架。其设计目的是用来简化新Spring应用的初始搭建以及开发过程,并不少什么新的框架。
二、SpringBoot优点
优点其实就是简单、快速
快速创建独立运行的Spring项目以及主流框架集成
使用嵌入式的server容器,应用无需打成WAR包
starters自动依赖与版本控制
有大量的自动配置,简化开发
准生产环境运行应用监控
与云计算的天然集成
SpringBoot主程序分析
//@SpringBootApplication标注这个类是一个Springboot的应用@SpringBootApplicationpublicclassSpringboot02DemoApplication{publicstaticvoidmain(String[]args){//将Springboot应用启动SpringApplication.run(Springboot02DemoApplication.class,args);}}
SpringBootApplication源码剖析,进入源码,结果发现其实它是一个组合注解
第一个SpringBootConfiguration注解:@SpringBootConfiguration--是SpringBoot配置类。下面有一个叫@Configuration:它是配置类,下面又有@Component,其实它就是一个注入组件。
第二个@EnableAutoConfiguration注解:是开启自配配置功能
@AutoConfigurationPackage//自动配置包
@Import(AutoConfigurationImportSelector.class)
public@interfaceEnableAutoConfiguration{}
@AutoConfigurationPackage:自动配置包,使用@Import(AutoConfigurationImportSelector.class)注解来完成的,它是springboot底层注解,作用是给容器中导入组件。
自动配置原理
(1)SpringBoot启动的时候首先加载主配置类,开启啦自动配置的功能(@EnableAutoConfiguration)
(2)自动配置功能@EnableAutoConfiguration的作用:它是利用了
@Import(AutoConfigurationImportSelector.class)给容器中导入一些组件。那么,他会给我们导入哪些组件呢?进入AutoConfigurationImportSelector源码看一下部分源码如下。
//@EnableAutoConfiguration注解
@AutoConfigurationPackage
/@Import(AutoConfigurationImportSelector.class)
public@interfaceEnableAutoConfiguration
@Import(AutoConfigurationImportSelector.class)自动配置导入选择
publicclassAutoConfigurationImportSelectorimplementsDeferredImportSelector,BeanClassLoaderAware,
ResourceLoaderAware,BeanFactoryAware,EnvironmentAware,Ordered{
//----部分源码省略----//
protectedAutoConfigurationEntrygetAutoConfigurationEntry(AnnotationMetadataannotationMetadata){
if(!isEnabled(annotationMetadata)){
returnEMPTY_ENTRY;
}
AnnotationAttributesattributes=getAttributes(annotationMetadata);
ListStringconfigurations=getCandidateConfigurations(annotationMetadata,attributes);
//----部分源码省略----//
}
SpringBoot源码-@EnableConfigurationProperties@ConfigurationProperties注解配置原理
1概述
2实例
3配置注入实现原理
使用过SpringBoot的都会知道,我们可以在application.properties文件中进行一系列的配置,该配置会被自动注入到我们需要使用的bean中,下面我们就介绍配置注入的实现原理。
首先,要知道在application.properties中的配置是通过BeanPostProcessor进行注入的,具体完成该功能的BeanPostProcessor实现类是ConfigurationPropertiesBindingPostProcessor。
本文接下来会介绍ConfigurationPropertiesBindingPostProcessor是在何时被加入到beanfactory中的,以及@EnableConfigurationProperties、@ConfigurationProperties注解的实现原理。
SpringBoot自动配置中充斥着大量使用通过application.properties进行扩展配置的实现,比如我们熟悉的MybatisAutoConfiguration:
下面我们在看下MybatisProperties类的定义:
通过如上的注解,MyBatis就可以获得我们在application.properties中的配置了,比如如下配置:
要了解配置注入的实现原理,首先要找到上文介绍到的ConfigurationPropertiesBindingPostProcessor是何时被注册到beanfactory中的,通过阅读源码发现,在spring.factories文件中有如下一行:
可见,是通过@EnableAutoConfiguration注解引入了相关的配置,@EnableAutoConfiguration通过@Import注解自动配置的原理这里不再介绍。我们看下ConfigurationPropertiesAutoConfiguration类的实现:
首先ConfigurationPropertiesAutoConfiguration被@Configuration注解,因此会在beanfactory加载时被作为配置类处理,具体在ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry调用ConfigurationClassParser.parse进行处理。
我们再看@EnableConfigurationProperties定义:
@EnableConfigurationProperties通过@Import(EnableConfigurationPropertiesImportSelector.class)向容器中注入了相关的处理类,@Import也是在ConfigurationClassParser.parse进行处理的。
EnableConfigurationPropertiesImportSelector类定义如下:
好了,到这里,我们已经知道注解@EnableConfigurationProperties.value中指定的配置类是如何被注入到beanfactory中的了,那么注解EnableConfigurationProperties.value中指定的配置类中的属性是如何从application.properties被注入的呢?比如上面的
对应配置如下:
这就是我们前面提到的BeanPostProcessor接口实现类ConfigurationPropertiesBindingPostProcessor类处理的,而ConfigurationPropertiesBindingPostProcessor则是通过上面EnableConfigurationPropertiesImportSelector中使用类ConfigurationPropertiesBindingPostProcessorRegistrar进行注册的:
ConfigurationPropertiesBindingPostProcessor是接口BeanPostProcessor的实现,会被ApplicationContext检测出来,在实例化每个bean时会被调用进行扩展处理。
SpringBoot自动装配原理初看@SpringBootApplication有很多的注解组成,其实归纳就是一个"三体"结构,重要的只有三个Annotation:
(1)@Configuration注解
(2)@ComponentScan
(3)@EnableAutoConfiguration
从源码中可以知道,最关键的要属@Import(EnableAutoConfigurationImportSelector.class),借助EnableAutoConfigurationImportSelector,@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。同时借助于Spring框架原有的一个工具类:SpringFactoriesLoader,@EnableAutoConfiguration就可以实现智能的自动配置。
总结:@EnableAutoConfiguration作用就是从classpath中搜寻所有的META-INF/spring.factories配置文件,并将其中org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射(JavaRefletion)实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总为一个并加载到IoC容器。这些功能配置类要生效的话,会去classpath中找是否有该类的依赖类(也就是pom.xml必须有对应功能的jar包才行)并且配置类里面注入了默认属性值类,功能类可以引用并赋默认值。生成功能类的原则是自定义优先,没有自定义时才会使用自动装配类。
1、从spring-boot-autoconfigure.jar/META-INF/spring.factories中获取redis的相关配置类全限定名(有120多个的配置类)RedisAutoConfiguration,一般一个功能配置类围绕该功能,负责管理创建多个相关的功能类,比如RedisAutoConfiguration负责:JedisConnectionFactory、RedisTemplate、StringRedisTemplate这3个功能类的创建
2、RedisAutoConfiguration配置类生效的一个条件是在classpath路径下有RedisOperations类存在,因此springboot的自动装配机制会会去classpath下去查找对应的class文件。
3.如果pom.xml有对应的jar包,就能匹配到对应依赖class,
4、匹配成功,这个功能配置类才会生效,同时会注入默认的属性配置类@EnableConfigurationProperties(RedisProperties.class)
5.Redis功能配置里面会根据条件生成最终的JedisConnectionFactory、RedisTemplate,并提供了默认的配置形式@ConditionalOnMissingBean(name="redisTemplate")
6.最终创建好的默认装配类,会通过功能配置类里面的@Bean注解,注入到IOC当中
7.用户使用,当用户在配置文件中自定义时候就会覆盖默认的配置@ConditionalOnMissingBean(name="redisTemplate")
1.通过各种注解实现了类与类之间的依赖关系,容器在启动的时候Application.run,会调用EnableAutoConfigurationImportSelector.class的selectImports方法(其实是其父类的方法)--这里需要注意,调用这个方法之前发生了什么和是在哪里调用这个方法需要进一步的探讨
2.selectImports方法最终会调用SpringFactoriesLoader.loadFactoryNames方法来获取一个全面的常用BeanConfiguration列表
3.loadFactoryNames方法会读取FACTORIES_RESOURCE_LOCATION(也就是spring-boot-autoconfigure.jar下面的spring.factories),获取到所有的Spring相关的Bean的全限定名ClassName,大概120多个
4.selectImports方法继续调用filter(configurations,autoConfigurationMetadata);这个时候会根据这些BeanConfiguration里面的条件,来一一筛选,最关键的是
@ConditionalOnClass,这个条件注解会去classpath下查找,jar包里面是否有这个条件依赖类,所以必须有了相应的jar包,才有这些依赖类,才会生成IOC环境需要的一些默认配置Bean
5.最后把符合条件的BeanConfiguration注入默认的EnableConfigurationPropertie类里面的属性值,并且注入到IOC环境当中
spring表达式注入原理开门见山。SpringBean的注入原理:
spring是在配置类需要指定扫描包,然后递归得到下面所有的文件;(springboot默认启动类和兄弟目录下面所有的包文件)
包名+文件名=类全限定名;
calss.from加载到内存当中,得到字节码(class);
判断这个类的脑门上是否有注解(就是类的头顶上),有注解的话,就把这个类先put到Map里面(ResourcesMap和autowiredMap各一份);
如果这个类下面有注解的话@Resources就去ResourcesMap里面去遍历,得到对象,然后注入进来,@Autowired就去AutowiredMap里面去遍历,然后得到对象,注入进来;
实体类脑门上没有注解是没有注入到IOC的。
SpringBoot运行原理SpringBoot是一个基于Spring开发,集成了大量第三方库配置的javaweb开发框架
pom.xml
父依赖
其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件。以后我们导入依赖默认是不需要写版本的。
启动器spring-boot-starter
springboot-boot-starter-xxx:spring-boot的场景启动器
spring-boot-starter-web:帮我们导入了web模块正常运行所依赖的组件。
springBoot将所有的功能场景都抽取出来,做成一个个的starter(启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会被引进来,我们要用什么功能就导入什么样的场景启动器即可。
@SpringBootApplication
作用:标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot运行这个类的main方法来启动SpringBoot应用。