springboot单例模式注入对象_001 | 搭上SpringBoot自动注入源码分析专车

001 | 搭上SpringBoot自动注入源码分析专车

点击上方“java进阶架构师”,选择右上角“置顶公众号”

20大进阶架构专题每日送达

本系列为SpringBoot深度源码专车系列,第一篇发车!

专车介绍

该趟专车是开往Spring Boot自动注入原理源码分析的专车

专车问题

Spring Boot何时注入@Autowired标注的属性?

如果注入类型的Bean存在多个Spring Boot是如何处理的?

专车示例

定义接口

public interface PersonService {

String hello(String name);

}

定义接口的一个实现

@Service(value = "studentService")

public class StudentServiceImpl implements PersonService {

@Override

public String hello(String name) {

return "[student service] hello " + name;

}

}

定义接口的另一个实现

@Service(value = "teacherService")

public class TeacherServiceImpl implements PersonService {

@Override

public String hello(String name) {

return "[teacher service] hello " + name;

}

}

定义控制器

@RestController

public class TestController {

@Autowired

private PersonService studentService;

@Autowired

private PersonService teacherService;

@GetMapping("/hello")

public String hello(@RequestParam(name = "name") String name) {

return studentService.hello(name) + "=======>" + teacherService.hello(name);

}

}

以上示例代码很简单,创建了一个接口,接口有两个实现类,然后在控制器中注入实现类,从而完成业务方法的调用。接下来我们就开始对源码进行分析

专车分析

在分析代码之前我们先回忆一下操作对象的步骤:

首先我们会实例化一个对象

然后调用对象的set方法来设置对象的属性

有了上面的基础知识,接下来就开始揭秘旅程

寻找入口

在分析源码的时候最关键的一步就是寻找程序的入口,有了入口我们就成功了一半,那么如何寻找程序的入口?针对此处的源码分析,我们可以在TestController类上打一个断点,然后查看调用链

基于调用链路,我们看到有一个doCreateBean方法,该方法就是用来创建bean的,也就是我们上面提到的实例化对象部分

实例化Bean

AbstractAutowireCapableBeanFactory#doCreateBean

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)

throws BeanCreationException {

// Instantiate the bean.

BeanWrapper instanceWrapper = null;

if (mbd.isSingleton()) {

instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);

}

if (instanceWrapper == null) {

// 创建bean

instanceWrapper = createBeanInstance(beanName, mbd, args);

}

final Object bean = instanceWrapper.getWrappedInstance();

Class> beanType = instanceWrapper.getWrappedClass();

// ...省略部分代码

// Initialize the bean instance.

Object exposedObject = bean;

try {

// 填充bean,也就是我们上面提到的调用对象的set方法设置对象属性

populateBean(beanName, mbd, instanceWrapper);

exposedObject = initializeBean(beanName, exposedObject, mbd);

}

// ...省略部分代码

return exposedObject;

}

填充bean

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {

// ...省略代码

PropertyDescriptor[] filteredPds = null;

if (hasInstAwareBpps) {

if (pvs == null) {

pvs = mbd.getPropertyValues();

}

// 遍历所有的后置处理器

for (BeanPostProcessor bp : getBeanPostProcessors()) {

if (bp instanceof InstantiationAwareBeanPostProcessor) {

InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;

// 通过断点分析我们可以得知此处调用的是AutowiredAnnotationBeanPostProcessor#postProcessProperties

PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);

if (pvsToUse == null) {

if (filteredPds == null) {

filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);

}

pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);

if (pvsToUse == null) {

return;

}

}

pvs = pvsToUse;

}

}

}

if (needsDepCheck) {

if (filteredPds == null) {

filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);

}

checkDependencies(beanName, mbd, filteredPds, pvs);

}

if (pvs != null) {

applyPropertyValues(beanName, mbd, bw, pvs);

}

}

处理属性

AutowiredAnnotationBeanPostProcessor#postProcessProperties

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {

// 查找当前bean需要注入的元数据信息,以TestController为例,那么需要注入的就是studentService和teacherService两个属性

InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);

try {

// 注入属性

metadata.inject(bean, beanName, pvs);

}

catch (BeanCreationException ex) {

throw ex;

}

catch (Throwable ex) {

throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);

}

return pvs;

}

注入属性 AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {

// 获取属性,此处的属性就是studentService

Field field = (Field) this.member;

// 属性对应的value

Object value;

if (this.cached) {

value = resolvedCachedArgument(beanName, this.cachedFieldValue);

}

else {

DependencyDescriptor desc = new DependencyDescriptor(field, this.required);

desc.setContainingClass(bean.getClass());

Set autowiredBeanNames = new LinkedHashSet<>(1);

Assert.state(beanFactory != null, "No BeanFactory available");

TypeConverter typeConverter = beanFactory.getTypeConverter();

try {

// 解析属性依赖

value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);

}

catch (BeansException ex) {

throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);

}

synchronized (this) {

if (!this.cached) {

if (value != null || this.required) {

this.cachedFieldValue = desc;

registerDependentBeans(beanName, autowiredBeanNames);

if (autowiredBeanNames.size() == 1) {

String autowiredBeanName = autowiredBeanNames.iterator().next();

if (beanFactory.containsBean(autowiredBeanName) &&

beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {

this.cachedFieldValue = new ShortcutDependencyDescriptor(

desc, autowiredBeanName, field.getType());

}

}

}

else {

this.cachedFieldValue = null;

}

this.cached = true;

}

}

}

if (value != null) {

ReflectionUtils.makeAccessible(field);

// 给属性设置值,完成注入功能

field.set(bean, value);

}

}

解析属性依赖 DefaultListableBeanFactory#resolveDependency

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,

@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());

if (Optional.class == descriptor.getDependencyType()) {

return createOptionalDependency(descriptor, requestingBeanName);

}

else if (ObjectFactory.class == descriptor.getDependencyType() ||

ObjectProvider.class == descriptor.getDependencyType()) {

return new DependencyObjectProvider(descriptor, requestingBeanName);

}

else if (javaxInjectProviderClass == descriptor.getDependencyType()) {

return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);

}

else {

Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(

descriptor, requestingBeanName);

if (result == null) {

// 解析依赖

result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);

}

return result;

}

}

解析属性依赖 DefaultListableBeanFactory#doResolveDependency

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,

@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);

try {

// ...省略代码

// 解析多个Bean,比如Array、List、Map类型,有兴趣可以自己查看分析

Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);

if (multipleBeans != null) {

return multipleBeans;

}

// 根据类型获取候选对象,针对studentService而言,该属性的类型为PersonService

// PersonService有2个实现类,StudentServiceImpl和TeacherServiceImpl

// 所以此处获取结果为StudentServiceImpl对象和TeacherServiceImpl对象

Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);

if (matchingBeans.isEmpty()) {

if (isRequired(descriptor)) {

raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);

}

return null;

}

String autowiredBeanName;

Object instanceCandidate;

// 重点处理,如果存在多个匹配的bean

if (matchingBeans.size() > 1) {

// 从已经匹配的bean中选择一个符合的bean

autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);

if (autowiredBeanName == null) {

// 如果bean必须注入或者存在多个匹配的bean,则抛出异常

if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {

return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);

}

else {

// In case of an optional Collection/Map, silently ignore a non-unique case:

// possibly it was meant to be an empty collection of multiple regular beans

// (before 4.3 in particular when we didn't even look for collection beans).

return null;

}

}

// 根据bean名称获取对应的示例

instanceCandidate = matchingBeans.get(autowiredBeanName);

}

else {

// We have exactly one match.

Map.Entry entry = matchingBeans.entrySet().iterator().next();

autowiredBeanName = entry.getKey();

instanceCandidate = entry.getValue();

}

if (autowiredBeanNames != null) {

autowiredBeanNames.add(autowiredBeanName);

}

if (instanceCandidate instanceof Class) {

instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);

}

Object result = instanceCandidate;

if (result instanceof NullBean) {

if (isRequired(descriptor)) {

raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);

}

result = null;

}

if (!ClassUtils.isAssignableValue(type, result)) {

throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());

}

// 返回对应的示例对象

return result;

}

finally {

ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);

}

}

此处主要根据类型获取所有匹配的bean,如果匹配的bean有多个,那么最后会选择一个符合条件的bean名称,然后将对应的bena实例返回,调用set方法进行进行注入,到此注入的原理本该结束了。但是还是要分析一下Spring Boot是如何选择出符合条件的bean?

选择符合条件的bean DefaultListableBeanFactory#determineAutowireCandidate

protected String determineAutowireCandidate(Map candidates, DependencyDescriptor descriptor) {

Class> requiredType = descriptor.getDependencyType();

// 如果bean对应的primary属性为true,则返回bean对应的名称

String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);

if (primaryCandidate != null) {

return primaryCandidate;

}

// 如果候选bean使用javax.annotation.Priority标注,返回高优先级bean对应的名称

String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);

if (priorityCandidate != null) {

return priorityCandidate;

}

// Fallback

// 如果匹配bean的名称和需要注入的属性名称一致,则返回匹配bean的名称

for (Map.Entry entry : candidates.entrySet()) {

String candidateName = entry.getKey();

Object beanInstance = entry.getValue();

if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||

matchesBeanName(candidateName, descriptor.getDependencyName())) {

return candidateName;

}

}

return null;

}

获取符合条件bean名称总结:

依据Bean的primary属性

依据javax.annotation.Priority

依据注入属性的名称

专车总结

Bean实例化完成后,填充Bean

调用AutowiredAnnotationBeanPostProcessor#postProcessProperties处理属性

获取所有需要注入的属性

根据注入属性的类型从IOC容器中查找匹配实例

如果匹配实例存在多个,根据primary属性--->javax.annotation.Priority注解--->注入属性名称依次过滤,返回符合条件的Bean名称

过滤之后,存在一个符合条件的Bean名称,则返回对应的实例,否则抛出异常

专车回顾

回顾一下开头的2个问题:

Spring Boot何时注入@Autowired标注的属性?

如果注入类型的Bean存在多个Spring Boot是如何处理的?

第一个问题:是在Bean实例化后,填充Bean的时候注入@Autowired标注的属性

第二个问题:如果存在多个类型的Bean,会根据primary--->javax.annotation.Priority--->名称依次过滤,得到最终匹配的bean名称

———— e n d ————

微服务、高并发、JVM调优、面试专栏等20大进阶架构师专题请关注公众号【Java进阶架构师】后在菜单栏查看。

看到这里,说明你喜欢本文

你的转发,是对我最大的鼓励!在看亦是支持

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值