spring中自动注入注解的实现方式
作者:潭影空人心
在前面的文章中,我们介绍过,基于注解的包扫描模式下,会默认注册一系列的后置处理器,其中,就包含一个 AutowiredAnnotationBeanPostProcessor,这个处理器默认就会处理 @Autowired 和 @Value 注解。
类结构
从图中可知,这是一个 MergedBeanDefinitionPostProcessor 实现类,所以会在每一个实例对象创建时,当实例化结束,还未提前暴露时,对实例对象进行处理。
// AutowiredAnnotationBeanPostProcessor @Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null); metadata.checkConfigMembers(beanDefinition); }
获取注解
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) { // 确定缓存 key String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); // 从缓存获取 InjectionMetadata InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); // metadata 为 null,表示需要刷新 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 metadata = buildAutowiringMetadata(clazz); // 放入缓存 this.injectionMetadataCache.put(cacheKey, metadata); } } } return metadata; } private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) { // autowiredAnnotationTypes 两种类型 @Autowired/@Value if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) { return InjectionMetadata.EMPTY; } List<InjectionMetadata.InjectedElement> elements = new ArrayList<>(); Class<?> targetClass = clazz; do { final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>(); // 处理 Field 上注解 ReflectionUtils.doWithLocalFields(targetClass, field -> { MergedAnnotation<?> ann = findAutowiredAnnotation(field); if (ann != null) { // static 不支持注入 if (Modifier.isStatic(field.getModifiers())) { if (logger.isInfoEnabled()) { logger.info("Autowired annotation is not supported on static fields: " + field); } return; } // 默认 true boolean required = determineRequiredStatus(ann); currElements.add(new AutowiredFieldElement(field, required)); } }); // 处理 Method 上注解 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); // Method 比 Field 多了 PropertyDescriptor PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); 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); } @Nullable private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) { // TypeMappedAnnotations MergedAnnotations annotations = MergedAnnotations.from(ao); for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) { // 获取指定 type 对应的 TypeMappedAnnotation,存在,将对应的 TypeMappedAnnotation 返回 MergedAnnotation<?> annotation = annotations.get(type); if (annotation.isPresent()) { return annotation; } } return null; }
可以看到,获取当前类及其父类中 Field 或 Method 上定义的注解,此时封装为 TypeMappedAnnotations,接着获取指定注入注解类型对应的 TypeMappedAnnotation,存在,返回 TypeMappedAnnotation,从中获取注解属性 "required" 对应的值,默认 true,之后将 Field 或 Method 封装成 InjectionMetadata.InjectedElement,加入 elements 集合,最后包装成 InjectionMetadata,放入 AutowiredAnnotationBeanPostProcessor 中 injectionMetadataCache 缓存。
有一点要注意,就是 Method 注入时,虽然获取了 pd,但测试中 pd 为 null,也不影响注入,由此也说明注入的方法不一定必须是 setter 或 getter 方法。
注入
实例化完 bean 之后,进行属性填充,执行 AbstractAutowireCapableBeanFactory#populateBean,此时会调用 InstantiationAwareBeanPostProcessor#postProcessProperties,AutowiredAnnotationBeanPostProcessor 实现了这个方法。
@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; }
findAutowiringMetadata 前面已经介绍过了,此时会直接从缓存获取到 InjectionMetadata。
// InjectionMetadata 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) { element.inject(target, beanName, pvs); } } }
遍历,对每个 InjectedElement,调用 inject 方法。从上面介绍可知,InjectedElement 共两种,分别是针对 Field 的 AutowiredFieldElement,以及针对 Method 的 AutowiredMethodElement。下面分别介绍。
Field 注入
@Override protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { Field field = (Field) this.member; Object value; // false if (this.cached) { try { value = resolvedCachedArgument(beanName, this.cachedFieldValue); } catch (NoSuchBeanDefinitionException ex) { // Unexpected removal of target bean for cached argument -> re-resolve value = resolveFieldValue(field, bean, beanName); } } else { value = resolveFieldValue(field, bean, beanName); } if (value != null) { // 反射注入值 ReflectionUtils.makeAccessible(field); field.set(bean, value); } } @Nullable private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) { DependencyDescriptor desc = new DependencyDescriptor(field, this.required); desc.setContainingClass(bean.getClass()); Set<String> autowiredBeanNames = new LinkedHashSet<>(1); Assert.state(beanFactory != null, "No BeanFactory available"); // 创建了一个 SimpleTypeConverter 作为 typeConverter TypeConverter typeConverter = beanFactory.getTypeConverter(); Object value; 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) { Object cachedFieldValue = null; if (value != null || this.required) { cachedFieldValue = desc; registerDependentBeans(beanName, autowiredBeanNames); if (autowiredBeanNames.size() == 1) { String autowiredBeanName = autowiredBeanNames.iterator().next(); if (beanFactory.containsBean(autowiredBeanName) && beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { cachedFieldValue = new ShortcutDependencyDescriptor( desc, autowiredBeanName, field.getType()); } } } this.cachedFieldValue = cachedFieldValue; this.cached = true; } } return value; }
逻辑比较简单,解析出注入的值,接着反射注入值。
Method 注入
@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) { try { arguments = resolveCachedArguments(beanName); } catch (NoSuchBeanDefinitionException ex) { // Unexpected removal of target bean for cached argument -> re-resolve arguments = resolveMethodArguments(method, bean, beanName); } } else { // 解析参数 arguments = resolveMethodArguments(method, bean, beanName); } if (arguments != null) { try { // 反射调用方法,注入属性 ReflectionUtils.makeAccessible(method); method.invoke(bean, arguments); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } } } @Nullable private Object[] resolveMethodArguments(Method method, Object bean, @Nullable String beanName) { int argumentCount = method.getParameterCount(); Object[] 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 MethodParameter methodParam = new MethodParameter(method, i); // 封装 DependencyDescriptor DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required); currDesc.setContainingClass(bean.getClass()); descriptors[i] = currDesc; try { // 解析依赖,required 默认 true,遇见无法解析的直接抛出异常 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; } } return arguments; }
可以看到,不管是 Field 注入还是 Method 注入,都是先封装出一个 DependencyDescriptor,接着执行 beanFactory.resolveDependency 进行依赖的解析,不同点在于 Field 解析完就返回了,而 Method 解析完是为了构造出参数数组。
之后,不管是 Field 注入,还是 Method 注入,都是利用反射完成注入。这也说明,Method 注入时,只要能正常的封装出参数数组,就能完成属性或字段注入。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。