美文网首页
spring源码解析二(@Autowired注解原理分析)

spring源码解析二(@Autowired注解原理分析)

作者: 为梦想前进 | 来源:发表于2020-04-24 14:26 被阅读0次

一直以来,我们使用某个类的时候,基本上都是通过@Autowired注解通过接口将实现类注入进来,但是我们有没有想过,这个注解到底是怎样工作的
怎嘛就可以通过他调用实现类的方法.今天我们就来一起研究下,这个东西到底是怎嘛一回事,
手下我们看看这个@Autowired注解,首先看下他的定义
1:将构造方法,字段,set方法或者config方法标记为由spring的依赖项注入工具自动装配,用于替代JSR-330的Inject注解

2:也可以注入集合类型或者map类型,但是必须要将映射的键设置为String类型,因为spring会将这个String代表的字符串定义为bean的名称

说道这里,我们写个demo,实验下,还没有这样用过,
定义一个接口

public interface CoreService {
    /**
     * 注入的名称
     * @return
     */
    String getCourseName();

    /**
     * 调用分支方法
     */
    void dohandle();
}
定义两个类实现这个接口
@Service
public class LionClass implements CoreService {

    @Override
    public String getCourseName() {
        return "我是狮子";
    }

    @Override
    public void dohandle() {
        System.out.println("奔跑速度是80公里每小时");
    }
}

@Service
public class TrigerClass implements CoreService {

    private static final String name = "";


    @Override
    public String getCourseName() {
        return "我是老虎";
    }

    @Override
    public void dohandle() {
        System.out.println("奔跑速度每小时50公里");
    }
}

写个测试类实验下
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestClass {


    @Autowired
    private Set<CoreService> coreServices;


    @Test
    public void test(){
        System.out.println(coreServices);
        for (CoreService coreService : coreServices) {
            coreService.dohandle();
        }
    }
}

如果你运行成功了,会打印以下信息
[com.ryx.xiaoxin_distribute.spring.springIocAndAop.IOC.autowire.ioc3.LionClass@1d2c253, com.ryx.xiaoxin_distribute.spring.springIocAndAop.IOC.autowire.ioc3.TrigerClass@15a484a9]
奔跑速度是80公里每小时
奔跑速度每小时50公里
这个很有用,当我们在项目中,某些类同属于一个业务,我们就可以定义让他们实现同一个接口,就好像类似于策略模式的味道,是不是

我们接着往下看,在源码中,告诉我们有一个类:AutowiredAnnotationBeanPostProcessor,该类是@Autowired的具体实现类,里面方法很多,
我们看下他的继承关系

发现实际有机会对bean的创建操作只是后置处理器,用于后置处理的有3个方法,postProcessPropertyValues(已过时)
分别是
1:postProcessMergedBeanDefinition
2:postProcessProperties

创建对象的时候,会调用postProcessMergedBeanDefinition方法,将需要注入的属性或者方法(包括父类上)set到InjectionMetadata对象中
需要注入的属性或者方法已经准备就绪,接下来,就是填充属性,这个时候就会去调用postProcessProperties方法,所以真正的注入方法也是在
这里完成的
先来分析第一个方法

@Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        //查询所有标注了Autowired注解的属性或者方法
        InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
        //检查配置成员
        metadata.checkConfigMembers(beanDefinition);
    }

    private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
            // 检查beanName是否为空,不为空的话,直接去缓存中获取beanName对应的元数据,否则通过反射的方式获取beanName
            String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
            // 缓存中获取beanName对应的元数据
            InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
            //检查元数据的metadata是否为null或者原数中的calzz是否和当前的clazz相等,这里看到,使用synchronized加锁的方式进行了双重检查
            if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                synchronized (this.injectionMetadataCache) {
                    metadata = this.injectionMetadataCache.get(cacheKey);
                    if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                        if (metadata != null) {
                            //清除属性值
                            metadata.clear(pvs);
                        }
                        //构建自动装配元数据
                        metadata = buildAutowiringMetadata(clazz);
                        //将beanName放入缓存中
                        this.injectionMetadataCache.put(cacheKey, metadata);
                    }
                }
            }
            return metadata;
        }

        //这段代码都是在循环调用,然后查询每个类的属性上或者方法上是否有@Autowired注解,
        private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
        List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
        Class<?> targetClass = clazz;

        do {
            //定义存放整合属性注解或者方法注解的集合,注意这里,会将参数注解和方法注解放在一个集合汇总
            final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

            //通过反射获取每个类上的属性上是否存在@Autowired注解
            ReflectionUtils.doWithLocalFields(targetClass, field -> {
                AnnotationAttributes ann = findAutowiredAnnotation(field);
                if (ann != null) {
                    if (Modifier.isStatic(field.getModifiers())) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Autowired annotation is not supported on static fields: " + field);
                        }
                        return;
                    }
                    boolean required = determineRequiredStatus(ann);
                    //将当前存在Autowired注解的属性放入集合中
                    currElements.add(new AutowiredFieldElement(field, required));
                }
            });

            //通过反射获取每个类上的方法上是否存在@Autowired注解
            ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                    return;
                }
                AnnotationAttributes 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;
                    }
                    if (method.getParameterCount() == 0) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Autowired annotation should only be used on methods with parameters: " +
                                    method);
                        }
                    }
                    //这里注意下@Autowired(required = true),意思是说,如果当前属性找不到依赖注入的bean,就会报错.
                    //也就是说在required为true的时候(我们一般不配置,默认就是true),但是找不到依赖的bean的时候,就会报错了,
                    //所以,当这里我们确定不需要注入某个属性的时候,可以赋值为false,会自动跳过注入的
                    boolean required = determineRequiredStatus(ann);
                    //获取方法上的属性值
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                    //将当前存在Autowired注解的方法放入集合中
                    currElements.add(new AutowiredMethodElement(method, required, pd));
                }
            });
            //添加全部元素到集合
            elements.addAll(0, currElements);
            //获取父类
            targetClass = targetClass.getSuperclass();
        }
        //如果父类不为空,循环父类上是否也存在注解,也需要一起找出来
        while (targetClass != null && targetClass != Object.class);

        //返回所有准备注入的方法或者属性
        return new InjectionMetadata(clazz, elements);
    }

我们简单总结下上面的步骤,
1:使用do while循环查询每个类的属性或者方法上是否存在@AutoWired注解
2:如果是属性上存在@Autowired注解,执行doWithLocalFields查询缓存中是否存在,如果不存在,再利用反射的方式或者属性值,判断属性上
是否存在@Autowired注解,存在的话,就添加到集合中
3:使用doWithLocalMethods遍历方法上是否存在@Autowired注解,同样的,也会先去缓存中查询,存在了,就直接返回添加到集合中,不存在,就利用
反射获取,然后额外的步骤是,获取方法的参数,一并放入集合中
4:获取目标类的父类,查询父类上是否存在@Autowired注解,循环上面的步骤,
5:返回注入元数据对象InjectionMetadata

接下来,我们一起来分析下,真正的注入方法postProcessProperties

@Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
        //查询元数据对象
        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;
    }

    public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
            //获取当前bean有中对应的属性或者方法(带有@AutoWired注解的)
            Collection<InjectedElement> checkedElements = this.checkedElements;
            Collection<InjectedElement> elementsToIterate =
                    (checkedElements != null ? checkedElements : this.injectedElements);
            //遍历elementsToIterate
            if (!elementsToIterate.isEmpty()) {
                for (InjectedElement element : elementsToIterate) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Processing injected element of bean '" + beanName + "': " + element);
                    }
                     //调用inject执行注入
                     //如果是属性注入.调用的就是AutoworedFieldElement.inject方法
                     //如果是方法注入,调用的就是AutoworedMethodElement.inject方法
                    element.inject(target, beanName, pvs);
                }
            }
        }


#AutoworedFieldElement
        @Override
                protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
                    //获取属性值
                    Field field = (Field) this.member;
                    Object value;
                    //缓存中是否存在
                    if (this.cached) {
                        //如果缓存中存在,判断属性值是否是DependencyDescriptor(注入包装类)对象,如果是执行依赖解决
                        value = resolvedCachedArgument(beanName, this.cachedFieldValue);
                    }
                    else {
                        //创建注入包装类对象
                        DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
                        desc.setContainingClass(bean.getClass());
                        //创建set集合,可以看到set集合创建的大小只有1,因为这里是属性注入只有一个
                        Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
                        Assert.state(beanFactory != null, "No BeanFactory available");
                        //从BeanFactory中活属性转换器
                        TypeConverter typeConverter = beanFactory.getTypeConverter();
                        try {
                            //铜鼓BeanFactory获取属性对应的值,并转换为对应的类型,
                            value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
                        }
                        catch (BeansException ex) {
                            throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
                        }
                        //如果当前缓存中不存在,就将当前的bean通过registerDependentBeans方法添加奥dependenciesForBean集合中
                        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);
                        //通过反射设置bean属性值为value
                        field.set(bean, value);
                    }
                }
            }

   #AutoworedMethodElement(方法属性注入)
            @Override
                    protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
                        if (checkPropertySkipping(pvs)) {
                            return;
                        }
                        //获取方法对象
                        Method method = (Method) this.member;
                        Object[] arguments;
                        //查询缓存中是否存在
                        if (this.cached) {
                            // Shortcut for avoiding synchronization...
                            arguments = resolveCachedArguments(beanName);
                        }
                        else {
                            //获取参数类型
                            Class<?>[] paramTypes = method.getParameterTypes();
                            //定义参数数组对象
                            arguments = new Object[paramTypes.length];
                            //定义注入包装类数组
                            DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length];
                            //定义集合
                            Set<String> autowiredBeans = new LinkedHashSet<>(paramTypes.length);
                            Assert.state(beanFactory != null, "No BeanFactory available");
                            //获取类型转换器
                            TypeConverter typeConverter = beanFactory.getTypeConverter();
                            //循环参数数组
                            for (int i = 0; i < arguments.length; i++) {
                                //获取方法参数对象
                                MethodParameter methodParam = new MethodParameter(method, i);
                                //创建定义包装类对象
                                DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
                                currDesc.setContainingClass(bean.getClass());
                                //将当前的包装类对象放入到descriptors中
                                descriptors[i] = currDesc;
                                try {
                                    //通过beanFactory根据beanName,类型,获取参数
                                    Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
                                    if (arg == null && !this.required) {
                                        arguments = null;
                                        break;
                                    }
                                    arguments[i] = arg;
                                }
                                catch (BeansException ex) {
                                    throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
                                }
                            }
                            //执行添加缓存操作
                            synchronized (this) {
                                if (!this.cached) {
                                    if (arguments != null) {
                                        Object[] cachedMethodArguments = new Object[paramTypes.length];
                                        System.arraycopy(descriptors, 0, cachedMethodArguments, 0, arguments.length);
                                        registerDependentBeans(beanName, autowiredBeans);
                                        if (autowiredBeans.size() == paramTypes.length) {
                                            Iterator<String> it = autowiredBeans.iterator();
                                            for (int i = 0; i < paramTypes.length; i++) {
                                                String autowiredBeanName = it.next();
                                                if (beanFactory.containsBean(autowiredBeanName) &&
                                                        beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
                                                    cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
                                                            descriptors[i], autowiredBeanName, paramTypes[i]);
                                                }
                                            }
                                        }
                                        this.cachedMethodArguments = cachedMethodArguments;
                                    }
                                    else {
                                        this.cachedMethodArguments = null;
                                    }
                                    this.cached = true;
                                }
                            }
                        }
                        if (arguments != null) {
                            try {
                                ReflectionUtils.makeAccessible(method);
                                //通过反射调用赋值
                                method.invoke(bean, arguments);
                            }
                            catch (InvocationTargetException ex) {
                                throw ex.getTargetException();
                            }
                        }
                    }

简单总结下,当我们开始为对象填充属性的时候,就要开始对象中注入了
1:获取注入对象集合
2:判断是属性注入还是方法注入,如果是属性注入,调用AutowiredFileldElement.inject方法
2.1:判断缓存中是否存在,存在,直接调用resolvedCachedArgument解决依赖
2.2:添加到缓存中
2.3:最后通过反射执行属性赋值
3:如果是方法注入:调用AutowiredMethodElement.inject方法
3.1:判断缓存中是否存在,存在,直接调用resolvedCachedArgument
3.2:循环获取方法中的参数,
3.3:执行缓存添加操作
3.4:通过反射调用赋值

通过以上步骤,依赖注入就完成了,相当于我们为类中的有@Autowired注解的对象完成了赋值操作!可能大家有一个疑问.我们不是注解的接口吗
他到底是怎样完成实现类的赋值的那,我们再具体分析下
1:首先,@Autowired会先通过类型去找对应的bean,如果是接口,就会去找实现类,找不到,在按照id为属性名去找,如果多个类实现一个接口,这个时候
会有多个bean,这个时候,会报错:required a single bean, but 2 were found:出现这样的情况,怎嘛解决那
我们需要处理下,告诉spring,我们到底要加载哪一个,既然spring分不了,我们就手动,区分下,我们属性名称改下,就可以了
比如如下:RyxAccountImpl和RyxPayImpl实现了同一个接口,直接这样写会报错,

public interface RyxAccount {
    void save();
}

@Service
public class RyxAccountImpl implements RyxAccount {
    @Override
    public void save() {
        System.out.println("账户保存");
    }
}

@Service
public class RyxPayImpl implements RyxAccount {

    @Override
    public void save() {
    System.out.println("支付");
    }
}

@Autowired
private RyxAccount ryxAccount;

这样的话,怎嘛处理那,也不难,既然为属性赋值的时候,spring区分不开怎嘛办,那就告诉她先加载哪一个,后加载哪一个,
所以我们可以任意一个需要类上添加@Primary(只能添加一个),这样的话,spring在读取到这里,发现两个bean,就知道先加载哪一个了,
下一个问题.这样我们引入的时候,就会一直先去读取第一次加载的bean,这可不行,怎嘛解决那,简单,我们为bean起个别名,就可以解决以上问题了
再看看修改后的实例

@Service("ryxAccountImpl")
public class RyxAccountImpl implements RyxAccount {
    @Override
    public void save() {
        System.out.println("账户保存");
    }
}


//这里告诉spring先加载RyxPayImpl这个bean
@Service("ryxPayImpl")
@Primary
public class RyxPayImpl implements RyxAccount {
    @Override
    public void save() {
    System.out.println("支付");
    }
}

//使用哪个bean,就使用@Qualifier注解指定即可
@Autowired
@Qualifier("ryxAccountImpl")
private RyxAccount ryxAccount;

2:赋值成功后,最终的结果就是这个样子了RyxAccount ryxAccount = new RyxAccountImpl();使用多态的向上转型得到结果
其实就和我们平时new对象一样的,如果不注入,就是这样new出来呗,分析到这里,终于有点眉目了,这就是spring的依赖注入
其实就是将类的属性通过注解解析完成完成反射并为属性赋值最终通过多态的向上转型达到目的,这样,我们在后面使用的时候,随取随用再也不用new了,可以直接去IOC容器中取了!

相关文章

网友评论

      本文标题:spring源码解析二(@Autowired注解原理分析)

      本文链接:https://www.haomeiwen.com/subject/bnjaihtx.html