Spring Boot自动装配原理

简介: Spring Boot自动装配原理以及源码深入
  • 前言
  • SpringBoot是一个脚手架,通常喜欢拿SpringBoot和Spring做比较,SpringBoot只是对于SSM框架开发时候的配置项做了一个默认配置,将开发中约定大于配置进行了实现,大大节约了开发时间写各种繁琐的配置文件环节,达到了开箱即用的便捷体验
  • SpringBoot入口
// 源码入口就是 @SpringBootApplication注解@SpringBootApplicationpublicclassBootDemoApplication {
publicstaticvoidmain(String[] args) {
SpringApplication.run(BootDemoApplication.class, args);
    }
}


  • 查看@SpringBootApplication注解
@Inherited@SpringBootConfiguration@EnableAutoConfiguration// 自动装配原理的核心注解@ComponentScan(excludeFilters= { @Filter(type=FilterType.CUSTOM, classes=TypeExcludeFilter.class),
@Filter(type=FilterType.CUSTOM, classes=AutoConfigurationExcludeFilter.class) })
public@interfaceSpringBootApplication {
  • 查看@EnableAutoConfiguration注解
@Inherited@AutoConfigurationPackage/*** 自动装配的时候使用的是@Import注解* 作用是导入一个或者多个组件搭配@Configuration注解使用,交给spring容器管理* 该注解有三种方式* 1.@import:指定导入一个或者多个类* 2.ImportSelector:定义一个类实现该接口,重写selectImports方法* 3.* 扩展:@ImportResource:指定导入一个或者多个xml文件*/@Import(AutoConfigurationImportSelector.class)
public@interfaceEnableAutoConfiguration {
  • AutoConfigurationImportSelector类源码解析
// 重写来自于DeferredImportSelector.Group#process@Overridepublicvoidprocess(AnnotationMetadataannotationMetadata, DeferredImportSelectordeferredImportSelector) {
Assert.state(deferredImportSelectorinstanceofAutoConfigurationImportSelector,
                 () ->String.format("Only %s implementations are supported, got %s",
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
// 获取自动装配信息AutoConfigurationEntryautoConfigurationEntry= ((AutoConfigurationImportSelector) deferredImportSelector)
        .getAutoConfigurationEntry(annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (StringimportClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
    }
}
// 获取自动装配信息protectedAutoConfigurationEntrygetAutoConfigurationEntry(AnnotationMetadataannotationMetadata) {
if (!isEnabled(annotationMetadata)) {
returnEMPTY_ENTRY;
    }
AnnotationAttributesattributes=getAttributes(annotationMetadata);
// 加载所有在META-INF/spring.factories中配置的类 跳到①List<String>configurations=getCandidateConfigurations(annotationMetadata, attributes);
configurations=removeDuplicates(configurations);
Set<String>exclusions=getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 经过condition注解过滤后的自动配置类configurations=getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
returnnewAutoConfigurationEntry(configurations, exclusions);
}
// ① META-INF/spring.factories中读取所有的候选的自动配置类名称protectedList<String>getCandidateConfigurations(AnnotationMetadatametadata, AnnotationAttributesattributes) {
// 通过SpringFactoriesLoader读取所有的候选的自动配置类名称// ② 加载配置候选的类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.");
returnconfigurations;
}
// ③ 加载配置候选的类protectedClass<?>getSpringFactoriesLoaderFactoryClass() {
returnEnableAutoConfiguration.class;
}
// 所以如果想要将一个外部(第三方)的类交给spring容器管理,可以把这个类配置添加到META-INF/spring.factories文件中。// 例如自定义starter场景启动器
  • 总结:SpringBoot的自动装配原理本质上就是读取项目中所有的META-INF/spring.factories的配置类信息


  • @Import之 ImportSelector/ImportBeanDefinitionRegistrar扩展
// ImportSelector (重要!SpringBoot底层使用这种方式,但是又有区别)publicclassMyImportSelectorimplementsImportSelector {
@OverridepublicString[] selectImports(AnnotationMetadataimportingClassMetadata) {
// 返回值String[]中值依旧是要导入类的全限定名,注意,返回值可以是空数组但是不能为nullreturnnewString[]{"com.fun.bootdemo.custome.Demo1"};
    }
}
/*** SpringBoot底层使用的是:* org.springframework.boot.autoconfigure.AutoConfigurationImportSelector* 该类实现的是DeferredImportSelector接口,该接口包含有额外功能:* gruop 该分组可以用来进行排序和过滤时同时DeferredImportSelector是优先级比较低的,* 需要等到其他bean注册完了。才注册该接口导入的bean。这个功能很好的结合了@Conditon等条件注解* 实现了用户自定义配置覆盖默认配置*/// ImportBeanDefinitionRegistrarpublicclassMyImportBeanDefinitionRegistrarimplementsImportBeanDefinitionRegistrar {
@OverridepublicvoidregisterBeanDefinitions(AnnotationMetadataimportingClassMetadata, BeanDefinitionRegistryregistry) {
// 指定注册bean定义信息RootBeanDefinitionrootBeanDefinition=newRootBeanDefinition(Demo3.class);
// demo3 是beanNameregistry.registerBeanDefinition("demo3", rootBeanDefinition);
    }
}
// 测试 (在配置类上)@Import({MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})


相关文章
|
1月前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
1月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
2月前
|
Java 应用服务中间件 开发者
Java面试题:解释Spring Boot的优势及其自动配置原理
Java面试题:解释Spring Boot的优势及其自动配置原理
95 0
|
2月前
|
设计模式 监控 Java
解析Spring Cloud中的断路器模式原理
解析Spring Cloud中的断路器模式原理
|
4天前
|
Java 开发者 数据格式
【Java笔记+踩坑】SpringBoot基础4——原理篇
bean的8种加载方式,自动配置原理、自定义starter开发、SpringBoot程序启动流程解析
【Java笔记+踩坑】SpringBoot基础4——原理篇
|
1月前
|
XML Java 数据格式
Spring5入门到实战------6、IOC容器-Bean管理XML方式(自动装配)
这篇文章是Spring5框架的入门教程,详细讲解了IOC容器中Bean的自动装配机制,包括手动装配、`byName`和`byType`两种自动装配方式,并通过XML配置文件和Java代码示例展示了如何在Spring中实现自动装配。
Spring5入门到实战------6、IOC容器-Bean管理XML方式(自动装配)
|
1月前
|
XML Java 数据格式
Spring5入门到实战------2、IOC容器底层原理
这篇文章深入探讨了Spring5框架中的IOC容器,包括IOC的概念、底层原理、以及BeanFactory接口和ApplicationContext接口的介绍。文章通过图解和实例代码,解释了IOC如何通过工厂模式和反射机制实现对象的创建和管理,以及如何降低代码耦合度,提高开发效率。
Spring5入门到实战------2、IOC容器底层原理
|
1月前
|
Java 程序员 数据库连接
女朋友不懂Spring事务原理,今天给她讲清楚了!
该文章讲述了如何解释Spring事务管理的基本原理,特别是针对女朋友在面试中遇到的问题。文章首先通过一个简单的例子引入了传统事务处理的方式,然后详细讨论了Spring事务管理的实现机制。
女朋友不懂Spring事务原理,今天给她讲清楚了!
|
2月前
|
SQL Java 数据库连接
springboot~mybatis-pagehelper原理与使用
【7月更文挑战第15天】MyBatis-PageHelper是用于MyBatis的分页插件,基于MyBatis的拦截器机制实现。它通过在SQL执行前动态修改SQL语句添加LIMIT子句以支持分页。使用时需在`pom.xml`添加依赖并配置方言等参数。示例代码: PageHelper.startPage(2, 10); List&lt;User&gt; users = userMapper.getAllUsers(); PageInfo&lt;User&gt; pageInfo = new PageInfo&lt;&gt;(users); 这使得分页查询变得简单且能获取总记录数等信息。
|
2月前
|
XML Java 数据格式
深入理解Spring中的依赖注入原理
深入理解Spring中的依赖注入原理