Spring中依赖注入底层原理与源码分析

Spring中依赖注入底层原理与源码分析

前言:Spring框架是一套非常成熟的框架,同时也被大多数开发者所喜欢。在Spring中我们通常用到@Autowired注解,也就是我们常说的依赖注入。那么本篇文章带大家一起分析@Autowired注解的底层逻辑是什么,它是如何帮助Spring实现依赖注入的。这也是面试中常问到的。下面我们开具体分析。

Spring中到底有几种依赖方式?

在了解Spring中依赖注入底层原理之前先问大家一个问题,那就是Spring中到底有几种依赖方式?网上有的说3种,有的说5种。在这里我们从Spring的源头去分析,首先依赖注入分为手动注入和自动注入两种情况。手动注入:指的是开发者自己在XML文件给对应的bean手动的赋值。自动注入值得是Spring自动帮助我们进行依赖注入。


情况一:手动注入之set方法注入,例如:




    
    
    
    
        
    
    


@Component
public class UserService {

    private OrderService orderService;


    public void setOrderService(OrderService orderService) {
        this.orderService = orderService;
    }

    public void test(){
        System.out.println(orderService);
    }
}

情况一:手动注入之构造方法注入,例如:




    
    
    
    
              
    

package com.autowired.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class UserService {

    private OrderService orderService;

    public UserService(OrderService orderService) {
        this.orderService = orderService;
    }

    public void test(){
        System.out.println(orderService);
    }


}


情况二:自动注入之XML自动注入

1.set方法注入




    
    
    
    
    
    


@Component
public class UserService {

    private OrderService orderService;


    public void setOrderService(OrderService orderService) {
        this.orderService = orderService;
    }

    public void test(){
        System.out.println(orderService);
    }
}

 set方法注入的自动注入同样的也分为两种方式:

  • 一种是byName,byName的工作流程:我们以UserService这个类为例,Spring在启动的时候会解析你的XML文件,解析过后发现你是通过byName方式去自动注入的,然后就会去UserService这个类去找所有的Set方法,取Set方法的名字(例如:setOrderService---->orderService),然后根据orderService这个beanName去Spring容器中去找这个bean对象,然后将这个bean对象赋值给UserService的OrderService属性。
  • 一种是byType。byType的工作流程:我们以UserService这个类为例,Spring在启动的时候会解析你的XML文件,解析过后发现你是通过byType方式去自动注入的,,然后就会去UserService这个类去找所有的Set方法,取Set方法的第一个参数的类型(OrderService),然后根据这个类型去Spring容器中去找对应的bean对象,然后将这个bean对象赋值给UserService的OrderService属性。

 注意:Set方法的依赖注入byType方式,有可能造成找到多个bean对象。Spring中有一套机制去筛选出唯一的一个bean。我们后面去了解这套机制。

  2.构造方法注入




    
    
    
    
    
    
package com.autowired.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class UserService {

    private OrderService orderService;

    public UserService(OrderService orderService) {
        this.orderService = orderService;
    }

    public void test(){
        System.out.println(orderService);
    }


}

构造方法注入的工作流程:我们还是以UserService这个类为例,Spring在启动的时候会解析你的XML文件,解析过后发现你是通过constructor方式去自动注入的,然后就会去UserService这个类去找构造方法,取构造方法的类型(OrderService),然后根据OrderService这个类型去Spring容器中去找这个bean对象,如果发现找到了多个对象,在根据构造方法的参数名(orderService)去找,找到唯一的一个,然后将这个bean对象赋值给UserService的OrderService属性。

 注意:Spring在使用XML时默认将autowire这个功能时关闭的。

 情况二:@Autowired注解的自动注入

随着Spring的发展,Spring将XML中的一些功能以注解的形式抽取出来,并作出了一些优化。例如:标签抽取成@bean,autowire抽取成@Autowired注解等等

@Autowired的注解有两种使用方式:分别是ClassPathXmlApplicationContext 的XML配置文件形式和AnnotationConfigApplicationContext的配置类的形式。

/**
 * 使用AnnotationConfigApplicationContext可以实现基于Java的配置类加载Spring的应用上下文。
 * 避免使用application.xml进行配置。相比XML配置,更加便捷。
 */
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("Spring.xml");
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

在使用XML配置文件需要添加下面配置: 打开注解使用权限 

  
    

用@Autowired注解存在多种方式:例如在属性,构造方法,普通方法上注入。

//注意:@Autowired只能加一次,这里为了阅读效果才这样写。
@Component
public class UserService {
    
    @Autowired
    private OrderService orderService;
    
    @Autowired
    public UserService(OrderService orderService) {
        this.orderService = orderService;
    }

    @Autowired
    public void fangfa(OrderService orderService,OrderService orderService1){
        this.orderService = orderService;
    }

    public void test(){
        System.out.println(orderService);
    }
}

普通方法注入的工作过程:首先会根据普通方法的第一个参数的类型去Spring中去找bean,如果找到多个bean对象,再根据第一个参数的名称去确定唯一的一个。这样参数一就有值了,也就是先byType再byName。参数二同参数一。

总结:

无论在是属性,构造,普通方法用@Autowired注解,都是通过先byType再byName的形式。

1.Spring中到底有几种依赖方式?
1.手动注入(set方法、构造方法)
2.自动注入
   1.XML自动注入(set方法、构造方法)
   2.@Autowired注解的自动注入(属性、构造方法、普通方法)

 @Autowired注解的底层原理

如果想要了解@Autowired底层原理,我们要去看AutowiredAnnotationBeanPostProcessor这个类实现了@Autowired注解的功能。

@Autowired注解的底层原理工作流程

Spring中依赖注入底层原理与源码分析_第1张图片

@Autowired底层原理之注入点扫描

1.寻找注入点调用方法

InjectionMetadata表示当前这个类所有注入点的集合。InjectedElement表示注入点,这个类有两个子类:AutowiredFieldElement表示属性的注入点、AutowiredMethodElement表示方法的注入点。

注入点就是在某个类中加了@Autowired注解的某个属性或方法。

    //寻找注入点
@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) {
        //获取beanType中的注入点
		InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
		metadata.checkConfigMembers(beanDefinition);
	}

 注入点的定义

public abstract static class InjectedElement {
       //是否注入的是一个方法
		protected final Member member;
   
        //是否注入的是一个字段
		protected final boolean isField;

		@Nullable
		protected final PropertyDescriptor pd;

		@Nullable
		protected volatile Boolean skip;

		....省略
		}

寻找注入点的外层逻辑。 

private InjectionMetadata findAutowiringMetadata(String beanName, Class clazz, @Nullable PropertyValues pvs) {
		// Fall back to class name as cache key, for backwards compatibility with custom callers.
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
		// 先去缓存中寻找注入点,如果找不到则调用真正寻找的方法buildAutowiringMetadata
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
		if (InjectionMetadata.needsRefresh(metadata, clazz)) {
			synchronized (this.injectionMetadataCache) {
				metadata = this.injectionMetadataCache.get(cacheKey);
				if (InjectionMetadata.needsRefresh(metadata, clazz)) {
					if (metadata != null) {
						metadata.clear(pvs);
					}
                   //寻找当前Clazz中的注入点,把所有注入点整合成为一个InjectionMetadata对象
					metadata = buildAutowiringMetadata(clazz);
                   //将找到的注入点放入缓存,方便下次调用
					this.injectionMetadataCache.put(cacheKey, metadata);
				}
			}
		}
		return metadata;
	}

寻找注入点的内部逻辑。

private InjectionMetadata buildAutowiringMetadata(final Class clazz) {
        //判断是不是候选者类,比如说类名,如果是以”Java“开头的则不是候选者类
        if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
            return InjectionMetadata.EMPTY;
        }

        List elements = new ArrayList<>();
        Class targetClass = clazz;

        do {
            final List currElements = new ArrayList<>();
            //遍历属性,看是否有@Autowired,@Value,@Inject(注入)注解
            ReflectionUtils.doWithLocalFields(targetClass, field -> {
                MergedAnnotation ann = findAutowiredAnnotation(field);
                //如果存在@Autowired,@Value,@Inject注解中的其中一个
                if (ann != null) {
                    //如果字段是静态(static)的,则直接进行返回,不进行注入
                    if (Modifier.isStatic(field.getModifiers())) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Autowired annotation is not supported on static fields: " + field);
                        }
                        return;
                    }
                    //是否required(是否必须注入)
                    boolean required = determineRequiredStatus(ann);
                    //生成一个注入点AutowiredFieldElement
                    currElements.add(new AutowiredFieldElement(field, required));
                }
            });
            //遍历方法,看是否有@Autowired,@Value,@Inject注解
            ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                    return;
                }
                MergedAnnotation ann = findAutowiredAnnotation(bridgedMethod);
                if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                    //静态方法不能用来注入属性
                    if (Modifier.isStatic(method.getModifiers())) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Autowired annotation is not supported on static methods: " + method);
                        }
                        return;
                    }
                    //方法的参数为0,不能用来注入属性
                    if (method.getParameterCount() == 0) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Autowired annotation should only be used on methods with parameters: " +
                                    method);
                        }
                    }
                    是否required(是否必须注入)
                    boolean required = determineRequiredStatus(ann);
                    //根据方法找出对应的属性
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                    //生成一个注入点AutowiredFieldElement
                    currElements.add(new AutowiredMethodElement(method, required, pd));
                }
            });
            //将注入点放入集合中
            elements.addAll(0, currElements);
            //去父类寻找注入点
            targetClass = targetClass.getSuperclass();
        }
        while (targetClass != null && targetClass != Object.class);

        return InjectionMetadata.forElements(elements, clazz);
    }

以上就完成了注入点的扫描,并将所有的注入点封装为一个List,InjectionMetadata表示当前这个类所有注入点的集合

@Autowired底层原理之注入点注入

注入点进行注入之属性注入逻辑,这个方法属于AutowiredFieldElement这个类。


    protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
        Field field = (Field) this.member;
        Object value;
        if (this.cached) {
            //当前注入点已经注入过了,有缓存了,则利用cachedFieldValue去找对应的bean
            value = resolvedCachedArgument(beanName, this.cachedFieldValue);
        }
        else {
            //Spring在真正查找属性对应的对象之前,会先将该属性的描述封装成一个
            DependencyDescriptor desc = new DependencyDescriptor(fieldDependencyDescriptor, this.required);
            desc.setContainingClass(bean.getClass());
            Set autowiredBeanNames = new LinkedHashSet<>(1);
            Assert.state(beanFactory != null, "No BeanFactory available");
            TypeConverter typeConverter = beanFactory.getTypeConverter();
            Object value;
            try {
                //根据field去寻找合适的bean
                value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
            } catch (BeansException ex) {
                throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
            }
            //找到bean之后
            synchronized (this) {
                if (!this.cached) {
                    Object cachedFieldValue = null;
                    if (value != null || this.required) {
                        cachedFieldValue = desc;
                        //注册当前的bean依赖了哪些其他的bean的name
                        registerDependentBeans(beanName, autowiredBeanNames);
                        if (autowiredBeanNames.size() == 1) {
                            String autowiredBeanName = autowiredBeanNames.iterator().next();
                            if (beanFactory.containsBean(autowiredBeanName) &&
                                    beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                                //对得到的对象进行缓存
                                this.cachedFieldValue = new AutowiredAnnotationBeanPostProcessor.ShortcutDependencyDescriptor(
                                        desc, autowiredBeanName, field.getType());
                            }
                        }
                    } else {
                        this.cachedFieldValue = null;
                    }
                    this.cached = true;
                }
            }
        }
        //反射设值
        if (value != null) {
            ReflectionUtils.makeAccessible(field);
            field.set(bean, value);
        }
    }

 根据field去寻找合适的bean的逻辑

 @Override
    @Nullable
    public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
                                    @Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
       //DependencyDescriptor表示一个依赖,可以是一个属性字段,可能是一个构造方法参数,可能是一个set方法参数
        //根据descriptor属性去BeanFactory中去找到bean
        descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
        //如果依赖的类型是Optional
        if (Optional.class == descriptor.getDependencyType()) {
            return createOptionalDependency(descriptor, requestingBeanName);
        }
        //如果依赖的类型是ObjectFactory
        else if (ObjectFactory.class == descriptor.getDependencyType() ||
                ObjectProvider.class == descriptor.getDependencyType()) {
            return new DefaultListableBeanFactory.DependencyObjectProvider(descriptor, requestingBeanName);
        }
        //如果依赖的类型是javaxInjectProviderClass
        else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
            return new DefaultListableBeanFactory.Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
        }
        else {
            //在使用@Autowired注解时,也可以使用@Lazy注解,到时候注入的会是一个代理对象
            Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
                    descriptor, requestingBeanName);
            if (result == null) {
                //通过解析descriptor(属性)找到bean对象
                result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
            }
            return result;
        }
    }

@Autowired底层原理之候选者筛选

 通过解析descriptor(属性)找到bean对象

/**
     * 根据属性信息,去得到bean对象
     * @param descriptor 属性
     * @param beanName 当前bean的名字
     * @param autowiredBeanNames 所有bean名称的集合
     * @param typeConverter 属性类型
     * @return
     * @throws BeansException
     */
    @Nullable
    public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
                                      @Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

        InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
        try {
            /**
             * 如果DependencyDescriptor是一个ShortcutDependencyDescriptor,
             * 那么会直接根据beanName从beanFactory中拿到一个bean,
             * 再利用@Autowired注解来进行依赖注入时会利用ShortcutDependencyDescriptor来进行依赖注入的缓存,
             * 表示当解析完某个依赖信息后,会把依赖的bean的beanName缓存起来
             */
            Object shortcut = descriptor.resolveShortcut(this);
            if (shortcut != null) {
                return shortcut;
            }
            //获取descriptor具体的类型,某个field的类型或某个方法参数的类型
            Class type = descriptor.getDependencyType();
            //获取@Value注解中所配置的值
            //是否通过@Value注解指定的值
            Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
            if (value != null) {
                if (value instanceof String) {
                    //先进行占位符的填充,解析”$“符号
                    String strVal = resolveEmbeddedValue((String) value);
                    BeanDefinition bd = (beanName != null && containsBean(beanName) ?
                            getMergedBeanDefinition(beanName) : null);
                    //解析Spring EL表达式,解析”#“符号(可以进行运算,可以写某个bean的名字)
                    value = evaluateBeanDefinitionString(strVal, bd);
                }
                //如果得到的value值与field属性的类型,不匹配,则需要进行类型转换,需要开发者自己实现类型转换器的功能
                //Spring并没有帮我们实现。如果没有类型转换器则会抛出异常。
                TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
                try {
                    return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
                }
                catch (UnsupportedOperationException ex) {
                    // A custom TypeConverter which does not support TypeDescriptor resolution...
                    return (descriptor.getField() != null ?
                            converter.convertIfNecessary(value, type, descriptor.getField()) :
                            converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
                }
            }
            //没有使用@Value注解的情况下走下面的代码
            //如果要注入的依赖的类型是一个Map,Array,Collection
            Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
            if (multipleBeans != null) {
                //直接返回所有的候选者
                return multipleBeans;
            }
            //如果注入的依赖的类型不是一个Map,Array,Collection
           //通过by_type找,可能找到多个bean对象,这里的value,可能时具体的对象,也可能暂时只是Class对象。也就是寻找候选者。
            Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);
            //如果matchingBeans为空
            if (matchingBeans.isEmpty()) {
                //判断@Autowired注解的isRequired是否为true
                if (isRequired(descriptor)) {
                    //如果是true,则抛出异常
                    raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
                }
                return null;
            }

            String autowiredBeanName;
            Object instanceCandidate;
            //根据type找到了多个bean对象
            if (matchingBeans.size() > 1) {
                //找到多个,去尝试确定出唯一的一个bean的名字
                /**
                 * 筛选逻辑:去遍历所有的候选者是否有@Primary注解,如果只有一个bean有@Primary注解则返回这个bean对象的名字。
                 * 如果有多个bean都没有@Primary注解,则选出优先级最高的bean对象的名字。通过@Priority来定义优先级,数字越小
                 * 优先级越高。如果上述步骤都没有招待唯一的bean对象,则通过by_name去找。
                 * 
                 * 如果都没有找到,则只能返回为空。
                 */
                autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
                //如果筛选后,返回为空
                if (autowiredBeanName == null) {
                    if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
                        //如果找到多个,并且当前依赖是required,或者不是数组或Collection或Map,则抛出异常
                        return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
                    }
                    else {
                        // 直接返回为空
                        return null;
                    }
                }
                instanceCandidate = matchingBeans.get(autowiredBeanName);
            }
            else {
                // 根据类型只能找到一个bean对象
                Map.Entry entry = matchingBeans.entrySet().iterator().next();
                autowiredBeanName = entry.getKey();
                instanceCandidate = entry.getValue();
            }
           //后续代码就是对找到的bean对象进行一些封装和校验
            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);
        }
    }

 

你可能感兴趣的:(Spring原理,spring,java,面试,后端)