zoukankan      html  css  js  c++  java
  • Spring 之autowired

    Spring中autowired主要用于装配树形值,其关键类为BeanWrapperImpl,阅读代码发现其关键方法setPropertyValue有如下一段代码。

     1 PropertyHandler ph = getLocalPropertyHandler(actualName);
     2             if (ph == null || !ph.isWritable()) {
     3                 if (pv.isOptional()) {
     4                     if (logger.isDebugEnabled()) {
     5                         logger.debug("Ignoring optional value for property '" + actualName +
     6                                 "' - property not found on bean class [" + getRootClass().getName() + "]");
     7                     }
     8                     return;
     9                 }
    10                 else {
    11                     throw createNotWritablePropertyException(propertyName);
    12                 }
    13             }
    14             Object oldValue = null;
    15             try {
    16                 Object originalValue = pv.getValue();
    17                 Object valueToApply = originalValue;
    18                 if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
    19                     if (pv.isConverted()) {
    20                         valueToApply = pv.getConvertedValue();
    21                     }
    22                     else {
    23                         if (isExtractOldValueForEditor() && ph.isReadable()) {
    24                             try {
    25                                 oldValue = ph.getValue();
    26                             }
    27                             catch (Exception ex) {
    28                                 if (ex instanceof PrivilegedActionException) {
    29                                     ex = ((PrivilegedActionException) ex).getException();
    30                                 }
    31                                 if (logger.isDebugEnabled()) {
    32                                     logger.debug("Could not read previous value of property '" +
    33                                             this.nestedPath + propertyName + "'", ex);
    34                                 }
    35                             }
    36                         }
    37                         valueToApply = convertForProperty(
    38                                 propertyName, oldValue, originalValue, ph.toTypeDescriptor());
    39                     }
    40                     pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
    41                 }
    42                 ph.setValue(this.wrappedObject, valueToApply);
    View Code

    显然最终都是调用setPropertyValue来设置属性值的。真实注入的时候是发生在getBean的时候,在实例化完成后会调用populateBean方法。查看populateBean方法发现如下代码:

     1 protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
     2         PropertyValues pvs = mbd.getPropertyValues();
     3 
     4         if (bw == null) {
     5             if (!pvs.isEmpty()) {
     6                 throw new BeanCreationException(
     7                         mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
     8             }
     9             else {
    10                 // Skip property population phase for null instance.
    11                 return;
    12             }
    13         }
    14 
    15         // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
    16         // state of the bean before properties are set. This can be used, for example,
    17         // to support styles of field injection.
    18         boolean continueWithPropertyPopulation = true;
    19 
    20         if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    21             for (BeanPostProcessor bp : getBeanPostProcessors()) {
    22                 if (bp instanceof InstantiationAwareBeanPostProcessor) {
    23                     InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
    24                     if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
    25                         continueWithPropertyPopulation = false;
    26                         break;
    27                     }
    28                 }
    29             }
    30         }
    31 
    32         if (!continueWithPropertyPopulation) {
    33             return;
    34         }
    35 
    36         if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
    37                 mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
    38             MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
    39 
    40             // Add property values based on autowire by name if applicable.
    41             if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
    42                 autowireByName(beanName, mbd, bw, newPvs);
    43             }
    44 
    45             // Add property values based on autowire by type if applicable.
    46             if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
    47                 autowireByType(beanName, mbd, bw, newPvs);
    48             }
    49 
    50             pvs = newPvs;
    51         }
    52 
    53         boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    54         boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
    55 
    56         if (hasInstAwareBpps || needsDepCheck) {
    57             PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
    58             if (hasInstAwareBpps) {
    59                 for (BeanPostProcessor bp : getBeanPostProcessors()) {
    60                     if (bp instanceof InstantiationAwareBeanPostProcessor) {
    61                         InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
    62                         pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
    63                         if (pvs == null) {
    64                             return;
    65                         }
    66                     }
    67                 }
    68             }
    69             if (needsDepCheck) {
    70                 checkDependencies(beanName, mbd, filteredPds, pvs);
    71             }
    72         }
    73 
    74         applyPropertyValues(beanName, mbd, bw, pvs);
    75     }
    View Code

    注意如下代码:

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

    在给属性赋值之前会调用InstantiationAwareBeanPostProcessor的postProcessPropertyValues方法,获取最终的PropertyValues。

    在Spring注入的InstantionAwaireBeanPostProcessor中比较关键的子类就是处理@Autowired的子类,AutowiredAnnotationBeanPostProcessor。下如战士postProcessPropertyValues的实现过程,只列出了几个关键的方法。

     

    (1) findAutowiringMetadata方法的主要功能是对InjectMetadata添加了本地缓存,真实的解析InjectMetadata会使用反射,添加缓存可以名小减少对反射的依赖。真实的生成InjectMetadata是buildAutowiringMetadata方法。

     1     private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
     2         LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
     3         Class<?> targetClass = clazz;
     4 
     5         do {
     6             final LinkedList<InjectionMetadata.InjectedElement> currElements =
     7                     new LinkedList<InjectionMetadata.InjectedElement>();
     8 
     9             ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
    10                 @Override
    11                 public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
    12                     AnnotationAttributes ann = findAutowiredAnnotation(field);
    13                     if (ann != null) {
    14                         if (Modifier.isStatic(field.getModifiers())) {
    15                             if (logger.isWarnEnabled()) {
    16                                 logger.warn("Autowired annotation is not supported on static fields: " + field);
    17                             }
    18                             return;
    19                         }
    20                         boolean required = determineRequiredStatus(ann);
    21                         currElements.add(new AutowiredFieldElement(field, required));
    22                     }
    23                 }
    24             });
    25 
    26             ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
    27                 @Override
    28                 public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
    29                     Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
    30                     if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
    31                         return;
    32                     }
    33                     AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
    34                     if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
    35                         if (Modifier.isStatic(method.getModifiers())) {
    36                             if (logger.isWarnEnabled()) {
    37                                 logger.warn("Autowired annotation is not supported on static methods: " + method);
    38                             }
    39                             return;
    40                         }
    41                         if (method.getParameterTypes().length == 0) {
    42                             if (logger.isWarnEnabled()) {
    43                                 logger.warn("Autowired annotation should be used on methods with parameters: " + method);
    44                             }
    45                         }
    46                         boolean required = determineRequiredStatus(ann);
    47                         PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
    48                         currElements.add(new AutowiredMethodElement(method, required, pd));
    49                     }
    50                 }
    51             });
    52 
    53             elements.addAll(0, currElements);
    54             targetClass = targetClass.getSuperclass();
    55         }
    56         while (targetClass != null && targetClass != Object.class);
    57 
    58         return new InjectionMetadata(clazz, elements);
    59     }
    buildAutowiringMetadata

    其实doWithLocalFields和doWithLocalMethods比较类似,都使用策略模式的实现回调方法来实现。这种回调方式是常用的方法。

     1     ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
     2                 @Override
     3                 public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
     4                     AnnotationAttributes ann = findAutowiredAnnotation(field);
     5                     if (ann != null) {
     6                         if (Modifier.isStatic(field.getModifiers())) {
     7                             if (logger.isWarnEnabled()) {
     8                                 logger.warn("Autowired annotation is not supported on static fields: " + field);
     9                             }
    10                             return;
    11                         }
    12                         boolean required = determineRequiredStatus(ann);
    13                         currElements.add(new AutowiredFieldElement(field, required));
    14                     }
    15                 }
    16             });
    doWithLocalFields
     1     public static void doWithLocalFields(Class<?> clazz, FieldCallback fc) {
     2         for (Field field : getDeclaredFields(clazz)) {
     3             try {
     4                 fc.doWith(field);
     5             }
     6             catch (IllegalAccessException ex) {
     7                 throw new IllegalStateException("Not allowed to access field '" + field.getName() + "': " + ex);
     8             }
     9         }
    10     }
    doWithLocalFields

    注意到@Autowired不支持静态注入的原因,就是增加了判断签名为static的时候,并没有解析。

    InjectElement有两个关键子类,AutowiredMethodElement主要解决method上面的注解AutowiredFieldElement主要解决field上面的注解。不同之处就是field会从容器查找filed对应的bean,method会将每一个参数都注入。其最关键的方法均为resolveDependency方法。其中观察resolveDependency方法的调用中有个关键方法findAutowireCandidates。

     1     protected Map<String, Object> findAutowireCandidates(
     2             String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
     3 
     4         String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
     5                 this, requiredType, true, descriptor.isEager());
     6         Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length);
     7         for (Class<?> autowiringType : this.resolvableDependencies.keySet()) {
     8             if (autowiringType.isAssignableFrom(requiredType)) {
     9                 Object autowiringValue = this.resolvableDependencies.get(autowiringType);
    10                 autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
    11                 if (requiredType.isInstance(autowiringValue)) {
    12                     result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
    13                     break;
    14                 }
    15             }
    16         }
    17         for (String candidateName : candidateNames) {
    18             if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) {
    19                 addCandidateEntry(result, candidateName, descriptor, requiredType);
    20             }
    21         }
    22         if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) {
    23             // Consider fallback matches if the first pass failed to find anything...
    24             DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
    25             for (String candidateName : candidateNames) {
    26                 if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
    27                     addCandidateEntry(result, candidateName, descriptor, requiredType);
    28                 }
    29             }
    30             if (result.isEmpty()) {
    31                 // Consider self references before as a final pass
    32                 for (String candidateName : candidateNames) {
    33                     if (isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
    34                         addCandidateEntry(result, candidateName, descriptor, requiredType);
    35                     }
    36                 }
    37             }
    38         }
    39         return result;
    40     }
    View Code

    首先处理的是resolevableDependencies,如果已经注册依赖,直接从注册的依赖中提取。否则直接调用getType方法获取bean。注册依赖可能是容易被忽略的。

    在refresh中就有直接注册依赖的调用:

        protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
            ....//省略部分代码
            beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
            beanFactory.registerResolvableDependency(ResourceLoader.class, this);
            beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
            beanFactory.registerResolvableDependency(ApplicationContext.class, this);
            ......//省略部分代码      
            }
    }
      
  • 相关阅读:
    navicat 连接 mysql 出现Client does not support authentication protocol requested by server解决方案
    oracle的concat、convert、listagg函数(字符串拼接和类型转换)
    oracle的decode、sign、nvl,case...then函数
    where、having区别
    Oracle的rollup、cube、grouping sets函数
    IP地址,子网掩码,网段表示法,默认网关,DNS服务器详解,DNS域名设计
    springmvc 参数解析绑定原理
    eclipse运行mapreduce的wordcount
    linux命令帮助 man bash
    shell学习笔记3-后台执行命令
  • 原文地址:https://www.cnblogs.com/dragonfei/p/5973855.html
Copyright © 2011-2022 走看看