如何自己實現一個自動注入的註解
- 首先,需要了解到的是。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;
}
// 判斷靜態方法引數是否為0
if (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;
@Nullable
private volatile Object cachedFieldValue;
public AutowiredFieldElement(Field field, boolean required) {
super(field, null);
this.required = required;
}
@Override
protected 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-resolve
value = resolveFieldValue(field, bean, beanName);
}
}
else {
// 首次建立的時候進入該方法
value = resolveFieldValue(field, bean, beanName);
}
if (value != null) {
// 屬性如果不為public的話,則設定為可訪問
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
@Nullable
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
// 構建DependencyDescriptor物件
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
// 注入bean的數量。 有可能欄位上是一個List
Set<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;
@Nullable
private volatile Object[] cachedMethodArguments;
public AutowiredMethodElement(Method method, boolean required, @Nullable PropertyDescriptor pd) {
super(method, pd);
this.required = required;
}
@Override
protected 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-resolve
arguments = 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();
}
}
}
@Nullable
private 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;
}
@Nullable
private 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);
}
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInstantiation(beanClass, beanName);
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return InstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);
}
@Override
public 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);
}
@Nullable
private 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
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
return postProcessProperties(pvs, bean, beanName);
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public 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;
}
@Override
protected 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;
@Override
public Class<? extends Annotation> annotationType() {
return RedisAutowired.class;
}
@Override
protected 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);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
- 在 Application 引入以上 @Import(RedisAutowiredBeanPostProcessor.class) 那麼
@RedisAutowired
註解就生效了
@RedisAutowired("db102")
private XXXService service;