02_spring_依赖注入

注:以下内容为学习《小马哥讲Spring核心编程思想》的个人笔记

Setter方法依赖注入

手动模式

  • XML 资源配置元信息

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    	<!--通过xml的配置方式注入-->
        <bean class="org.geekbang.thinking.in.spring.ioc.dependency.injection.UserHolder">
            <property name="user" ref="superUser" />
        </bean>
    
    </beans>
    
  • Java 注解配置元信息

        // 通过注解的方式注入
    	@Bean
        public UserHolder userHolder(User user) {
            UserHolder userHolder = new UserHolder();
            userHolder.setUser(user);
            return userHolder;
        }
    
  • API 配置元信息

    	// 通过Api形式
        private static BeanDefinition createUserHolderBeanDefinition() {
            BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
            definitionBuilder.addPropertyReference("user", "superUser");
            return definitionBuilder.getBeanDefinition();
        }
    

实际上,不管是什么形式注入,实际上最后生成的是BeanDefinition,spring通过解析BeanDefinition来创建Bean。因此,Java注解,api配置和xml配置实际上是对BeanDefinition属性的补充

自动模式

不建议使用自动模式,不可控

  • byName

        <bean class="org.geekbang.thinking.in.spring.ioc.dependency.injection.UserHolder"
              autowire="byName"
        >
    <!--        <property name="user" ref="superUser" /> 替换成 autowiring 模式 -->
        </bean>
    
  • byType

        <bean class="org.geekbang.thinking.in.spring.ioc.dependency.injection.UserHolder"
              autowire="byType"
        >
    <!--        <property name="user" ref="superUser" /> 替换成 autowiring 模式 -->
        </bean>
    

构造器依赖注入

手动模式

  • XML 资源配置元信息

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <import resource="classpath:/"/>
    
        <bean class="org.geekbang.thinking.in.spring.ioc.dependency.injection.UserHolder">
            <constructor-arg name="user" ref="superUser" />
        </bean>
    
    </beans>
    
  • Java 注解配置元信息

        @Bean
        public UserHolder userHolder(User user) {
            // 与setter不同的是直接通过构造方法传入Bean
            return new UserHolder(user);
        }
    
  • API 配置元信息

        /**
         * 为 {@link UserHolder} 生成 {@link BeanDefinition}
         *
         * @return
         */
        private static BeanDefinition createUserHolderBeanDefinition() {
            BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
            definitionBuilder.addConstructorArgReference("superUser");
            return definitionBuilder.getBeanDefinition();
        }
    

自动模式

不建议使用自动模式,不可控

  • constructor

    <bean class="org.geekbang.thinking.in.spring.ioc.dependency.injection.UserHolder"
          autowire="constructor">
        <!--        <property name="user" ref="superUser" /> 替换成 autowiring 模式 -->
    </bean>
    

字段注入

注解在字段上面

手动模式

  • Java 注解配置元信息
    • @Autowired

    • @Resource

    • @Inject(可选)

    @Autowired
    private UserHolder userHolder;

    @Resource
    private UserHolder userHolder2;

方法注入

注解在方法上面

手动模式

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);
    }

回调注入

Aware 系列接口回调

内建接口说明
BeanFactoryAware获取 IoC 容器 - BeanFactory
ApplicationContextAware获取 Spring 应用上下文 - ApplicationContext 对象
EnvironmentAware获取 Environment 对象
ResourceLoaderAware获取资源加载器 对象 - ResourceLoader
BeanClassLoaderAware获取加载当前 Bean Class 的 ClassLoader
BeanNameAware获取当前 Bean 的名称
MessageSourceAware获取 MessageSource 对象,用于 Spring 国际化
ApplicationEventPublisherAware获取 ApplicationEventPublishAware 对象,用于 Spring 事件
EmbeddedValueResolverAware获取 StringValueResolver 对象,用于占位符处理

依赖注入类型选择

注入选型

  • 低依赖:构造器注入
  • 多依赖:Setter 方法注入
  • 便利性:字段注入
  • 声明类:方法注入

基础类型注入

  • 原生类型(Primitive):boolean、byte、char、short、int、float、long、double
  • 标量类型(Scalar):Number、Character、Boolean、Enum、Locale、Charset、Currency、Properties、UUID
  • 常规类型(General):Object、String、TimeZone、Calendar、Optional 等
  • Spring 类型:Resource、InputSource、Formatter 等

集合类型注入

  • 数组类型(Array):原生类型、标量类型、常规类型、Spring 类型
  • 集合类型(Collection)
  • Collection:List、Set(SortedSet、NavigableSet、EnumSet)
  • Map:Properties

限定注入

使用注解 @Qualifier 限定

@Configuration
public class QualifierAnnotationDependencyInjectionDemo {

    // 通过名称限定
    @Autowired
    @Qualifier("user1") 
    private User namedUser;

    // 不限定
    @Autowired
    private Collection<User> allUsers; 

    // 分组限定
    @Autowired
    @Qualifier
    private Collection<User> qualifiedUsers; 

    // 自定义注解限定
    @Autowired
    @UserGroup
    private Collection<User> groupedUsers; 

    @Bean
    @Qualifier // 进行逻辑分组
    public User user1() {
        return createUser(7L);
    }

    @Bean
    @Qualifier // 进行逻辑分组
    public User user2() {
        return createUser(8L);

    }

    @Bean
    @UserGroup
    public User user3() {
        return createUser(9L);
    }

    @Bean
    @UserGroup
    public User user4() {
        return createUser(10L);
    }
    
    private static User createUser(Long id) {
        User user = new User();
        user.setId(id);
        return user;
    }

}

  • 通过 Bean 名称限定

    // 通过名称限定,namedUser注入的Bean是user1
    @Autowired
    @Qualifier("user1") 
    private User namedUser;
    
  • 通过分组限定

    // 分组限定,qualifiedUsers注入的是user1,user2,user3,user4。@UserGroup注解扩展了@Qualifier
    @Autowired
    @Qualifier
    private Collection<User> qualifiedUsers; 
    

基于注解 @Qualifier 扩展限定

  • 自定义注解 - 如 Spring Cloud @LoadBalanced

    // 自定义注解限定,groupedUsers注入的是user3,user4。自定义的 @UserGroup 注解
    @Autowired
    @UserGroup
    private Collection<User> groupedUsers; 
    

延迟依赖注入

使用 API ObjectFactory 延迟注入

  • 单一类型
  • 集合类型

使用 API ObjectProvider 延迟注入(推荐)

  • 单一类型

  • 集合类型

    @Autowired
    private ObjectProvider<User> userObjectProvider; // 延迟注入
    
    @Autowired
    private ObjectFactory<Set<User>> usersObjectFactory;
    

依赖处理过程

基础知识

  • 入口 - DefaultListableBeanFactory#resolveDependency

  • 依赖描述符 - DependencyDescriptor

    public class DependencyDescriptor extends InjectionPoint implements Serializable {
    	// 要被注入的类
    	private final Class<?> declaringClass;
    
        // 方法注入的方法名
    	@Nullable
    	private String methodName;
    
        // 构造器注入的参数列表
    	@Nullable
    	private Class<?>[] parameterTypes;
    
    	private int parameterIndex;
    
        // 字段注入的字段名
    	@Nullable
    	private String fieldName;
    
        // 参考@Autowire里面required
    	private final boolean required;
    
        // 是否是懒加载
    	private final boolean eager;
    
    	private int nestingLevel = 1;
    
    	@Nullable
    	private Class<?> containingClass;
    
    	@Nullable
    	private transient volatile ResolvableType resolvableType;
    
    	@Nullable
    	private transient volatile TypeDescriptor typeDescriptor;
    }
    
  • 自定绑定候选对象处理器 - AutowireCandidateResolver

@Autowired注入原理

@Autowired 注入的步骤在org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties方法中,该方法在 org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor 接口中定义。

  • 元信息解析
  • 依赖查找
  • 依赖注入(字段、方法)
//org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			Field field = (Field) this.member;
			Object value;
			if (this.cached) {
				value = resolvedCachedArgument(beanName, this.cachedFieldValue);
			}
			else {
                // 获取依赖描述符
				DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
				desc.setContainingClass(bean.getClass());
				Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
				Assert.state(beanFactory != null, "No BeanFactory available");
				TypeConverter typeConverter = beanFactory.getTypeConverter();
				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) {
						if (value != null || this.required) {
							this.cachedFieldValue = desc;
							registerDependentBeans(beanName, autowiredBeanNames);
							if (autowiredBeanNames.size() == 1) {
								String autowiredBeanName = autowiredBeanNames.iterator().next();
								if (beanFactory.containsBean(autowiredBeanName) &&
										beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
									this.cachedFieldValue = new ShortcutDependencyDescriptor(
											desc, autowiredBeanName, field.getType());
								}
							}
						}
						else {
							this.cachedFieldValue = null;
						}
						this.cached = true;
					}
				}
			}
    		// 通过反射进行注入
			if (value != null) {
				ReflectionUtils.makeAccessible(field);
				field.set(bean, value);
			}
		}
	}

JSR-330 @Inject注入原理

@Inject 注入过程

如果 JSR-330 存在于 ClassPath 中,复用 AutowiredAnnotationBeanPostProcessor 实现

//org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#AutowiredAnnotationBeanPostProcessor
public AutowiredAnnotationBeanPostProcessor() {
		this.autowiredAnnotationTypes.add(Autowired.class);
		this.autowiredAnnotationTypes.add(Value.class);
		try {
            // 判断加载Inject注解,如果不存在,则不加载
			this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
					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.
		}
	}

Java通用注解注入注解

@Autowired 注入的步骤在org.springframework.beans.factory.annotation.CommonAnnotationBeanPostProcessor#postProcessProperties方法中,该方法在 org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor 接口中定义。

注入注解

  • javax.xml.ws.WebServiceRef
  • javax.ejb.EJB
  • javax.annotation.Resource

生命周期注解

  • javax.annotation.PostConstruct
  • javax.annotation.PreDestroy

自定义依赖注入注解

有用的广告

​ 我是程序员,也热爱投资。个人认为,程序员这种职业(大部分是青春饭)非常适合投资,在年轻的积累本金,35岁后能过有睡后收入,想想就美滋滋。当然,如果没有专业的投资知识就是在股市中韭菜的份,这里推广下我学习投资知识的地方。简单说明下,这两个群都不会荐股,只是告诉你投资理念和知识,授人以鱼不如授人以渔,如果对投资感兴趣的人,我相信你会觉得相见恨晚。

老齐的读书圈:里面包含了几百本书籍,主要包括投资类,格局类,经营管理类三种。感兴趣的可以听听,三天内无条件可以退款。强烈推荐
在这里插入图片描述

齐俊杰的粉丝群:主要是对市场的解读,当然里面主要考虑的是周期的定位以及资产配置的相关知识。感兴趣的也可以进来听听,
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值