Bean後置處理器 - applyMergedBeanDefinitionPostProcessors
建立完物件之後, 接下來, 就應該想辦法對屬性進行注入了, 其中就包括 @Autowired 注入
但是在注入之前, 貌似 還沒有對 @Autowired 進行掃描和解析.
程式碼塊:
if (instanceWrapper == null) { /** * 建立 bean 例項,並將例項包裹在 BeanWrapper 實現類物件中返回。 * createBeanInstance中包含三種建立 bean 例項的方式: * 1. 通過工廠方法建立 bean 例項 * 2. 通過構造方法自動注入(autowire by constructor)的方式建立 bean 例項 * 3. 通過無參構造方法方法建立 bean 例項 * * 若 bean 的配置資訊中配置了 lookup-method 和 replace-method,則會使用 CGLIB 增強 bean 例項。*/ instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } // Allow post-processors to modify the merged bean definition.synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { //呼叫屬性合併後置處理器, 進行屬性合併 //這裡會進行 一些註解 的掃描 //CommonAnnotationBeanPostProcessor -> @PostConstruct @PreDestroy @Resource //AutowiredAnnotationBeanPostProcessor -> @Autowired @ValueapplyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex); } mbd.postProcessed = true; } }
接著看裡面的內容
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof MergedBeanDefinitionPostProcessor) { MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp; bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName); } } }
通過除錯, 可以獲取, 這裡滿足條件的, 有三個後置處理器, 按照呼叫先後順序為:
接下來看看裡面都幹了啥
CommonAnnotationBeanPostProcessor
這一步, 主要是掃描作用.
1. 掃描 @PostConstruct 和 @PreDestroy (這個很直觀的能看到, 其無參建構函式中, 出現了這兩個註解)
2. 掃描 @Resource , 這個需要到 findResourceMetadata 中, 才能看到
public CommonAnnotationBeanPostProcessor() { setOrder(Ordered.LOWEST_PRECEDENCE - 3); setInitAnnotationType(PostConstruct.class); setDestroyAnnotationType(PreDestroy.class); ignoreResourceType("javax.xml.ws.WebServiceContext"); } /** * 1.遍歷掃描方法上標註了 @PostConstruct 和 @PreDestroy 註解的類 * 2.遍歷掃描方法上標註了 @Resource 註解的類 * @param beanDefinition * @param beanType * @param beanName */ @Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName); InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null); metadata.checkConfigMembers(beanDefinition); }
1. 呼叫父類方法, 進行@PostConstruct 和 @PreDestroy 掃描
org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#postProcessMergedBeanDefinition
@Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { LifecycleMetadata metadata = findLifecycleMetadata(beanType); metadata.checkConfigMembers(beanDefinition); }
findLifecycleMetadata最終會呼叫org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#buildLifecycleMetadata 方法
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) { List<LifecycleElement> initMethods = new ArrayList<>(); List<LifecycleElement> destroyMethods = new ArrayList<>(); Class<?> targetClass = clazz; do { final List<LifecycleElement> currInitMethods = new ArrayList<>(); final List<LifecycleElement> currDestroyMethods = new ArrayList<>(); ReflectionUtils.doWithLocalMethods(targetClass, method -> { if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) { LifecycleElement element = new LifecycleElement(method); currInitMethods.add(element); if (logger.isTraceEnabled()) { logger.trace("Found init method on class [" + clazz.getName() + "]: " + method); } } if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) { currDestroyMethods.add(new LifecycleElement(method)); if (logger.isTraceEnabled()) { logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method); } } }); initMethods.addAll(0, currInitMethods); destroyMethods.addAll(currDestroyMethods); //當前類解析完後, 拿到父類繼續進行解析, 直到父類為 Object targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); return new LifecycleMetadata(clazz, initMethods, destroyMethods); }
這裡就是遍歷類和其父類, 進行查詢的.
2.進行 @Resource 掃描
Resource 掃描, 是在本類中完成的.
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#findResourceMetadata
private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable 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); } metadata = buildResourceMetadata(clazz); this.injectionMetadataCache.put(cacheKey, metadata); } } } return metadata; }
這裡主要看 buildResourceMetadata( ) 方法.
private InjectionMetadata buildResourceMetadata(final Class<?> clazz) { List<InjectionMetadata.InjectedElement> elements = new ArrayList<>(); Class<?> targetClass = clazz; do { final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>(); //掃描欄位 ReflectionUtils.doWithLocalFields(targetClass, field -> { if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) { if (Modifier.isStatic(field.getModifiers())) { throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields"); } currElements.add(new WebServiceRefElement(field, field, null)); } else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) { if (Modifier.isStatic(field.getModifiers())) { throw new IllegalStateException("@EJB annotation is not supported on static fields"); } currElements.add(new EjbRefElement(field, field, null)); } else if (field.isAnnotationPresent(Resource.class)) { //靜態欄位上標註 @Resource , 會拋異常 if (Modifier.isStatic(field.getModifiers())) { throw new IllegalStateException("@Resource annotation is not supported on static fields"); } if (!this.ignoredResourceTypes.contains(field.getType().getName())) { currElements.add(new ResourceElement(field, field, null)); } } }); //掃描方法 ReflectionUtils.doWithLocalMethods(targetClass, method -> { Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) { return; } if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) { if (Modifier.isStatic(method.getModifiers())) { throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods"); } if (method.getParameterCount() != 1) { throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method); } PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); currElements.add(new WebServiceRefElement(method, bridgedMethod, pd)); } else if (ejbRefClass != null && bridgedMethod.isAnnotationPresent(ejbRefClass)) { if (Modifier.isStatic(method.getModifiers())) { throw new IllegalStateException("@EJB annotation is not supported on static methods"); } if (method.getParameterCount() != 1) { throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method); } PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); currElements.add(new EjbRefElement(method, bridgedMethod, pd)); } else if (bridgedMethod.isAnnotationPresent(Resource.class)) { if (Modifier.isStatic(method.getModifiers())) { throw new IllegalStateException("@Resource annotation is not supported on static methods"); } Class<?>[] paramTypes = method.getParameterTypes(); //如果目標方法, 沒有引數, 或者有多個引數, 則丟擲異常 if (paramTypes.length != 1) { throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method); } if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) { //這裡拿到方法名, 會去跟類中的屬性進行匹配 //匹配的規則是: method.equals(pd.getReadMethod()) || method.equals(pd.getWriteMethod()) //這個 readMethod 就是 getXXX 或 isXXX, writeMethod 就是 setXXX //如果匹配不上, pd = null PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); currElements.add(new ResourceElement(method, bridgedMethod, pd)); } } } }); elements.addAll(0, currElements); targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); return new InjectionMetadata(clazz, elements); }
注意到, 這裡只進行了掃描轉換工作, 並沒有進行屬性注入工作.
AutowiredAnnotationBeanPostProcessor
public AutowiredAnnotationBeanPostProcessor() { this.autowiredAnnotationTypes.add(Autowired.class); this.autowiredAnnotationTypes.add(Value.class); try { this.autowiredAnnotationTypes.add((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader())); logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring"); } catch (ClassNotFoundException ex) { // JSR-330 API not available - simply skip. } } @Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null); metadata.checkConfigMembers(beanDefinition); }
從這段程式碼, 可以猜測, 自動注入的型別, 是個集合,這裡有兩個
1. @Autowired
2. @Value
findAutowiringMetadata() 最終會呼叫本類方法:
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) { List<InjectionMetadata.InjectedElement> elements = new ArrayList<>(); //需要處理的目標類 Class<?> targetClass = clazz; do { final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>(); // 通過反射獲取該類所有的欄位,並遍歷每一個欄位,通過方法 findAutowiredAnnotation 遍歷每一個欄位的所用註解, // 如果用autowired修飾了,則返回 auotowired 相關屬性 ReflectionUtils.doWithLocalFields(targetClass, field -> { AnnotationAttributes ann = findAutowiredAnnotation(field); if (ann != null) { // 校驗autowired註解是否用在了static方法上 if (Modifier.isStatic(field.getModifiers())) { if (logger.isInfoEnabled()) { logger.info("Autowired annotation is not supported on static fields: " + field); } return; } 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; } 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); } } boolean required = determineRequiredStatus(ann); //這裡也會進行屬性的匹配, 按照規則 : method.equals(pd.getReadMethod()) || method.equals(pd.getWriteMethod()) //如果匹配不上, pd = null PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); currElements.add(new AutowiredMethodElement(method, required, pd)); } }); //用@Autowired修飾的註解可能不止一個,因此都加在 elements 這個容器裡面,一起處理 elements.addAll(0, currElements); targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); return new InjectionMetadata(clazz, elements); }
這裡也只是進行了掃描, 沒有進行屬性注入工作.
ApplicationListenerDetector
@Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { this.singletonNames.put(beanName, beanDefinition.isSingleton()); }
這個類也是挺能湊熱鬧的. 這裡沒有進行任何掃描工作. 只是記錄了容器中的 bean 是否是單例模式.
這裡記錄這個標誌, 是為了後面用的. 對監聽器進行過濾用的.