如何自己實現一個自動注入的注解
- 首先,需要了解到的是。Spring Bean 的生命周期
- 在生命周期中。注入bean屬性的位置是在以下代碼:populateBean?位置中
- 那么我們在項目中使用注解 產生一個bean的時候必定會經過以下代碼進行一個bean的創建流程
/**省略代碼**/
// 開始初始化 bean 實例對象
Object exposedObject = bean;
try {// <5> 對 bean 進行填充,將各個屬性值注入,其中,可能存在依賴于其他 bean 的屬性populateBean(beanName, mbd, instanceWrapper);// <6> 調用初始化方法exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}
}
/**省略代碼**/
- 在生命周期中 populateBean 進行填充bean數據。把其他依賴引入進來
- BeanPostProcessor 是一個bean創建時候的一個鉤子。
- 以下代碼 是循環調用實現了 BeanPostProcessor 子類?InstantiationAwareBeanPostProcessor#postProcessProperties?方法
- Spring 在以下代碼中有自動注入的拓展點。 關鍵就是實現?InstantiationAwareBeanPostProcessor#postProcessProperties
/**省略代碼**/
for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;// 對所有需要依賴檢查的屬性進行后處理PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {// 從 bw 對象中提取 PropertyDescriptor 結果集// PropertyDescriptor:可以通過一對存取方法提取一個屬性if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {return;}}pvs = pvsToUse;}
}
/**省略代碼**/
- 我們展開來講一下 @Autowired 的實現是怎么樣的吧:
- 實現類為?AutowiredAnnotationBeanPostProcessor.java
- 從上面可以得知,填充bean的時候。時調用了方法?ibp.postProcessPropertyValues()
- 那么?AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues()?則會被調用
- 調用?findAutowiringMetadata?獲取 class 以及父類 帶有?@Autowired?或者?@Value?的屬性或者方法:
/**省略代碼**/
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;
}
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {// 緩存名字獲取String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);// 獲取是否已經讀取過這個 class 類的 InjectionMetadata 有的話直接從緩存中獲取出去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 = buildAutowiringMetadata(clazz);this.injectionMetadataCache.put(cacheKey, metadata);}}}return metadata;
}
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {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<>();// 循環 targetClass 的所有 field 并執 FieldCallback 邏輯 (函數式編程接口,傳入的是一個執行函數)ReflectionUtils.doWithLocalFields(targetClass, field -> {// 獲得字段上面的 Annotation 注解MergedAnnotation<?> ann = findAutowiredAnnotation(field);if (ann != null) {// 判斷是否為靜態屬性 如果是,則不進行注入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));}});// 循環 targetClass 的所有 Method 并執 MethodCallback 邏輯 (函數式編程接口,傳入的是一個執行函數)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;}// 判斷靜態方法參數是否為0if (method.getParameterCount() == 0) {if (logger.isInfoEnabled()) {logger.info("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 = targetClass.getSuperclass();}while (targetClass != null && targetClass != Object.class);return InjectionMetadata.forElements(elements, clazz);
}/**省略代碼**/
- 真正注入數據的是?metadata.inject(bean, beanName, pvs);
- 調用的是?InjectionMetadata#inject?方法
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);}}
}
- 循環調用之前加入的帶有注解的方法或者屬性構建的對象?AutowiredFieldElement#inject,?AutowiredMethodElement#inject
/*** 屬性上有注解 構建的處理對象*/private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {private final boolean required;private volatile boolean cached;@Nullableprivate volatile Object cachedFieldValue;public AutowiredFieldElement(Field field, boolean required) {super(field, null);this.required = required;}@Overrideprotected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {// 獲取屬性名Field field = (Field) this.member;Object value;// Bean 不是單例的話,會重復進入注入的這個操作,if (this.cached) {try {value = resolvedCachedArgument(beanName, this.cachedFieldValue);}catch (NoSuchBeanDefinitionException ex) {// Unexpected removal of target bean for cached argument -> re-resolvevalue = resolveFieldValue(field, bean, beanName);}}else {// 首次創建的時候進入該方法value = resolveFieldValue(field, bean, beanName);}if (value != null) {// 屬性如果不為public的話,則設置為可訪問ReflectionUtils.makeAccessible(field);field.set(bean, value);}}@Nullableprivate Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {// 構建DependencyDescriptor對象DependencyDescriptor desc = new DependencyDescriptor(field, this.required);desc.setContainingClass(bean.getClass());// 注入bean的數量。 有可能字段上是一個ListSet<String> autowiredBeanNames = new LinkedHashSet<>(1);Assert.state(beanFactory != null, "No BeanFactory available");// 獲得beanFactory類型轉換類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;}}/*** 方法上有注解 構建的處理對象*/private class AutowiredMethodElement extends InjectionMetadata.InjectedElement {private final boolean required;private volatile boolean cached;@Nullableprivate volatile Object[] cachedMethodArguments;public AutowiredMethodElement(Method method, boolean required, @Nullable PropertyDescriptor pd) {super(method, pd);this.required = required;}@Overrideprotected 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-resolvearguments = resolveMethodArguments(method, bean, beanName);}}else {// 首次創建的時候進入該方法arguments = resolveMethodArguments(method, bean, beanName);}if (arguments != null) {try {// 屬性如果不為public的話,則設置為可訪問ReflectionUtils.makeAccessible(method);// 調用方法 并傳入參數method.invoke(bean, arguments);}catch (InvocationTargetException ex) {throw ex.getTargetException();}}}@Nullableprivate Object[] resolveCachedArguments(@Nullable String beanName) {Object[] cachedMethodArguments = this.cachedMethodArguments;if (cachedMethodArguments == null) {return null;}Object[] arguments = new Object[cachedMethodArguments.length];for (int i = 0; i < arguments.length; i++) {arguments[i] = resolvedCachedArgument(beanName, cachedMethodArguments[i]);}return arguments;}@Nullableprivate 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++) {// 方法參數,從方法參數中取出 i 構造 MethodParameter 對象MethodParameter methodParam = new MethodParameter(method, i);DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);currDesc.setContainingClass(bean.getClass());descriptors[i] = currDesc;try {// 獲取方法中 i 參數的內容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;}}
- 以上就是?@Autowired?實現的完整流程。 可概括為:
populateBean?->?AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues
-> 獲取帶有注解的屬性和方法構建?AutowiredFieldElement,?AutowiredMethodElement?對象,然后循環調用了?inject?進行屬性調用
自定義自動注入注解。
package com.yunlongn.common.core.autowired;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.lang.Nullable;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;/*** 抽象的自動注入方法* @author yunlgongn*/
public abstract class AbstractAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor {private final Set<Class<? extends Annotation>> annotationTypes = new LinkedHashSet<>(4);private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);protected final Log logger = LogFactory.getLog(getClass());/*** 處理的 annotationType 對象* @return Annotation 自定義注解*/public abstract Class<? extends Annotation> annotationType();AbstractAnnotationBeanPostProcessor () {Class<? extends Annotation> annotation = this.annotationType();annotationTypes.add(annotation);}@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInstantiation(beanClass, beanName);}@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {return InstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);}@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {InjectionMetadata metadata = findAbstractMetadata(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;}private InjectionMetadata findAbstractMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);// 獲取是否已經讀取過這個 class 類的 InjectionMetadata 有的話直接從緩存中獲取出去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 = buildAbstractMetadata(clazz);this.injectionMetadataCache.put(cacheKey, metadata);}}}return metadata;}private InjectionMetadata buildAbstractMetadata(final Class<?> clazz) {if (!AnnotationUtils.isCandidateClass(clazz, this.annotationTypes)) {return InjectionMetadata.EMPTY;}List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();Class<?> targetClass = clazz;do {final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();// 循環 targetClass 的所有 field 并執 FieldCallback 邏輯 (函數式編程接口,傳入的是一個執行函數)ReflectionUtils.doWithLocalFields(targetClass, field -> {// 獲得字段上面的 Annotation 注解MergedAnnotation<?> ann = findAbstractAnnotation(field);if (ann != null) {// 判斷是否為靜態屬性 如果是,則不進行注入if (Modifier.isStatic(field.getModifiers())) {if (logger.isInfoEnabled()) {logger.info("Abstract annotation is not supported on static fields: " + field);}return;}currElements.add(new AbstractFieldElement(field, ann));}});//數據加到數組最前方 父類的的注解都放在靠前的位置elements.addAll(0, currElements);targetClass = targetClass.getSuperclass();}while (targetClass != null && targetClass != Object.class);return InjectionMetadata.forElements(elements, clazz);}@Nullableprivate MergedAnnotation<?> findAbstractAnnotation(AccessibleObject ao) {// 將指定方法上的注解合并成一個注解MergedAnnotations annotations = MergedAnnotations.from(ao);// 循環要掃描的注解 annotationTypes 那個在前面就認哪個for (Class<? extends Annotation> type : this.annotationTypes) {MergedAnnotation<?> annotation = annotations.get(type);if (annotation.isPresent()) {return annotation;}}return null;}@Deprecated@Overridepublic PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {return postProcessProperties(pvs, bean, beanName);}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return InstantiationAwareBeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);}/*** 實現交給子類進行實現 將注解透傳出去* @param mergedAnnotation 屬性上的注解* @param bean bean實例* @param beanName bean的名字* @param field 字段* @param autowiredFieldElement 注解* @return 注入對象* @throws Exception*/protected abstract Object getInjectedObject(MergedAnnotation<?> mergedAnnotation, Object bean, String beanName, Field field,AbstractFieldElement autowiredFieldElement) throws Exception;public class AbstractFieldElement extends InjectionMetadata.InjectedElement {private final MergedAnnotation<?> mergedAnnotation;public AbstractFieldElement(Field field, MergedAnnotation<?> mergedAnnotation) {super(field, null);this.mergedAnnotation = mergedAnnotation;}@Overrideprotected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Field field = (Field) this.member;Object value = getInjectedObject(this.mergedAnnotation, bean, beanName, field, this);if (value != null) {ReflectionUtils.makeAccessible(field);field.set(bean, value);}}}}
- 抽象類實現,實現一個?@RedisAutowired?自定義注入注解
package com.yunlongn.common.core.autowired;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.core.annotation.MergedAnnotation;import java.lang.annotation.Annotation;
import java.lang.reflect.Field;public class RedisAutowiredBeanPostProcessor extends AbstractAnnotationBeanPostProcessor implements BeanFactoryAware {private BeanFactory beanFactory = null;@Overridepublic Class<? extends Annotation> annotationType() {return RedisAutowired.class;}@Overrideprotected Object getInjectedObject(MergedAnnotation<?> mergedAnnotation, Object bean, String beanName, Field field,AbstractAnnotationBeanPostProcessor.AbstractFieldElement autowiredFieldElement) throws Exception {// 從value中獲取bean的名字。 或者通過一些其他的邏輯獲取名字String s = mergedAnnotation.getString("value");return beanFactory.getBean(s);}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = beanFactory;}
}
- 在 Application 引入以上 @Import(RedisAutowiredBeanPostProcessor.class) 那么?@RedisAutowired?注解就生效了
@RedisAutowired("db102")private XXXService service;
總結
以上是生活随笔為你收集整理的从源码层面带你实现一个自动注入注解的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。