今天接下去講我們的內容,上次的解析了AnnotationBeanUtils這個類的運用和源碼。今天主要關注的是Autowired和 AutowiredAnnotationBeanPostProcessor這2個類。首先我們來看一下Autowired標簽的定義。
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowired { /** * * <p>Defaults to {@code true}. */ boolean required() default true; }
從標簽的定義和上面的注釋可以知道,該標簽可以用於構造函數、方法、參數、標簽上。為了使這個標簽生效,我們需要一個解析這個標簽的類,Spring 為我們提供解析的類就是AutowiredAnnotationBeanPostProcessor,這是個BeanPostProcessor類。關於BeanPostProcessor大家可以查閱相關資料,之后等我讀到這個接口的時候,會具體的和大家一起探討。這里我們以參數注入為例,來分析了一下,這個類到底做了哪些事情。這個參數注入主要是它的一個內部類AutowiredFieldElement來處理。
而這個類的inject()方法被調用是在AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues方法上。
@Override public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException { 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.inject()的方法。在以參數注入就是調用AutowiredFieldElement.inject()方法。
這些類型的關系,將在之后解釋。讓我們具體來看一下 AutowiredFieldElement.inject()方法。
@Override protected void inject(Object bean, String beanName, 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); desc.setContainingClass(bean.getClass()); Set<String> autowiredBeanNames = new LinkedHashSet<String>(1); TypeConverter typeConverter = beanFactory.getTypeConverter(); try { //通過BeanFactory的resolveDependency()方法解決依賴的值。也就是這個參數需要注入的值 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); if (autowiredBeanNames.size() == 1) { String autowiredBeanName = autowiredBeanNames.iterator().next(); if (beanFactory.containsBean(autowiredBeanName)) { if (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); field.set(bean, value); } }
接下來,我們需要知道,AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues()方法什么時候被調用。在這個函數上,我們關注2個參數,一個是PropertyDescriptor
類型的數組,一個beanName。beanName就是我們實例化的對象,其中PropertyDescriptor就是描述這個名為beanName的Bean的參數內容。在AbstractAutowireCapableBeanFactory的
doCreateBean()方法里,有一個populateBean()里面調用了postProcessPropertyValues()。從方法名稱上,我們知道創建Bean(doCreateBean)>填充Bean(populateBean)。在這個populateBean()里面有如一下這么一段代碼:
if (hasInstAwareBpps || needsDepCheck) { PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); if (hasInstAwareBpps) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvs == null) { return; } } } } if (needsDepCheck) { checkDependencies(beanName, mbd, filteredPds, pvs); } }
在for循環里面,判斷每一個BeanPostProcessor ,看這個BeanPostProcessor 是否實現InstantiationAwareBeanPostProcessor這個接口,剛好,我們知道AutowiredAnnotationBeanPostProcessors實現了這個接口,重載了InstantiationAwareBeanPostProcessor的postProcessPropertyValues()方法。到此為止,我們知道Bean的Autowired的注入實現。那么我們在回到postProcessPropertyValues的findAutowiringMetadata(),從上面已經點出這個方法是找出注入元數據信息。那么它是如何查找的,看如下代碼:
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, PropertyValues pvs) { // Fall back to class name as cache key, for backwards compatibility with custom callers. String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); // Quick check on the concurrent map first, with minimal locking. 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); } try { metadata = buildAutowiringMetadata(clazz); this.injectionMetadataCache.put(cacheKey, metadata); } catch (NoClassDefFoundError err) { throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() + "] for autowiring metadata: could not find class that it depends on", err); } } } } return metadata; }
其中的關鍵代碼就是InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);這句話。從這里我們知道他是從this.injectionMetadataCache,這是一個Map,key為beanName,value為注入元數據InjectionMetadata。即直接從這個Map中獲取,那么接下來我們就要知道這個注入信息是什么時候放入到這個緩存Map上的。從上面代碼上,我們看到
this.injectionMetadataCache.put(cacheKey, metadata);這段代碼,這代碼就是把注入信息放到this.injectionMetadataCache上。那么,從這里我們可以猜測,findAutowiringMetadata()這個方法肯定被調用了多次,在Bean實例化過程中。從查看代碼,印證了我的想法。
再回到AutowiredAnnotationBeanPostProcessor的BeanPostProcessor,之前我們知道他實現InstantiationAwareBeanPostProcessor這個接口。在這里,我要說AutowiredAnnotationBeanPostProcessor還實現了MergedBeanDefinitionPostProcessor這個接口,這個MergedBeanDefinitionPostProcessor接口只有一個函數postProcessMergedBeanDefinition(),該方法就是用來整合BeanDefinition。讓我們自己毛估估也知道,這個對Bean內部的參數描述PropertyDescriptor也應該在專門用來整合Bean定義的這種BeanPostProcessors。從 AutowiredAnnotationBeanPostProcessor的如下代碼,它果然實現postProcessMergedBeanDefinition函數。在其中調用了findAutowiringMetadata()。
@Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { if (beanType != null) { InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null); metadata.checkConfigMembers(beanDefinition); } }
第一次調用findAutowiringMetadata()的時候,我們this.injectionMetadataCache.get()得到metadata為null,這樣就會進入if{}段代碼,接着 調用 buildAutowiringMetadata()從該Bean的字節碼中得到注入元信息。接着我們把得到的注入源信息InjectionMetadata放到this.injectionMetadataCache上。那么我們看一下這個方法。
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) { LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>(); Class<?> targetClass = clazz; do { final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>(); ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() { @Override public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { AnnotationAttributes ann = findAutowiredAnnotation(field); if (ann != null) { if (Modifier.isStatic(field.getModifiers())) { if (logger.isWarnEnabled()) { logger.warn("Autowired annotation is not supported on static fields: " + field); } return; } boolean required = determineRequiredStatus(ann); currElements.add(new AutowiredFieldElement(field, required)); } } }); ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() { @Override public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { 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.isWarnEnabled()) { logger.warn("Autowired annotation is not supported on static methods: " + method); } return; } if (method.getParameterTypes().length == 0) { if (logger.isWarnEnabled()) { logger.warn("Autowired annotation should only be used on methods with parameters: " + method); } } boolean required = determineRequiredStatus(ann); 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 new InjectionMetadata(clazz, elements); }
從上面,我們知道這個方法主要通過ReflectionUtils.doWithLocalFields()和ReflectionUtils.doWithLocalMethods()來得到源注入信息。到這里,我們可以大致知道依賴注入了。瞎 main提供一下test,大家可以通過debug知道Bean的創建流程。
@Test public void testResourceInjection2() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); bpp.setBeanFactory(bf); bf.addBeanPostProcessor(bpp); RootBeanDefinition bd1 = new RootBeanDefinition(Uss.class); bd1.setScope(RootBeanDefinition.SCOPE_SINGLETON); bf.registerBeanDefinition("uss", bd1); RootBeanDefinition bd2 = new RootBeanDefinition(Tss.class); bd2.setScope(RootBeanDefinition.SCOPE_SINGLETON); bf.registerBeanDefinition("tss", bd2); Uss uss = (Uss) bf.getBean("uss"); Tss tss = (Tss) bf.getBean("tss"); System.out.println(uss.getTss() == tss); System.out.println(tss.getUss() == uss); }
public class Uss { private String id; @Autowired private Tss tss; public String getId() { return id; } public void setId(String id) { this.id = id; } public Tss getTss() { return tss; } public void setTss(Tss tss) { this.tss = tss; } }
public class Tss { private String id; @Autowired private Uss uss; public String getId() { return id; } public void setId(String id) { this.id = id; } public Uss getUss() { return uss; } public void setUss(Uss uss) { this.uss = uss; } }
在這里,還有一些東西沒有講的非常的清楚,第一,是我自己有些代碼還不太清楚,整體把握不住,還有些要等到我看到了其他內容在和大家一起分享。