5、spring核心源码解析之DI依赖注入、自动装配@Autowired和@Resource

文章目录

    • 前情
    • 1.依赖注入之setter注入
    • 2.依赖注入之构造方法注入
    • 3.依赖注入之自动装配之@Autowired、@Resource等注解详解
    • 4.依赖注入源码分析
    • 5.@Autowired和@Resource的应用与分析
    • 6.ioc小结

前情

​ spirng 的DI(dependency injection )依赖注入是我们在开发中最常用的,如setter注入、构造方法注入,还有我们的自动装配@Autowired、@Resource注入,它可以帮助我们更好的关注我们的业务开发,而无需关注DI依赖注入的实现细节。

​ 为什么有时候我们还可以将一个接口的多个实现类通过map的形式进行注入呢?难道你在开发的过程中对spring如何实现通过一个注解就完成这些就不好奇吗?

为了更清晰的理解概念,本文将采用xml和java配置类结合的方式进行讲解。

1.依赖注入之setter注入

两个实体类Person、Car

public class Person {
	private String name;
	private Car car;

//	public Person(String name, Car car) {
//		this.name = name;
//		this.car = car;
//	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Car getCar() {
		return car;
	}

	public void setCar(Car car) {
		this.car = car;
	}
}
public class Car {
	private String name;
	private String color;
	private String price;

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}
	public String getPrice() {
		return price;
	}
	public void setPrice(String price) {
		this.price = price;
	}
}

使用xml方式完成setter注入,很简单的setter属性注入。

	<bean id="car" class="com.upanda.app.test.Car">bean>
	
	<bean id="person" class="com.upanda.app.test.Person">
		<property name="car" ref="car"/>
		<property name="name" value="coyhzx"/>
	bean>

使用java配置类的方式完成setter注入,个人理解~就是调用setter方法注入属性。

public void setCar(Car car) {
		this.car = car;
	}

2.依赖注入之构造方法注入

使用xml方式完成构造方法注入,很简单的setter属性注入。

	<bean id="car" class="com.upanda.app.test.Car">bean>

	<bean id="person" class="com.upanda.app.test.Person">
		<constructor-arg name="name" value="coyhzx"/>
		<constructor-arg name="car" ref="car"/>
	bean>

java配置类的方式完成构造方法注入,个人理解就是通过构造方法注入。

public Person(String name, Car car) {
		this.name = name;
		this.car = car;
	}

3.依赖注入之自动装配之@Autowired、@Resource等注解详解

	
	<bean id="person" class="com.upanda.app.test.Person" autowire="byName" >
	bean>

至于java配置类方式的注入,最常见的就是service中,注入dao了,此处类似。

@Autowired
private Car car;

@Autowried自动装配的方式有三种,在Autowire枚举类中有定义

Autowire#NO:表示没有自动装配的常量(注入:并不代表这种就是不能自动装配)。

Autowire#BY_NAME:表示通过名称自动装配

Autowire#BY_TYPE:表示通过类型自动装配

在AutowireCapableBeanFactory类中定义了五种依赖注入,包括上述三种的自动装配。

AUTOWIRE_NO:表示没有外部的自动装配,但是BeanFactoryAware和注解驱动的注入仍旧能应用。

应用场景:在创建bean、指定autowire方式、bean的属性注入时应用。

AUTOWIRE_BY_NAME:表示通过名称依赖注入

应用场景:在创建bean、指定autowire方式、bean的属性注入时应用。

AUTOWIRE_BY_TYPE:表示通过类型依赖注入

应用场景:在创建bean、指定autowire方式、bean的属性注入时应用。

AUTOWIRE_CONSTRUCTOR:表示通过构造函数进行依赖注入

应用场景:在创建bean、指定autowire方式。

AUTOWIRE_AUTODETECT:表示通过内省bean类依赖注入

应用场景:在创建bean、指定autowire方式。

	/**
	 * Constant that indicates no externally defined autowiring. Note that
	 * BeanFactoryAware etc and annotation-driven injection will still be applied.
	 * @see #createBean 创建bean时
	 * @see #autowire 自动注入
	 * @see #autowireBeanProperties bean的属性注入
	 */
	//指示没有外部定义的自动装配的常数。注意BeanFactoryAware等和注解驱动的注入将仍然适用。
	int AUTOWIRE_NO = 0;

	/**
	 * Constant that indicates autowiring bean properties by name
	 * (applying to all bean property setters).
	 * @see #createBean
	 * @see #autowire
	 * @see #autowireBeanProperties
	 */
	//通过名称指示自动装配Bean属性的常数,应用于所有bean属性设置
	int AUTOWIRE_BY_NAME = 1;

	/**
	 * Constant that indicates autowiring bean properties by type
	 * (applying to all bean property setters).
	 * @see #createBean
	 * @see #autowire
	 * @see #autowireBeanProperties
	 */
	//指示按类型自动装配Bean属性的常量,应用于所有bean属性设置
	int AUTOWIRE_BY_TYPE = 2;

	/**
	 * Constant that indicates autowiring the greediest constructor that
	 * can be satisfied (involves resolving the appropriate constructor).
	 * @see #createBean
	 * @see #autowire
	 */
	//指示自动装配可以满足最贪婪的构造函数的常数(涉及解析适当的构造函数)
	int AUTOWIRE_CONSTRUCTOR = 3;

	/**
	 * Constant that indicates determining an appropriate autowire strategy
	 * through introspection of the bean class.
	 * @see #createBean
	 * @see #autowire
	 * @deprecated as of Spring 3.0: If you are using mixed autowiring strategies,
	 * prefer annotation-based autowiring for clearer demarcation of autowiring needs.
	 */
	//指示通过内省bean类确定适当的自动装配策略的常数
	@Deprecated
	int AUTOWIRE_AUTODETECT = 4;

总结一下,其实依赖注入和自动装配的概率有点模糊,总之就是我们可以通过spring ioc容器自动的完成了我们的依赖注入和自动装配,如果非要说有什么区别,通过我刚刚给出的两个类里定义的依赖方式,可以发现依赖注入的本质是包含了自动装配。

好了,接下来我们就来具体看看源码是怎么完成 自动装配的。

4.依赖注入源码分析

  1. 首先构造方法注入流程
    5、spring核心源码解析之DI依赖注入、自动装配@Autowired和@Resource_第1张图片

  2. 分析核心源码,最核心代码在ConstructorResolver#resolveAutowiredArgument方法中。

在该方法中,重点就是从beanFacotry容器中解析依赖----后续是beanFactory根据类型查找Bean,这个不复杂,但是代码量还有点大,有兴趣的朋友可以继续跟踪一下。

最后获取到参数之后,bean的实例化时就是通过有参构造进行反射实例化bean。

protected Object resolveAutowiredArgument(MethodParameter param, String beanName,
			@Nullable Set<String> autowiredBeanNames, TypeConverter typeConverter, boolean fallback) {

		Class<?> paramType = param.getParameterType();
		if (InjectionPoint.class.isAssignableFrom(paramType)) {
			InjectionPoint injectionPoint = currentInjectionPoint.get();
			if (injectionPoint == null) {
				throw new IllegalStateException("No current InjectionPoint available for " + param);
			}
			return injectionPoint;
		}
		try {
            //重点,从beanFacotry容器中解析依赖----后续是beanFactory根据类型查找Bean。
			return this.beanFactory.resolveDependency(
					new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);
		}
    }

​ 其他注入方式大同小异,有兴趣的可以自行了解一下。

5.@Autowired和@Resource的应用与分析

@Autowired: 是spring自动装配的注解,默认按照类型byType进行自动装配。

@Resource:是jdk自带的一个注解,在spring中也具有自动装配功能,其中可以通过指定name,通过名称进行装配,也可以指定type,按照类型进行自动装配。同时指定同时指定name和type,这样只有两者都满足才能进行自动装配。

@Autowired和@Resource这两个注解都是通过后置处理器进行解析完成自动装配,属性填充的。

@Autowired注解是被AutowiredAnnotationBeanPostProcessor进行解析完成自动装配的。

@Resource注解是被CommonAnnotationBeanPostProcessor进行解析完成自动装配的。

两者直接或间接的实现了InstantiationAwareBeanPostProcessor接口,都有一个相同的方法postProcessProperties,处理bean的自动装配属性。

CommonAnnotationBeanPostProcessor#postProcessProperties方法。

	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
		InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
		try {
			metadata.inject(bean, beanName, pvs);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
		}
		return pvs;
	}

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

具体的依赖注入过程其实我在spring核心源码分析的第二篇文章的依赖注入中讲了,不重复叙述了。

6.ioc小结

​ 整体的ioc容器,依赖注入的思想在一次次的源码分析之后,我并没有觉得很复杂。但是这也只是spring的核心思想之一,也是最基础的。只有在充分了解了bean的初始化过程,以及容器的初始化过程,在后续,我们才能慢慢的理解spring boot是为何、如何一步步将其做成启动依赖的自动装配。

​ 只有自己用心思考,深入源码,才能在日常遇到问题时,做到处变不惊,冷静分析、解决问题。

​ 学习优秀的代码编程设计思想,提升自我的代码编程设计思想。

上一篇:4、spring核心源码解析之自定义bean三种方式@import、ImportSelector、ImportBeanDefinitionRegistrar
下一篇:6、spring核心源码解析之aop概况流程1

你可能感兴趣的:(spring,5.0,源码,源码解析,spring,java,bean)