最近正在看spring官網,看Spring IOC的時候看Spring容器擴展點的時候發現了BeanPostProcessor 這個接口。下面是官方對它的詳細描述:
BeanPostProcessor接口定義了回調方法,您可以實現提供自己的(或覆蓋容器的默認)實例化邏輯,依賴性解析邏輯,等等。如果你想實現一些自定義邏輯Spring容器實例化完成後,配置和初始化一個bean,您可以插入一個或多個BeanPostProcessor實現。
您可以配置多個BeanPostProcessor實例,您可以控制的順序執行這些BeanPostProcessors通過設置屬性。你可以設置這個屬性只有BeanPostProcessor實現命令接口;如果你寫自己的BeanPostProcessor你也應該考慮實現theOrdered接口。詳情,請咨詢BeanPostProcessor的Javadoc和命令接口。
BeanPostProcessor有兩個方法postProcessBeforeInitialization,postProcessAfterInitialization.如果一個對象實現了這個接口,那麼就會在容器初始化init方法之前(就像InitializingBean的afterPropertiesSet()和其它公開的init方法)或在Spring bean初始化之後執行回調。
實現BeanPostProcessor接口的類由容器是特殊而區別對待。所有BeanPostProcessors和他們在啟動時直接引用實例化bean,作為特殊的ApplicationContext的啟動階段。接下來,所有BeanPostProcessorsare注冊分類的方式,適用於所有進一步bean容器。因為實現AOP auto-proxying aBeanPostProcessor本身,無論是BeanPostProcessors還是beas他們有資格獲得auto-proxying直接引用,因此沒有方面編織進去。
實現BeanPostProcessor接口的類由容器是特殊而區別對待。所有BeanPostProcessors和他們在啟動時直接引用實例化bean,作為特殊的ApplicationContext的啟動階段。接下來,所有BeanPostProcessorsare注冊分類的方式,適用於所有進一步bean容器。因為實現AOP auto-proxying aBeanPostProcessor本身,無論是BeanPostProcessors還是beas他們有資格獲得auto-proxying直接引用,因此沒有方面編織進去。
使用回調接口或注釋與自定義實現BeanPostProcessor是一種常見的擴展SpringIoC容器。RequiredAnnotationBeanPostProcessor是Spring的一個例子 —— 一個實現BeanPostProcessor附帶的Spring分布,確保JavaBean屬性bean上標有一個(任意)注釋(配置)會依賴注入值。
你說我一看到上面的AOP這個Spring兩大特性之一我心裡面都有一點小激動。後面他再來個Spring的Annotation一般也是用這個接口實現的。這下就忍不住了想去看一看RequiredAnnotationBeanPostProcessor這個類到底干了什麼。直接上源碼
Spring Annotation Support /* * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.beans.factory.annotation; import java.beans.PropertyDescriptor; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.springframework.beans.BeansException; import org.springframework.beans.PropertyValues; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanInitializationException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.core.Conventions; import org.springframework.core.Ordered; import org.springframework.core.PriorityOrdered; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.Assert; /** * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation * that enforces required JavaBean properties to have been configured. * 強制檢測JavaBean必須的properties是否已經被配置 * Required bean properties are detected through a Java 5 annotation: * 必須的bean屬性通過Java 5中的annotation自動檢測到 * by default, Spring's {@link Required} annotation. * * <p>The motivation for the existence of this BeanPostProcessor is to allow * BeanPostProcessor存在的意義是允許 * developers to annotate the setter properties of their own classes with an * arbitrary JDK 1.5 annotation to indicate that the container must check * for the configuration of a dependency injected value. This neatly pushes * 開發人員注釋setter屬性與一個他們自己的類任意的JDK 1.5注釋表明容器必須檢查依賴注入的配置值。 * responsibility for such checking onto the container (where it arguably belongs), * 這樣就巧妙的把check的責任給了Spring容器(它應該就屬於的) * and obviates the need (<b>in part</b>) for a developer to code a method that * simply checks that all required properties have actually been set. * 這樣也就排除了開發人員需要編寫一個簡單的方法用來檢測那麼必須的properties是否已經設置了值 * <p>Please note that an 'init' method may still need to implemented (and may * still be desirable), because all that this class does is enforce that a * 請注意初始化方法還是必須要實現的(並且仍然是可取的) * 'required' property has actually been configured with a value. It does * 因為所有這個Class強制執行的是'required'屬性是否已經被配置了值 * <b>not</b> check anything else... In particular, it does not check that a * 它並不會check其實的事,特別的是,它不會check這個配置的值是不是null值 * configured value is not {@code null}. * * <p>Note: A default RequiredAnnotationBeanPostProcessor will be registered * by the "context:annotation-config" and "context:component-scan" XML tags. * 當你使用了"context:annotation-config"或者"context:component-scan"XML標簽就會默認注冊RequiredAnnotationBeanPostProcessor * Remove or turn off the default annotation configuration there if you intend * to specify a custom RequiredAnnotationBeanPostProcessor bean definition. * 你如果打算指定一個自定義的RequiredAnnotationBeanPostProcessor的bean實現可以移除或者關閉默認的annotation配置 * * @author Rob Harrop * @author Juergen Hoeller * @since 2.0 * @see #setRequiredAnnotationType * @see Required */ public class RequiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware { /** * Bean definition attribute that may indicate whether a given bean is supposed * to be skipped when performing this post-processor's required property check. * 這個bean定義的屬性表明當執行post-processor(後處理程序)這個check提供的bean的必須的屬性 * @see #shouldSkip */ public static final String SKIP_REQUIRED_CHECK_ATTRIBUTE = Conventions.getQualifiedAttributeName(RequiredAnnotationBeanPostProcessor.class, "skipRequiredCheck"); private Class<? extends Annotation> requiredAnnotationType = Required.class; private int order = Ordered.LOWEST_PRECEDENCE - 1; private ConfigurableListableBeanFactory beanFactory; /** * Cache for validated bean names, skipping re-validation for the same bean * 緩存已經確認過的bean名稱,跳過後續同樣的bean */ private final Set<String> validatedBeanNames = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(64)); /** * Set the 'required' annotation type, to be used on bean property * setter methods. * 設置所需的注釋類型,使用bean屬性setter方法 * <p>The default required annotation type is the Spring-provided * {@link Required} annotation. * 這個默認的required annotation類型是Spring提供的annotation * <p>This setter property exists so that developers can provide their own * (non-Spring-specific) annotation type to indicate that a property value * is required. * 這裡設置這個property是為了開發者能夠提供自己定義的annotaion類型用來表明這個屬性值是必須的 */ public void setRequiredAnnotationType(Class<? extends Annotation> requiredAnnotationType) { Assert.notNull(requiredAnnotationType, "'requiredAnnotationType' must not be null"); this.requiredAnnotationType = requiredAnnotationType; } /** * Return the 'required' annotation type. */ protected Class<? extends Annotation> getRequiredAnnotationType() { return this.requiredAnnotationType; } @Override public void setBeanFactory(BeanFactory beanFactory) { if (beanFactory instanceof ConfigurableListableBeanFactory) { this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; } } public void setOrder(int order) { this.order = order; } @Override public int getOrder() { return this.order; } @Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { } @Override public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { // 利用緩存確定是否這個bean被validated if (!this.validatedBeanNames.contains(beanName)) { // 不跳過 if (!shouldSkip(this.beanFactory, beanName)) { List<String> invalidProperties = new ArrayList<String>(); for (PropertyDescriptor pd : pds) { // 如果被標記為了required 且 這個屬性沒有屬性值(或其他處理條目) if (isRequiredProperty(pd) && !pvs.contains(pd.getName())) { // 增加這個屬性 invalidProperties.add(pd.getName()); } } // <span >如果無效的properties不為空。拋出異常</span> if (!invalidProperties.isEmpty()) { throw new BeanInitializationException(buildExceptionMessage(invalidProperties, beanName)); } } // 把需要驗證的bean名稱添加進去 this.validatedBeanNames.add(beanName); } return pvs; } /** * Check whether the given bean definition is not subject to the annotation-based * required property check as performed by this post-processor. * 通過post-processor(後處理程序)檢測這個被給予的定義的bean是否受注釋為基礎的check必須的property的管束 * <p>The default implementations check for the presence of the * {@link #SKIP_REQUIRED_CHECK_ATTRIBUTE} attribute in the bean definition, if any. * 這個默認的實現check存在SKIP_REQUIRED_CHECK_ATTRIBUTE這個屬性的定義的bean * It also suggests skipping in case of a bean definition with a "factory-bean" * reference set, assuming that instance-based factories pre-populate the bean. * 它同樣也建議跳過如果這個bean定義了"factory-bean"引用,假設那個基於實例的factories預先配置了bean * @param beanFactory the BeanFactory to check against * @param beanName the name of the bean to check against * @return {@code true} to skip the bean; {@code false} to process it * 如果返回 true跳過這個bean,返回false就處理它 */ protected boolean shouldSkip(ConfigurableListableBeanFactory beanFactory, String beanName) { // 如果這個beanFacotry為空或者這個bean工廠不包含一個給定名稱的bean定義。返回false if (beanFactory == null || !beanFactory.containsBeanDefinition(beanName)) { return false; } BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); // 判斷這個bean的工廠beanName,如果不為null,返回true if (beanDefinition.getFactoryBeanName() != null) { return true; } Object value = beanDefinition.getAttribute(SKIP_REQUIRED_CHECK_ATTRIBUTE); return (value != null && (Boolean.TRUE.equals(value) || Boolean.valueOf(value.toString()))); } /** * Is the supplied property required to have a value (that is, to be dependency-injected)? * 是否這個提供的必須的propery是否有一個值(這個是被依賴注入)? * <p>This implementation looks for the existence of a * {@link #setRequiredAnnotationType "required" annotation} * on the supplied {@link PropertyDescriptor property}. * 這個實現是為了找到提供的ProertyDescriptor是提供了"required"注解 * @param propertyDescriptor the target PropertyDescriptor (never {@code null}) * @return {@code true} if the supplied property has been marked as being required; * 返回true,如果提供的property已經被標記為必須的</span> * {@code false} if not, or if the supplied property does not have a setter method * 返回false,如果沒有標記為必須的或者提供的property沒有一個setter方法 */ protected boolean isRequiredProperty(PropertyDescriptor propertyDescriptor) { Method setter = propertyDescriptor.getWriteMethod(); return (setter != null && AnnotationUtils.getAnnotation(setter, getRequiredAnnotationType()) != null); } /** * Build an exception message for the given list of invalid properties. * 使用所給的異常properties來構建異常信息 * @param invalidProperties the list of names of invalid properties * @param beanName the name of the bean * @return the exception message */ private String buildExceptionMessage(List<String> invalidProperties, String beanName) { int size = invalidProperties.size(); StringBuilder sb = new StringBuilder(); sb.append(size == 1 ? "Property" : "Properties"); for (int i = 0; i < size; i++) { String propertyName = invalidProperties.get(i); if (i > 0) { if (i == (size - 1)) { sb.append(" and"); } else { sb.append(","); } } sb.append(" '").append(propertyName).append("'"); } sb.append(size == 1 ? " is" : " are"); sb.append(" required for bean '").append(beanName).append("'"); return sb.toString(); } }
在上面的代碼中所示。我們可以得出以下結論:
上面已經把Spring對於 org.springframework.beans.factory.annotation.Required 這個標簽的實現出來了。雖然只是一個小例子。但是我們可以根據Spring以下的的包結構看到這是Spring對於它自身Annotation的很common的實現:
從上面的例子中我可以看出Spring對它本身的Annotaion的一種實現。當前文中並沒有講述Exception Message是通過怎麼傳遞的。但是這並不是本文討論的范疇,有興趣的朋友可以自己去看看。
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!