【Spring】IoC容器 - 依赖注入
阅读原文时间:2023年07月11日阅读:2

前言

上一篇文章已经学习了【依赖查找】相关的知识,这里详细的介绍一下【依赖注入】。

依赖注入 - 分类

因为自己是基于小马哥的脉络来学习,并且很认可小马哥梳理的分类方式,下面按照小马哥思想为【依赖注入】分类:

  1. Setter方法注入
  2. 构造器注入
  3. 字段注入
  4. 方法注入
  5. 接口回调注入

1. Setter方法注入

1.1 手动模式

1.1.1 XML配置
    <bean class="org.geekbang.thinking.in.spring.ioc.dependency.injection.UserHolder">
        <property name="user" ref="superUser" />
    </bean>

Spring容器里面有另外一个bean,名字是superUser。

这里user bean的注入就是使用的setter注入。可以在set方法上打断点验证。

后续我们会进行源码分析。

1.1.2 Java注解配置
    @Bean
    public UserHolder userHolder(User user) {
        UserHolder userHolder = new UserHolder();
        userHolder.setUser(user);
        return userHolder;
    }
1.1.3 API配置
    /**
     * 为 UserHolder 生成 BeanDefinition
     */
    private static BeanDefinition createUserHolderBeanDefinition() {
        BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
        definitionBuilder.addPropertyReference("user", "superUser");
        return definitionBuilder.getBeanDefinition();
    }

1.2 自动模式

1.2.1 byName
    <bean class="org.geekbang.thinking.in.spring.ioc.dependency.injection.UserHolder" autowire="byName">
    </bean>

自动装配默认是byType,不是byName

1.2.2 byType
    <bean class="org.geekbang.thinking.in.spring.ioc.dependency.injection.UserHolder" autowire="byType">
    </bean>

2. 构造器注入

2.1 手动模式

2.1.1 XML配置
    <bean class="org.geekbang.thinking.in.spring.ioc.dependency.injection.UserHolder">
        <constructor-arg name="user" ref="superUser" />
    </bean>

Spring容器里面有另外一个bean,名字是superUser。

2.1.2 Java注解配置
    @Bean
    public UserHolder userHolder(User user) {
        return new UserHolder(user);
    }
2.1.3 API配置
    /**
     * 为 UserHolder 生成 BeanDefinition
     */
    private static BeanDefinition createUserHolderBeanDefinition() {
        BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
        definitionBuilder.addConstructorArgReference("superUser");
        return definitionBuilder.getBeanDefinition();
    }

2.2 自动模式

2.2.1 constructor
    <bean class="org.geekbang.thinking.in.spring.ioc.dependency.injection.UserHolder"
          autowire="constructor">
    </bean>

这里的UserHolder类中存在如下构造器:

    public UserHolder(User user) {
        this.user = user;
    }

构造器自动注入的时候会去spring容器中获取type为User的bean,自动注入。

3. 字段注入

字段注入只有手动模式,并且只支持Java注解配置。

@Autowired

@Resource

@Inject(可选)

    @Autowired
    private UserHolder userHolder;
    @Resource(name = "xxxx")
    private UserHolder userHolder2;
    @Inject
    private UserHolder userHolder2;

4. 方法注入

方法注入只有手动模式,并且只支持Java注解配置。

@Autowired

@Resource

@Inject(可选)

@Bean

    @Autowired
    public void init1(UserHolder userHolder) {
        this.userHolder = userHolder;
    }
    @Resource
    public void init2(UserHolder userHolder2) {
        this.userHolder2 = userHolder2;
    }
    @Bean
    public UserHolder userHolder(User user) {
        return new UserHolder(user);
    }

项目中有使用到如下的一种方法注入:

@Autowired
public MyClass(Map<String, MyApplicationEvent> eventMap) {
       //any logic
}

这里是自己的bean的构造器,参数eventMap会被容器自动构建一个map,所有MyApplicationEvent类型的bean都会被装载,map的key是bean的名字。

5. 接口回调注入Aware

public class AwareInterfaceDependencyInjectionDemo implements BeanFactoryAware, ApplicationContextAware {

    private static BeanFactory beanFactory;

    private static ApplicationContext applicationContext;

    public static void main(String[] args) {

        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        // 注册 Configuration Class(配置类) -> Spring Bean
        context.register(AwareInterfaceDependencyInjectionDemo.class);

        // 启动 Spring 应用上下文
        context.refresh();

        System.out.println(beanFactory == context.getBeanFactory());
        System.out.println(applicationContext == context);

        // 显示地关闭 Spring 应用上下文
        context.close();
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        AwareInterfaceDependencyInjectionDemo.beanFactory = beanFactory;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        AwareInterfaceDependencyInjectionDemo.applicationContext = applicationContext;
    }
}

之前倒是熟悉这个接口项目中也在使用,但是没想到分类居然是依赖注入相关的。

各种注入方式的比较

上面介绍来大部分注入方式,其实在我自己的项目中用得最多的自然就是字段注入。相信大部分Java开发都是,但是熟悉其他注入方式对spring应用的扩展与理解有更好的帮助。

注入方式

适合于

构造器注入

低依赖

Setter

多依赖

字段注入

便利性

方法注入

声明类

依赖注入 - 特殊注入方式说明

基础类型注入

集合类型注入

限定注入

延迟依赖注入

依赖处理过程

依赖处理过程基础知识

入口:org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency

依赖描述符:org.springframework.beans.factory.config.DependencyDescriptor

自动绑定候选对象处理器:org.springframework.beans.factory.support.AutowireCandidateResolver

依赖处理过程解析

我们先来分析一下DefaultListableBeanFactory.resolveDependency()的方法:

点击查看代码

/**
 * 参数1:DependencyDescriptor是依赖描述符
 * 参数2:requestingBeanName,待注入的bean名称
 */
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
        @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

    descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
    //注入类型如果是Optional,特殊处理。
    if (Optional.class == descriptor.getDependencyType()) {
        return createOptionalDependency(descriptor, requestingBeanName);
    }
    //注入类型如果是ObjectFactory或ObjectProvider,特殊处理。
    else if (ObjectFactory.class == descriptor.getDependencyType() ||
            ObjectProvider.class == descriptor.getDependencyType()) {
        return new DependencyObjectProvider(descriptor, requestingBeanName);
    }
    //注入类型如果是javax.inject.Provider,特殊处理。
    else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
        return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
    }
    else {
        //常规依赖处理,使用[自动绑定候选对象处理器]处理一个事情,先放着。。。
        Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
                descriptor, requestingBeanName);
        if (result == null) {
            //真正的处理依赖在这里
            result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
        }
        return result;
    }
} 

然后是:DefaultListableBeanFactory.doResolveDependency

点击查看代码

@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
        @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

    //处理嵌套注入时候的一个保护点,获取上次注入点(InjectionPoint),
    //内部使用的是ThreadLocal去存储InjectionPoint,所以这里获取的是单线程内的上次的注入点
    InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
    try {
        //获取描述符的shortcut
        Object shortcut = descriptor.resolveShortcut(this);
        if (shortcut != null) {
            return shortcut;
        }
        //获取注入类型,未深入
        Class<?> type = descriptor.getDependencyType();
        //获取建议值,未深入
        Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
        if (value != null) {
            if (value instanceof String) {
                String strVal = resolveEmbeddedValue((String) value);
                BeanDefinition bd = (beanName != null && containsBean(beanName) ?
                        getMergedBeanDefinition(beanName) : null);
                value = evaluateBeanDefinitionString(strVal, bd);
            }
            TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
            try {
                return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
            }
            catch (UnsupportedOperationException ex) {
                // A custom TypeConverter which does not support TypeDescriptor resolution...
                return (descriptor.getField() != null ?
                        converter.convertIfNecessary(value, type, descriptor.getField()) :
                        converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
            }
        }
        //判断是不是处理多个bean,比如Map,Array,List的注入就是在这里处理。
        Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
        if (multipleBeans != null) {
            return multipleBeans;
        }
        //重点:根据要注入的描述符,bean的名字,获取可以注入的容器上下文里面可以注入的候选bean
        //20210926分析到这里,接下来进入该方法分析
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
        if (matchingBeans.isEmpty()) {
            if (isRequired(descriptor)) {
                raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
            }
            return null;
        }

        String autowiredBeanName;
        Object instanceCandidate;

        if (matchingBeans.size() > 1) {
            autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
            if (autowiredBeanName == null) {
                if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
                    return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
                }
                else {
                    // In case of an optional Collection/Map, silently ignore a non-unique case:
                    // possibly it was meant to be an empty collection of multiple regular beans
                    // (before 4.3 in particular when we didn't even look for collection beans).
                    return null;
                }
            }
            instanceCandidate = matchingBeans.get(autowiredBeanName);
        }
        else {
            // We have exactly one match.
            Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
            autowiredBeanName = entry.getKey();
            instanceCandidate = entry.getValue();
        }

        if (autowiredBeanNames != null) {
            autowiredBeanNames.add(autowiredBeanName);
        }
        if (instanceCandidate instanceof Class) {
            instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
        }
        Object result = instanceCandidate;
        if (result instanceof NullBean) {
            if (isRequired(descriptor)) {
                raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
            }
            result = null;
        }
        if (!ClassUtils.isAssignableValue(type, result)) {
            throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
        }
        return result;
    }
    finally {
        ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
    }
} 

依赖描述符DependencyDescriptor类定义:

点击查看代码

/**
 * Descriptor for a specific dependency that is about to be injected.
 * Wraps a constructor parameter, a method parameter or a field,
 * allowing unified access to their metadata.
 * (一个特定被注入的依赖的描述符。包含一个构造器、方法或者字段。包装构造函数参数、方法参数或字段,允许对其元数据进行统一访问。)
 * @author Juergen Hoeller
 * @since 2.5
 */
public class DependencyDescriptor extends InjectionPoint implements Serializable { 

注入原理

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器