如何自己实现一个自动注入的注解
- 首先,需要了解到的是。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()) {