(头条代码排版存在问题,可点击底部链接查看原文)
一、自动依赖注入的方式
注解类型
- spring提供了基于注解的属性自动注入特性,其中可以可用的注解包括spring自身提供的@Autowired和@Value,其中@Autowired是我们在项目中最常用来注入对象属性的,@Value注解通常用于注入属性文件properties的值,除此之外还可以使用JSR-330提供的注解@Inject,类型为javax.inject.Inject。如下:
@Component public class NettyServer { @Autowired private WebSocketService webSocketService; /** * 监听端口号 */ @Value("${netty.port}") private int port; // 省略其他代码 }
- 关于以上注解的更多特性可参考:Spring实现依赖注入的三个注解:@Autowired,@Resource,@Inject
注解方式
- 在使用@Autowired注解进行自动属性注入时,通常可以通过以下三种方式进行配置,分别为:构造函数注入,属性值注入,setter方法注入。如下:
@RestController public class AccountController { // 属性值注入 @Autowired private AccountService accountService; private UserService userService; private IndexService indexService; // 构造函数注入 @Autowired public AccountController(UserService userService) { this.userService = userService; } // setter方法注入 public void setIndexService(IndexService indexService) { this.indexService = indexService; } // 省略其他代码 }
- 当通过构造函数和setter方法进行注入时,由于构造函数和setter方法都可以有多个参数,而@Autowired的required的值又是true,如下为@Autowired注解的定义:
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowired { // 依赖是必须的 boolean required() default true; }
- 即默认需要所有属性值都存在,不能为null,否则会创建对象失败,如下:
// 构造函数注入 @Autowired public AccountController(UserService userService, IndexService indexService) { this.userService = userService; this.indexService = indexService; }
- 所以如果某个属性值不是必须的,则可以使用Java8的Optional或者spring5的@Nullable来修饰,如下假如IndexServer不是必需的:
- Optional的使用:
private Optional<IndexService> indexService; // 构造函数注入 @Autowired public AccountController(UserService userService, Optional<IndexService> indexService) { this.userService = userService; this.indexService = indexService; }
@Nullable的使用:
// 构造函数注入 @Autowired public AccountController(UserService userService, @Nullable IndexService indexService) { this.userService = userService; this.indexService = indexService; }
- 如果不想使用以上注解,则可以使用setter方式或属性值注入,或者不要将不需要注入的类放在构造函数或者方法上。
二、自动依赖注入的实现
- 依赖注入是spring的IOC容器的一个重要特性,通过依赖注入来自动解决类对象之间的引用关系,即由spring来创建bean对象,并且在spring的IOC容器内部自动查找或者创建该bean对象所依赖的其他bean对象,从而保证整个bean对象的属性值的完整性。
- 由以上分析可知,spring可以基于构造函数注入,属性值注入和setter方法注入,在spring的内部实现当中,这三种方式的实现是存在差别的。
构造函数注入
- Java在创建每个对象实例时,都需要调用该对象对应的类的构造函数,所以spring在创建bean对象时,也会选择其中一个构造函数来创建该对象。当该类存在多个构造函数时,只能有一个构造函数使用required为true的@Autowired注解,其他构造函数如果也使用了@Autowired,则需要设置required为false。
spring选择构造函数的规则
- 选择能够成功注入最多bean对象的使用了@Autowired注解的构造函数,即基于贪婪的策略,注意不是选择包含最多参数这么简单,而是能够从spring的IOC容器获取bean对象并注入成功最多的构造函数。
- 或者如果某个类的所有构造函数都没有使用@Autowired注解,则spring会使用该类的默认构造函数,即如果没有显式定义任何构造函数,则使用默认的无参构造函数;如果只存在一个,则调用这个;如果存在多个且没有无参构造函数,也没有使用@Autowired注解,则会编译出错或者idea会提示构造函数有误,因为这种方式,spring无法确定使用哪个构造函数。
- 以上选择构造函数的构造函数的核心源码实现如下:在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory类的createBeanInstance方法定义:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // Make sure bean class is actually resolved at this point. // 类加载 Class<?> beanClass = resolveBeanClass(mbd, beanName); // 省略其他代码 // 查找该类的所有的构造函数,包括使用了@Autowired注解和没有使用@Autowired注解的 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); // 基于贪婪原则选择能注入最多bean对象的构造函数 if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { // 贪婪选择构造函数,执行构造函数属性注入与创建bean对象 return autowireConstructor(beanName, mbd, ctors, args); } // 指定了特定偏好的构造函数,默认为null ctors = mbd.getPreferredConstructors(); if (ctors != null) { return autowireConstructor(beanName, mbd, ctors, null); } // 使用无参构造函数创建bean对象实例 return instantiateBean(beanName, mbd); }
构造函数属性注入
- 以上分析了spring选择构造函数的规则,对于贪婪选择能注入最多bean对象的构造函数和完成构造函数属性注入,创建bean对象是在AbstractAutowireCapableBeanFactory类的autowireConstructor方法实现的:
protected BeanWrapper autowireConstructor( String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) { return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs); }
- 具体在ConstructorResolver类的autowireConstructor方法实现构造函数的选择和构造函数的属性依赖注入,autowireConstructor的核心实现如下:如果只存在一个显式定义的构造函数,则使用这个构造函数;否则先基于构造函数的参数个数对所有构造函数进行降序排序,然后遍历检查这些构造函数。选中最合适的构造函数后,则进行构造函数的属性对象的注入。注意使用构造函数进行属性注入存在循环依赖问题,具体后面文章详细分析spring的解决方案和无法解决的情况。请参考:Spring的构造函数注入的循环依赖问题
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) { // 省略其他代码 // 只有一个构造函数,则使用该构造函数即可 if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) { Constructor<?> uniqueCandidate = candidates[0]; if (uniqueCandidate.getParameterCount() == 0) { synchronized (mbd.constructorArgumentLock) { mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate; mbd.constructorArgumentsResolved = true; mbd.resolvedConstructorArguments = EMPTY_ARGS; } bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS)); return bw; } } // 省略其他代码 // 基于构造函数的参数个数排序,越多的越前,即降序排序 AutowireUtils.sortConstructors(candidates); // 从所有构造函数中,基于贪婪规则筛选出能注入成功最多bean对象的构造函数 for (Constructor<?> candidate : candidates) { // 构造函数的参数的类型 Class<?>[] paramTypes = candidate.getParameterTypes(); // 省略其他代码 ArgumentsHolder argsHolder; if (resolvedValues != null) { try { // 省略其他代码 // 获取构造函数参数对应的bean对象,在这里解决构造函数依赖注入 argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames, getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1); } // 省略其他代码 } // 省略其他代码 bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse)); return bw; }
- 在以上代码中,主要是在createArgumentArray方法处理构造函数的属性注入问题,最终会调用到BeanFactory的getBean方法从BeanFactory获取所依赖的其他对象。如果BeanFactory当前还不存在该依赖的bean对象,则会在getBean方法中创建该bean对象并返回。所以如果该被依赖的bean对象如果也在构造函数中依赖了当前正在创建的bean对象,则该依赖的bean对象就无法创建了,故出现了循环依赖问题,导致程序异常退出。createArgumentArray的核心实现如下:
private ArgumentsHolder createArgumentArray( String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues, BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable, boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException { // 省略其他代码 // 遍历构造函数的参数列表 for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) { // 省略其他代码 try { // 处理@Autowired自动注入的对象属性 Object autowiredArgument = resolveAutowiredArgument( methodParam, beanName, autowiredBeanNames, converter, fallback); args.rawArguments[paramIndex] = autowiredArgument; args.arguments[paramIndex] = autowiredArgument; args.preparedArguments[paramIndex] = new AutowiredArgumentMarker(); args.resolveNecessary = true; } // 省略其他代码 } } // 省略其他代码 return args; }
属性值注入和setter方法注入
- 属性值注入和setter方法注入是spring在创建该bean对象成功后,即调用构造函数创建了bean对象之后,在对该bean对象的属性值进行赋值时处理的,故属性值注入和setter方法注入不存在循环依赖问题,因为此时对象已经创建成功了,在这步进行属性注入主要是避免依赖的属性值为null。具体的方法调用顺序为:
- AbstractBeanFactory的getBean方法:getBean调用doGetBean方法,doGetBean方法内部调用createBean方法。
public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { // 省略其他代码 if (mbd.isSingleton()) { // 创建bean对象实例并注册到单例bean映射map中 sharedInstance = getSingleton(beanName, () -> { try { // bean对象实例创建 return createBean(beanName, mbd, args); } } } // 省略其他代码 }
- AbstractAutowireCapableBeanFactory类定义createBean的方法实现,在createBean方法内部调用doCreateBean方法完成bean对象的创建,包括调用populateBean方法进行属性赋值。populateBean方法的定义如下:
// 属性值赋值 protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { // 省略其他代码 if (hasInstAwareBpps) { if (pvs == null) { pvs = mbd.getPropertyValues(); } // 调用InstantiationAwareBeanPostProcessor的postProcessProperties和postProcessPropertyValues // 即AutowiredAnnotationBeanPostProcessor for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; // 进行属性处理,包括属性注入和setter方法注入 PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); // 省略其他代码 } } } // 省略其他代码 }
- 所以属性值注入和setter方法注入是在AutowiredAnnotationBeanPostProcessor这个类的postProcessProperties方法处理的,AutowiredAnnotationBeanPostProcessor是一个BeanPostProcessor,在创建BeanFactory对象时会创建该BeanPostProcessor对象。
- 在AutowiredAnnotationBeanPostProcessor内部是先进行属性注入,在进行方法注入,核心实现如下:
- 属性和setter方法进行属性值注入
// 属性和setter方法进行属性值注入 @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; }
AutowiredAnnotationBeanPostProcessor内部初始化postProcessProperties中所使用的InjectionMetadata的方法:其中属性值注入是在AutowiredFieldElement定义的,方法注入是在AutowiredMethodElement定义的,这两个都是AutowiredAnnotationBeanPostProcessor的内部类。由以下代码可知,在elements数组中,属性值解析器AutowiredFieldElement在数组前面,故先遍历到;方法注入解析器AutowiredMethodElement在数组后面,故后遍历到。
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) { List<InjectionMetadata.InjectedElement> elements = new ArrayList<>(); Class<?> targetClass = clazz; do { final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>(); // 1. 添加属性注入解析器AutowiredFieldElement到elements ReflectionUtils.doWithLocalFields(targetClass, field -> { AnnotationAttributes ann = findAutowiredAnnotation(field); if (ann != null) { // 省略其他代码 boolean required = determineRequiredStatus(ann); // 属性注入解析器AutowiredFieldElement currElements.add(new AutowiredFieldElement(field, required)); } }); // 2. 添加方法注入解析器AutowiredMethodElement到elements ReflectionUtils.doWithLocalMethods(targetClass, method -> { // 省略其他代码 AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod); if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { // 省略其他代码 boolean required = determineRequiredStatus(ann); PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); // 方法注入解析器AutowiredMethodElement currElements.add(new AutowiredMethodElement(method, required, pd)); } }); elements.addAll(0, currElements); targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); return new InjectionMetadata(clazz, elements); }
- InjectionMetadata的解析过程:遍历elements并调用AutowiredFieldElement或者AutowiredMethodElement的inject方法。AutowiredFieldElement先遍历到,AutowiredMethodElement后遍历到,故先进行属性注入,在进行方法注入。
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()) { // 遍历elements并调用对应的inject方法 for (InjectedElement element : elementsToIterate) { if (logger.isTraceEnabled()) { logger.trace("Processing injected element of bean '" + beanName + "': " + element); } element.inject(target, beanName, pvs); } } }