您现在的位置是:首页 > 电脑 > 

spring boot 自动配置功能解剖

2025-07-29 04:27:45
spring boot 自动配置功能解剖     说起spring boot和spring的区别,大家第一反应就是spring boot 少了很多配置,但不是说少了很多配置很多功能就没有了,或者比spring就少了很多功能,而是spring boot 自己约定了很多默认配置,让大家感觉不到其中的一些信息   问题来了&#x

spring boot 自动配置功能解剖

    说起spring boot和spring的区别,大家第一反应就是spring boot 少了很多配置,但不是说少了很多配置很多功能就没有了,或者比spring就少了很多功能,而是spring boot 自己约定了很多默认配置,让大家感觉不到其中的一些信息

 

问题来了,spring boot的自动配置怎么实现的?今天我将自己这2天学习到的东西分享一下,有不对的地方可以说出来一起讨论

首先我们先看一下下面这个注解:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({})
public @interface EnableAutoConfiguration {String EABLED_OVERRIDE_PROPERTY = spring.;Class<?>[] exclude() default {};String[] excludeame() default {};
}

看到@import那个注解了吗?这个注解就是会把第三方jar的类加载到当前spring容器,接下来我们看一下import的这个类,源码如下

@Deprecated
public class EnableAutoConfigurationImportSelector extends AutoConfigurationImportSelector {public EnableAutoConfigurationImportSelector() {}protected boolean isEnabled(AnnotationMetadata metadata) {return this.getClass().equals() ? ((Boolean)this.getEnvironment().getProperty(spring., , true)).booleanValue() : true;}
}

下面是父类AutoConfigurationImportSelector 中关键2个方法的源码

   public String[] selectImports(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) { //判断 enableautoconfiguration注解有没有开启,默认开启return O_IMPORTS;} else {try {
//第一部分 :获取 META-IF/spring-autoconfigure-metadata.properties 的配置数据AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
//第二部分 :获取 META-IF/spring.factoies 的类相关数据List<String> configurati = this.getCandidateConfigurati(annotationMetadata, attributes);
//去重configurati = this.removeDuplicates(configurati);、
//排序configurati = this.sort(configurati, autoConfigurationMetadata);
//第三部分:去除一些多余的类,根据EnableAutoConfiguration 注解的一个exclusi属性Set<String> exclusi = this.getExclusi(annotationMetadata, attributes);(configurati, exclusi);configurati.removeAll(exclusi);
//第四部:根据OnClassCondition注解过滤调一些条件没有满足的configurati = this.filter(configurati, autoConfigurationMetadata);
//第五部:广播AutoConfigurationImportEvents事件(最下面有详解)this.fireAutoConfigurationImportEvents(configurati, exclusi);return (String[])(new String[configurati.size()]);} catch (IOException var6) {throw new IllegalStateException(var6);}}}protected boolean isEnabled(AnnotationMetadata metadata) {return true;}

首先程序是先调用EnableAutoConfigurationImportSelector 的selectImport方法,也就是父类的这个方法,下面我们先研究一下代码

大家看上面源码的第一部分,获取spring-autoconfigure-metadata.properties的代码,深究进去的代码如下

 public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {return loadMetadata(classLoader, META-IF/spring-autoconfigure-metadata.properties);}static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {try {Enumeration<URL> urls = classLoader != null ? classLoader.getResources(path) : ClassLoader.getSystemResources(path);Properties properties = new Properties();while(urls.hasMoreElements()) {properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource((URL)())));}return loadMetadata(properties);} catch (IOException var4) {throw new IllegalArgumentException(Unable to load @ConditionalOnClass location [  path  ], var4);}}

ClassLoader.getResource()方法到具有给定名称的资源。资源是一些数据(图像,音频,文本等),返回URL对象读取资源。

该方法就是获取该目录下的配置数据

第二部分:道理跟第一部分一样获取相关类的数据

 

第三步就是去除一些不用的class,这是具体过滤的代码

  private List<String> filter(List<String> configurati, AutoConfigurationMetadata autoConfigurationMetadata) {long startTime = ();String[] candidates = (String[])(new String[configurati.size()]);boolean[] skip = new boolean[candidates.length];boolean skipped = false;Iterator var8 = this.getAutoConfigurationImportFilters().iterator();while(var8.hat()) {AutoConfigurationImportFilter filter = (AutoConfigurationImportFilter)();this.invokeAwareMethods(filter);boolean[] match = (candidates, autoConfigurationMetadata);for(int i = 0; i < match.length; i) {if (!match[i]) {skip[i] = true;skipped = true;}}}if (!skipped) {return configurati;} else {List<String> result = new ArrayList(candidates.length);int numberFiltered;for(numberFiltered = 0; numberFiltered < candidates.length; numberFiltered) {if (!skip[numberFiltered]) {result.add(candidates[numberFiltered]);}}if (logger.isTraceEnabled()) {numberFiltered = configurati.size() - result.size();(Filtered   numberFiltered   auto configuration class in   TimeUnit.(() - startTime)   ms);}return new ArrayList(result);}}

AutoConfigurationImportFilter 是一个接口,OnClassCondition才是它的实现类,主要功能就是第二部加载的类中不是所有都是要加载的,spring boot 提供了很多条件注解,具体如下

@ConditionalOnClass : classpath中存在该类时起效 
@ConditionalOnMissingClass : classpath中不存在该类时起效 
@ConditionalOnBean : DI容器中存在该类型Bean时起效 
@ConditionalOnMissingBean : DI容器中不存在该类型Bean时起效 
@ConditionalOnSingleCandidate : DI容器中该类型Bean只有一个或@Primary的只有一个时起效 
@ConditionalOnExpression : SpEL表达式结果为true时 
@ConditionalOnProperty : 参数设置或者值一致时起效 
@ConditionalOnResource : 指定的文件存在时起效 
@ConditionalOnJndi : 指定的JDI存在时起效 
@ConditionalOnJava : 指定的Java版本存在时起效 
@ConditionalOnWebApplication : Web应用环境下起效 
@ConditionalOnotWebApplication : 非Web应用环境下起效

以上注解都是元注解@Conditional演变而来的,过滤调一些没有满足条件的class

第五步:广播事件

 private void fireAutoConfigurationImportEvents(List<String> configurati, Set<String> exclusi) {// 通过SpringFactoriesLoader.loadFactories()方法获取所有实现 //  AutoConfigurationImportListener的实例化对象List<AutoConfigurationImportListener> listeners = this.getAutoConfigurationImportListeners();if (!listeners.isEmpty()) {
//  生成一个Even事件,给listener发送AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurati, exclusi);Iterator var5 = listeners.iterator();while(var5.hat()) {AutoConfigurationImportListener listener = (AutoConfigurationImportListener)();// 如果实现了或者继承了一些Aware,则设置相应的值。这个大家可以去百度Awarethis.invokeAwareMethods(listener);
// 给AutoConfigurationImportListener发送事件(event);}}}

关键的一个问题来了,回到源头,项目启动之后什么时候会去执行AutoConfigurationImportSelector的selectImports方法?

查了一下资料,其实spring boot是从我们SpringApplication.run方法开始最终执行最终执行到selectImports方法,然后将selectImports方法得到的数据注入到容器里面

springApplication.run----->refreshContext()----->AbstractApplicationContext.refresh---->PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors----->ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry----------->ConfigurationClassPostProcessor.processConfigBeanDefiniti------>ConfigurationClassParser.parse

最终到如下代码

    private void processDeferredImportSelectors() {List<ConfigurationClassParser.DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;this.deferredImportSelectors = null;Collecti.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);Iterator var2 = deferredImports.iterator();while(var2.hat()) {ConfigurationClassParser.DeferredImportSelectorHolder deferredImport = (ConfigurationClassParser.DeferredImportSelectorHolder)();ConfigurationClass configClass = deferredImport.getConfigurationClass();try {
//执行导入自动化数据配置String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
//处理这些数据,注入容器this.processImports(configClass, this.asSourceClass(configClass), this.asSourceClasses(imports), false);} catch (BeanDefinitionStoreException var6) {throw var6;} catch (Throwable var7) {throw new BeanDefinitionStoreException(Failed to process import candidates for configuration class [  configClass.getMetadata().getClassame()  ], var7);}}}

好了,这个如何注入的问题是解决了,spring boot的自动化注入大致讲解完了,

现在又有一个问题了,如果自己要做一个类似于第三方的jar,让当前的容器加载我这个第三方的bean怎么做呢?其实也是非常简单。

第一步:肯定是新建一个spring boot项目A

第二步:定义类

public class people{
}
@Configuration
public class MyConfig {@Beanpublic People people (){return new People();}
}

第三步:将A的jar放到B中

第四部:在B中写如下测试代码,并启动

@EnableAutoConfiguration
@ComponentScan
public class Application {public static void main(String[] args) {ConfigurableApplicationContext context =SpringApplication.run(,args);People people = context.getBean(People .class);println(people );}
}

不过这样启动会报错,不到这个类,那是因为你的第五步没有做

第五步:在core-bean项目resource下新建文件夹META-IF,在文件夹下面新建spring.factories文件,文件中配置,key为自定配置类EnableAutoConfiguration的全路径,value是配置类的全路径(就上面分析spring boot自动配置的那个spring.factories文件一样的道理)

这样之后就可以实现了

到此为止大部分该讲的也都讲完了,如果有什么不对的地方,可以提出来讨论

#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格

本文地址:http://www.dnpztj.cn/diannao/880918.html

相关标签:无
上传时间: 2024-04-17 06:50:11
留言与评论(共有 16 条评论)
本站网友 燕窝的食用方法
5分钟前 发表
args);People people = context.getBean(People .class);println(people );} } 不过这样启动会报错,不到这个类,那是因为你的第五步没有做 第五步
本站网友 马坡二手房
4分钟前 发表
var7);}}} 好了,这个如何注入的问题是解决了,spring boot的自动化注入大致讲解完了, 现在又有一个问题了,如果自己要做一个类似于第三方的jar,让当前的容器加载我这个第三方的bean怎么做呢?其实也是非常简单
本站网友 周志文
4分钟前 发表
spring boot 自动配置功能解剖     说起spring boot和spring的区别,大家第一反应就是spring boot 少了很多配置,但不是说少了很多配置很多功能就没有了,或者比spring就少了很多功能,而是spring boot 自己约定了很多默认配置,让大家感觉不到其中的一些信息   问题来了,spring boot的自动配置怎么实现的?今天我将自己这2天学习到的东西分享一下,有不对的地方可以说出来一起讨论 首先我们先看一下下面这个注解: @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUTIME) @Documented @Inherited @AutoConfigurationPackage @Import({}) public @interface EnableAutoConfiguration {String EABLED_OVERRIDE_PROPERTY = spring.;Class<?>[] exclude() default {};String[] excludeame() default {}; } 看到@import那个注解了吗?这个注解就是会把第三方jar的类加载到当前spring容器,接下来我们看一下import的这个类,源码如下 @Deprecated public class EnableAutoConfigurationImportSelector extends AutoConfigurationImportSelector {public EnableAutoConfigurationImportSelector() {}protected boolean isEnabled(AnnotationMetadata metadata) {return this.getClass().equals() ? ((Boolean)this.getEnvironment().getProperty(spring.
本站网友 tftpd32
7分钟前 发表
var7);}}} 好了,这个如何注入的问题是解决了,spring boot的自动化注入大致讲解完了, 现在又有一个问题了,如果自己要做一个类似于第三方的jar,让当前的容器加载我这个第三方的bean怎么做呢?其实也是非常简单
本站网友 华普报价
2分钟前 发表
args);People people = context.getBean(People .class);println(people );} } 不过这样启动会报错,不到这个类,那是因为你的第五步没有做 第五步
本站网友 文峰广场
25分钟前 发表
autoConfigurationMetadata); //第三部分
本站网友 沙发十大品牌排行榜
24分钟前 发表
attributes);(configurati
本站网友 fedex快递电话
30分钟前 发表
资源是一些数据(图像,音频,文本等)
本站网友 游戏原画线稿
16分钟前 发表
返回URL对象读取资源
本站网友 农工商红利卡
3分钟前 发表
true)).booleanValue()
本站网友 彩虹心水论坛
15分钟前 发表
根据OnClassCondition注解过滤调一些条件没有满足的configurati = this.filter(configurati
本站网友 一点点的蓝
13分钟前 发表
this.asSourceClasses(imports)
本站网友 秀山房屋出租
23分钟前 发表
第一步:肯定是新建一个spring boot项目A 第二步:定义类 public class people{ } @Configuration public class MyConfig {@Beanpublic People people (){return new People();} } 第三步:将A的jar放到B中 第四部:在B中写如下测试代码,并启动 @EnableAutoConfiguration @ComponentScan public class Application {public static void main(String[] args) {ConfigurableApplicationContext context =SpringApplication.run(
本站网友 ze
2分钟前 发表
exclusi);Iterator var5 = listeners.iterator();while(var5.hat()) {AutoConfigurationImportListener listener = (AutoConfigurationImportListener)();// 如果实现了或者继承了一些Aware,则设置相应的值
本站网友 百度可穿戴设备
18分钟前 发表
configurati