详解Spring中@Autowire,@Value 注解实现原理

Java研发军团

共 5446字,需浏览 11分钟

 ·

2021-12-24 08:39

来源:blog.csdn.net/u013202238/article/details/107879726

本文主要基于SpringBoot-2.3.3.RELEASE, Spring-5.2.8.RELEASE 讲解.

Spring中@Autowire,@Value 注解实现原理,将这两个注解放到一块讲解主要是他们的实现基本一致。

本文涉及注解:@Autowire、@Value、@Qualifier、@Lazy、@Primary、@javax.annotation.Priority

相关类介绍

如下是几个重要的相关类:

  • org.springframework.beans.factory.config.BeanPostProcessor
  • org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor
  • org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor
  • org.s.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
  • org.s.beans.factory.annotation.InjectionMetadata.InjectedElement
  • org.s.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement
  • org.s.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement

BeanPostProcessor

BeanPostProcessor是一个接口类,所有的bean在初始时期都会经过这个后置处理器,主要提供如下两个接口方法,

public interface BeanPostProcessor {
 @Nullable
 default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  return bean;
 }

 @Nullable
 default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  return bean;
 }
}

1、postProcessBeforeInitialization方法在bean初始化方法之前执行.例如bean实现了InitializingBean接口,会在InitializingBean#afterPropertiesSet方法之前执行。(不完全是这样,因为要看创建bean时,某个BeanPostProcessor实现类是否已经注册)

对于BeanPostProcessor#postProcessBeforeInitialization是否在@PostConstruct注解的初始化方法之前执行,这是不确定的,因为@PostConstruct初始化方法的执行是通过InitDestroyAnnotationBeanPostProcessor实现,并且InitDestroyAnnotationBeanPostProcessor通过重写BeanPostProcessor#postProcessBeforeInitialization实现@PostConstruct功能,CommonAnnotationBeanPostProcessor通过继承InitDestroyAnnotationBeanPostProcessor拥有了相同的能力,因此要看BeanPostProcessor 实现类被注册的顺序才能决定是否优先于@PostConstruct注解的方式执行。

2、postProcessAfterInitialization 方法在bean的初始化方法之后执行。

3、BeanPostProcessor 的子类接口如下UML图

4、AbstractAutowireCapableBeanFactory#initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd)源码如下:

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
 if (System.getSecurityManager() != null) {
  AccessController.doPrivileged((PrivilegedAction) () -> {
   invokeAwareMethods(beanName, bean);
   return null;
  }, getAccessControlContext());
 }else {
     //判断是否实现了Aware接口,执行子类接口方法,
     //此时只有:BeanNameAware,BeanClassLoaderAware,BeanFactoryAware
  invokeAwareMethods(beanName, bean); 
 }
 Object wrappedBean = bean;
 if (mbd == null || !mbd.isSynthetic()) {
     //调用BeanPostProcessor#postProcessBeforeInitialization
     //ApplicationContextAwareProcessor#postProcessBeforeInitialization
     //实现EnvironmentAware,..ApplicationContextAware等Aware的回调.
  wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
 }
 try {
     //如果bean实现了InitializingBean接口则执行接口的afterPropertiesSet方法
  invokeInitMethods(beanName, wrappedBean, mbd);
 }
 catch (Throwable ex) {
  throw new BeanCreationException(
    (mbd != null ? mbd.getResourceDescription() : null),
    beanName, "Invocation of init method failed", ex);
 }
 if (mbd == null || !mbd.isSynthetic()) {
  wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
 }
 return wrappedBean;
}

MergedBeanDefinitionPostProcessor

@Autowire,@Value 的查找 就是AutowiredAnnotationBeanPostProcessor通过重写该方法实现

public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {

 void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName);
 
 default void resetBeanDefinition(String beanName) {
 }
}

BeanDefinition主要封装了bean的类信息,例如是否是单实例(Singleton),初始化方法名,依赖的bean名称等等。

在bean对象被创建之前,如果一个bean的BeanDefinition是一个子类,会先合并父类BeanDefinition,最终返回一个合并后的RootBeanDefinition,MergedBeanDefinitionPostProcessor则是Spring提供给开发的接口,便于对合并后的RootBeanDefinition做自定义修改。在调用AbstractAutowireCapableBeanFactory#doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)时回调MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition方法。扩展:40 个 SpringBoot 常用注解

InstantiationAwareBeanPostProcessor

看注释

@Autowire,@Value 的赋值 就是AutowiredAnnotationBeanPostProcessor通过重写postProcessProperties方法实现

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
    //创建bean对象实例之前执行
 default Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException {
  return null;
 }
    //创建bean对象实例之后执行
 default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
  return true;
 }
    //用于给bean对象中的成员属性赋值
    //@Autowire,@Value的赋值就是AutowiredAnnotationBeanPostProcessor通过重写该方法实现
 default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
   throws BeansException 
{
  return null;
 }

 @Deprecated   //标记为过时
 default PropertyValues postProcessPropertyValues(
   PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
 throws BeansException 
{
  return pvs;
 }
}

AutowiredAnnotationBeanPostProcessor

@Autowire,@Value,@Lookup等注解功能都是由AutowiredAnnotationBeanPostProcessor实现,在本文主要讲解@Autowire,@Value注解功能实现原理。

AutowiredAnnotationBeanPostProcessor的继承关系如下:

AutowiredAnnotationBeanPostProcessor的构造方法如下:主要定义了@Autowire,@Value两个注解是过滤目标bean的条件,如果bean中的Field、Method被标记这两个注解,则需要为其注入对应的bean或者属性值。

public AutowiredAnnotationBeanPostProcessor() {
  this.autowiredAnnotationTypes.add(Autowired.class);
  this.autowiredAnnotationTypes.add(Value.class);
  try {
   this.autowiredAnnotationTypes.add((Class)
     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.
  }
 }

在实现@Autowire,@Value功能的过程中,AutowiredAnnotationBeanPostProcessor主要起到两个作用。

1、重写MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition方法,反射遍历beanClass中的所有Field和Method,查找bean中标记有@Autowire,@Value的Field、Method,封装到org.springframework.beans.factory.annotation.InjectionMetadata中。

保存在成员变量private final Map injectionMetadataCache = new ConcurrentHashMap<>(256);中。

AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition 源码:

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) {
 InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
 metadata.checkConfigMembers(beanDefinition);
}

findAutowiringMetadata方法内部会调用到AnnotationUtils#isCandidateClass(Class, Class)用于判断某个类是否可能 被标记指定的某个注解。源码如下:

public static boolean isCandidateClass(Class clazz, Class annotationType) {
 return isCandidateClass(clazz, annotationType.getName());
}

public static boolean isCandidateClass(Class clazz, String annotationName) {
    //如果注解所在包是java开头,任何类上都可能标记这个注解
 if (annotationName.startsWith("java.")) {
  return true;
 }
 //注解所在包不是java开头的情况
 //可以认为是自定义注解,例如Spring的@Service @Autowired @Value 对Spring来说就是其自定义注解
 //如果类的包是以java开头,则不可能标记自定义的注解
 if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {
  return false;
 }
 return true;
}

AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)

static boolean hasPlainJavaAnnotationsOnly(Class type) {
 return (type.getName().startsWith("java.") || type == Ordered.class);
}

2、重写InstantiationAwareBeanPostProcessor#postProcessProperties方法,遍历injectionMetadataCache中的InjectionMetadata,调用org.springframework.beans.factory.annotation.InjectionMetadata#inject方法,为bean的@Autowire和@value属性字段赋值。

AutowiredAnnotationBeanPostProcessor#postProcessProperties 源码:

@Override
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;
}

InjectionMetadata里面有个abstract内部类InjectionMetadata.InjectedElement,主要用于给Field或者Method赋值。

AutowiredAnnotationBeanPostProcessor中有两个私有内部类分别继承了InjectedElement。

  • AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement: 通过反射给Field赋值.
  • AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement: 通过反射调用setter Method赋值.

AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject源码:

@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
 Field field = (Field) this.member;
 Object value;
 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) {
     //反射赋值
  ReflectionUtils.makeAccessible(field);
  field.set(bean, value);
 }
}

AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#resolveFieldValue源码:

private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
 DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
 desc.setContainingClass(bean.getClass());
 Set autowiredBeanNames = new LinkedHashSet<>(1);
 Assert.state(beanFactory != null"No BeanFactory available");
 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;
}

方法内部调用的beanFactory.resolveDependency(默认DefaultListableBeanFactory)整体逻辑大概如下:

1.判断Filed或者Method上是否有@Lazy注解,如果存在则创建代理,实现懒加载。

2.不是懒加载,则判断是否存在@Value注解,如果存在则获取value值,最后通过PropertySourcesPropertyResolver#getProperty(java.lang.String, java.lang.Class, boolean)解析属性值(其实就是ConfigurableEnvironment中封装的MutablePropertySources集合),获取到属性值之后还会通过SpringEL进行一次解析。解析之后再由SimpleTypeConverter对象进行一次数据类型转换,转为Filed所需要的类型返回.

3.如果不存在@Value注解,则是根据@Autowire注入bean, 从DefaultListableBeanFactory中变量所有的beanName,判断对象类型是否和所需的相同,相同则保存beanName到List集合中(一个相同的接口可能出现多个实现类,所以用集合),

  • 遍历beanNames,判断每个bean是否符合要求,如果存在@Qualifier会判断名称是否匹配,匹配则获取对应bean对象。如果没有@Qualifier注解,则获取全部的bean对象,封装到Map中。
  • 如果Map中存在多个实例对象,再判断查找带有@Primary注解的实现类,返回对象。同类型实现@Primary只能有一个
  • 如果Map中存在多个实例对象,但是没有@Primary注解,再比较是否有@javax.annotation.Priority注解,选择优先高的返回,值越小优先级越高。
  • 根据名称匹配
  • 不符合以上规则,则抛出异常信息,出现多个bean实现。

Spring中依赖注入Bean的匹配逻辑如下

DefaultListableBeanFactory#determineAutowireCandidate

protected String determineAutowireCandidate(Map candidates, DependencyDescriptor descriptor) {
 Class requiredType = descriptor.getDependencyType();
 String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
 if (primaryCandidate != null) {
  return primaryCandidate;
 }
 String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
 if (priorityCandidate != null) {
  return priorityCandidate;
 }
 // Fallback
 for (Map.Entry entry : candidates.entrySet()) {
  String candidateName = entry.getKey();
  Object beanInstance = entry.getValue();
  if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
    matchesBeanName(candidateName, descriptor.getDependencyName())) {
   return candidateName;
  }
 }
 return null;
}


END


推荐阅读

一键生成Springboot & Vue项目!【毕设神器】

Java可视化编程工具系列(一)

Java可视化编程工具系列(二)


顺便给大家推荐一个GitHub项目,这个 GitHub 整理了上千本常用技术PDF,绝大部分核心的技术书籍都可以在这里找到,

GitHub地址:https://github.com/javadevbooks/books

Gitee地址:https://gitee.com/javadevbooks/books

电子书已经更新好了,你们需要的可以自行下载了,记得点一个star,持续更新中..



浏览 89
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报