java中@autowired,@Autowired的实现原理

  java中@autowired,@Autowired的实现原理

  

目录
@自动连线使用@自动连线源码分析1.查找所有@ Autowired2 .注入2.1 字段注入(AutowiredFieldElement)2.2方法注入(AutowiredMethodElement)

  

@Autowired使用

构造函数注入

  public Class Outer { private Inner Inner;@ Autowired public Outer(Inner Inner){ this。内=内;}}属性注入

  public Class Outer { @ auto wired private Inner Inner;}方法注入

  public Class Outer { private Inner Inner;public Inner getInner(){ return Inner;} @ Autowired public void set Inner(Inner Inner){ this。内=内;}}目前绝大部分的代码都使用第2、第3种。第一种在豆实例化时完成,而第2、第3种的实现原理都是一样的,在属性填充时完成。本篇将介绍第二第三种的是实现原理

  在开始之前,如果我们自己设计@Autowired,我们应该怎么实现?我想做法还是比较简单的

  通过反射查找豆的班级下所有注解了@自动连线的字段和方法获取到字段,通过getBean(字段)获取到对应豆子,然后再通过反射调用领域的设置将豆注入

  

@Autowired源码分析

AutowiredAnnotationBeanPostProcessor类

  该类是@自动连线的具体实现类,先预览一下类方法

  发现实际有机会介入豆的创建操作只有可能是后置处理器,用于后置处理的有3个方法,其中一个过时不用,分别是后期处理MergedBeanDefinition,后期处理属性后置处理,我们再看一下这注射毒品个方法的具体代码

  公共类AutowiredAnnotationBeanPostProcessor扩展instantiationwarebeanpostprocessor radapter实现MergedBeanDefinitionPostProcessor,PriorityOrdered,BeanFactoryAware {.@ Override public void postprocessmergedbean定义(root bean definition bean definition,Class?beanType,String beanName) { //1 .寻找豆中所有被@自动连线注释的属性,并将属性封装成注射元素类型注入元数据metadata=find autowiringmetadata(bean name,beanType,null);元数据。checkconfigmembers(bean定义);} .@ Override public property values postProcessProperties(属性值PVS,对象bean,字符串beanName) { //1 .寻找通过@自动连线注解的属性或者方法注入元数据metadata=find autowiringmetadata(bean name,bean.getClass(),PVS);试试{ //2。注入metadata.inject(bean,beanName,PVS);} catch(BeanCreationException ex){ throw ex;} catch(Throwable ex){ throw new bean creation exception(bean name,自动连线依赖项注入失败,ex);}返回PV;} .}跟我们的猜想是一样的,首先先找出所有注解了

  de>@Autowired的属性或者方法,然后进行注入,当然postProcessMergedBeanDefinition后置处理器的调用肯定是在postProcessProperties之前的,这里我们回顾一下spring bean的创建过程。

  2个处理器我已用黄色标出

  

  

  

1.查找所有@Autowired

// 寻找bean中所有被@Autowired注释的属性,并将属性封装成InjectedElement类型InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) { // Fall back to class name as cache key, for backwards compatibility with custom callers. // 获取缓存的key值,一般以beanName做key String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); // Quick check on the concurrent map first, with minimal locking. // 从缓存中获取metadata InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); // 检测metadata是否需要更新 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类,查找所有@Autowired的属性或者方法,并封装成InjectionMetadata类型 metadata = buildAutowiringMetadata(clazz); // 将metadata加入缓存 this.injectionMetadataCache.put(cacheKey, metadata); } } } return metadata; }
可以看到spring依然在用缓存的方式提高性能,继续跟踪核心代码buildAutowiringMetadata(clazz)

  

 private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) { // 查看clazz是否有Autowired注解 if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) { return InjectionMetadata.EMPTY; } // 这里需要注意AutowiredFieldElement,AutowiredMethodElement均继承了InjectionMetadata.InjectedElement // 因此这个列表是可以保存注解的属性和被注解的方法的 List<InjectionMetadata.InjectedElement> elements = new ArrayList<>(); Class<?> targetClass = clazz; // 1. 通过do while循环,递归的往直接继承的父类寻找@Autowired do { final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>(); // 2. 通过反射,获取所有属性,doWithLocalFields则是循环的对每个属性应用以下匿名方法 ReflectionUtils.doWithLocalFields(targetClass, field -> { // 判断当前field属性是否含有@Autowired的注解 MergedAnnotation<?> ann = findAutowiredAnnotation(field); if (ann != null) { // 返回该属性在类中的修饰符,如果等于static常量,则抛出异常,@Autowired不允许注解在静态属性上 if (Modifier.isStatic(field.getModifiers())) { if (logger.isInfoEnabled()) { logger.info("Autowired annotation is not supported on static fields: " + field); } return; } // @Autowired有required属性,获取required的值,默认为true boolean required = determineRequiredStatus(ann); // 3. 将field封装成InjectedElement,并添加到集合中,这里用的是AutowiredFieldElement currElements.add(new AutowiredFieldElement(field, required)); } }); // 4. @Autowired可以注解在方法上 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; } if (method.getParameterCount() == 0) { if (logger.isInfoEnabled()) { logger.info("Autowired annotation should only be used on methods with parameters: " + method); } } boolean required = determineRequiredStatus(ann); PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); // 5. 将方法封装成InjectedElement,并添加到集合中,这里用的是AutowiredMethodElement currElements.add(new AutowiredMethodElement(method, required, pd)); } }); elements.addAll(0, currElements); // 返回直接继承的父类 targetClass = targetClass.getSuperclass(); } // 如果父类不为空则需要把父类的@Autowired属性或方法也找出 while (targetClass != null && targetClass != Object.class); // 6. new InjectionMetadata(clazz, elements),将找到的所有的待注入属性或方法生成metadata返回 return InjectionMetadata.forElements(elements, clazz); }
外层 do … while … 的循环被用于递归的查找父类的@Autowired属性或方法通过反射的方式获取到所有属性并循环验证每一个属性是否被@Autowired注解将查找到包含@Autowired注解的filed封装成AutowiredFieldElement,加入到列表中循环查找在方法上的注解将找到的方法封装成AutowiredMethodElement,并加入列表这里需要特别强调一点,InjectedElementAutowiredFieldElementAutowiredMethodElement所继承,他们都有各自的inject函数,实现各自的注入。因此改ArrayList elements是拥有2种类型的属性

  

  将找到的所有元素列表和clazz作为参数生成metadata数据返回

  

2. 注入

// 注入metadata.inject(bean, beanName, pvs); public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { // 获取所有需要被注入的元素 Collection<InjectedElement> checkedElements = this.checkedElements; Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements); // 迭代的元素不为空 if (!elementsToIterate.isEmpty()) { for (InjectedElement element : elementsToIterate) { if (logger.isTraceEnabled()) { logger.trace("Processing injected element of bean " + beanName + ": " + element); } // 循环注入,这里有可能是AutowiredFieldElement也可能AutowiredMethodElement,因此调用的inject是2个不同的方法 element.inject(target, beanName, pvs); } } }
利用for循环,遍历刚刚我们查到到的elements列表,进行注入。

  在上面有特别提醒,这里的element有可能是AutowiredFieldElement类型、或AutowiredMethodElement类型。各自代表@Autowired注解在属性上、以及注解在方法上的2种不同元素。因此他们调用的element.inject(target, beanName, pvs);也是不一样的

  

  

2.1 字段注入(AutowiredFieldElement)

 private class AutowiredFieldElement extends InjectionMetadata.InjectedElement { @Override protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { Field field = (Field) this.member; Object value; if (this.cached) { value = resolvedCachedArgument(beanName, this.cachedFieldValue); } else { // 专门用于注入的包装类,包装构造函数参数,方法参数或字段 DependencyDescriptor desc = new DependencyDescriptor(field, this.required); // 设置class desc.setContainingClass(bean.getClass()); // 需要被自动注入的beanNames,这里只有可能 = 1,方法注入时才有可能为多个 Set<String> autowiredBeanNames = new LinkedHashSet<>(1); Assert.state(beanFactory != null, "No BeanFactory available"); TypeConverter typeConverter = beanFactory.getTypeConverter();// 获取类型转换器 try { // 通过beanFactory获取属性对应的值,比如需要调用getBean("b")获取依赖的属性单例,并且通过自动转型转为需要的类型 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); // 因为是属性注入,因此这里只有可能等于1 if (autowiredBeanNames.size() == 1) { String autowiredBeanName = autowiredBeanNames.iterator().next(); if (beanFactory.containsBean(autowiredBeanName) && beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { // 缓存当前value this.cachedFieldValue = new ShortcutDependencyDescriptor( desc, autowiredBeanName, field.getType()); } } } else { this.cachedFieldValue = null; } this.cached = true; } } } if (value != null) { // 通过反射,将value值设置到bean中 ReflectionUtils.makeAccessible(field); field.set(bean, value); } } }
上方大部分的工作都在做待注入bean的获取以及类型的转换,如果深究下去可以再把spring Ioc讲一遍,但是核心还是getBean(字段)获取到对应bean…我们这里就关心核心的语句,就是这2句

  

if (value != null) { // 通过反射,将value值设置到bean中 ReflectionUtils.makeAccessible(field); field.set(bean, value);}
spring通过反射的方式,调用field的set进行属性的注入

  

  

2.2 方法注入(AutowiredMethodElement)

 private class AutowiredMethodElement extends InjectionMetadata.InjectedElement { @Override protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { if (checkPropertySkipping(pvs)) { return; } // @Autowired标注在方法上 Method method = (Method) this.member; Object[] arguments; if (this.cached) { // Shortcut for avoiding synchronization... // 有缓存 arguments = resolveCachedArguments(beanName); } else { // 没缓存,直接获取方法上所有的参数 int argumentCount = method.getParameterCount(); arguments = new Object[argumentCount]; DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount]; Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount); 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[i] = currDesc; try { // 通过beanFactory,获取代注入的bean,并进行类型转换 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) { DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length); // 注册依赖 registerDependentBeans(beanName, autowiredBeans); // 如果自动注入的个数 = 参数个数,则缓存 if (autowiredBeans.size() == argumentCount) { Iterator<String> it = autowiredBeans.iterator(); Class<?>[] paramTypes = method.getParameterTypes(); 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 { // 反射调用注入方法,将获取到的所有bean作为参数 ReflectionUtils.makeAccessible(method); method.invoke(bean, arguments); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } } } }
这里与属性注入最大的区别在于,@Autowired注解在方法上,方法可以拥有多个参数,因此这里需要通过循环将一个个获取,而获取bean的方式于上面一样,本质都是通过getBean获取。

  而核心语句还是2句

  

// 反射调用注入方法,将获取到的所有bean作为参数ReflectionUtils.makeAccessible(method);method.invoke(bean, arguments);
与属性注入不同的是,当@Autowired注解在方法上,例如我们注解在setter方法上,则只需要直接调用该setter方法将参数数组传入即可以,即使用invoke触发方法,具体属性赋值的过程在setter方法中由用户自行编写

  到此这篇关于Java超详细分析@Autowired原理的文章就介绍到这了,更多相关Java @Autowired内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: