(头条代码排版存在问题,可点击底部链接查看原文)
一、自动依赖注入的方式
注解类型
- 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);
}
}
}
