@Autowired的原理简识

发布于:2022-12-14 ⋅ 阅读:(459) ⋅ 点赞:(0)

一、@Autowired是什么

(1)存在范围

@Autowired注解是属于spring的容器配置的一个注解,因此@Autowired注解是一个用于Spring容器配置的注解。与它同属容器配置的注解还有:

@Primary(含义:首选项,当类型冲突情况下,此注解修饰类作为首选注入
                 位置:修饰类
                 注意:不能单独使用),

@Qualifier(value="注入的id")

                 含义:按照名称装配
                 位置:修饰成员变量
                 注意:不能单独使用

 @Resource(name="注入的id")
            含义:按照名称装配
            位置:修饰成员变量
            注意:单独使用......等等。

(2)定义解释

@Autowired注解又称:自动装配。在Spring中,自动装配指的就是使用将Spring容器中的bean自动的和我们需要这个bean的类组装在一起。

二、什么情况下使用到@Autowired

前情回顾:使用spring开发时,进行配置Spring bean元数据主要有三种方式。

一:基于 XML 配置

二:基于 注解  配置:Spring2.5以上版本支持

三:基于Java 配置:Spring3.0以上版本支持

基于注解配置时,完成自动化装配Bean的情况下,@Autowired的使用便会使Spring自动满足bean之间的依赖注入。

三、如何使用@Autowired

(1)使用位置:修饰成员变量

@Controller
public class StudentControllerImp implements IStudentController {

    @Autowired
    private IStudentService service;

    @Override
    public void save() {
        System.out.println("======controler的新增方法=======");
        service.save();
    }
}

(2)在xml文件中完成组件扫描设置

 <!--扫描包-->
    <context:component-scan base-package="com.apesource"></context:component-scan>

com.apesource---包名;启用组件扫描,默认当前配置类所在包为基础包

四、@Autowired注解是如何实现的

--------------------------------以下部分内容参考于相关公众号文章-----------------------------------------------

(1)打开@Autowired源码

package org.springframework.beans.factory.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    boolean required() default true;
}

我们知道: 在java中注解实现的核心技术是反射

(2)我们让看一下源代码中的元注解(也就是上面提到的注解的注解),总共有4个如下:

  • @Target,说明的是Annotation所修饰的对象范围

  • @Retention,定义了该Annotation被保留的时间长短:使用这个元注解可以对 Annotation的“生命周期”限制

  • @Documented,用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员

  • @Inherited;元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类

Autowired注解可以应用在构造方法,普通方法,参数,字段,以及注解这五种类型的地方,它的保留策略是在运行时。

(3)在Spring源代码当中,Autowired注解位于包org.springframework.beans.factory.annotation之中,该包的内容如下:

Spring对autowire注解的实现逻辑位于类:AutowiredAnnotationBeanPostProcessor之中,红色箭头所指的类。其中的核心处理代码如下:

private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
		if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
			return InjectionMetadata.EMPTY;
		}

		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;	//需要处理的目标类

		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

//通过反射获取该类所有的字段,并遍历每一个字段,并通过方法findAutowiredAnnotation遍历每一个字段的所用注解,并如果用autowired修饰了,则返回auotowired相关属性

			ReflectionUtils.doWithLocalFields(targetClass, field -> {
				MergedAnnotation<?> ann = findAutowiredAnnotation(field);

				if (ann != null) {校验autowired注解是否用在了static方法上

					if (Modifier.isStatic(field.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static fields: " + field);
						}
						return;

						//判断是否指定了required

					}
					boolean required = determineRequiredStatus(ann);
					currElements.add(new AutowiredFieldElement(field, required));
				}
			});

				//和上面一样的逻辑,但是是通过反射处理类的method

			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
				if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
					return;
				}
				MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
				if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
					if (Modifier.isStatic(method.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static methods: " + method);
						}
						return;
					}
					if (method.getParameterCount() == 0) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation should only be used on methods with parameters: " +
									method);
						}
					}
					boolean required = determineRequiredStatus(ann);
					PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
					currElements.add(new AutowiredMethodElement(method, required, pd));
				}
			});


			//用@Autowired修饰的注解可能不止一个,因此都加在currElements这个容器里面,一起处理  

			elements.addAll(0, currElements);
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);

		return InjectionMetadata.forElements(elements, clazz);
	}

最后这个方法返回的是一个InjectionMetadata集合。由两部分组成:

一是我们处理的目标类,二就是上述方法获取到的所以elements集合。

源代码:

	private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
		if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
			return InjectionMetadata.EMPTY;
		}

		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;

有了目标类,与所有需要注入的元素集合之后,我们就可以实现autowired的依赖注入逻辑了,实现的方法如下:

源代码:

@Deprecated
	@Override
	public PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {

		return postProcessProperties(pvs, bean, beanName);
	}

 它调用的方法是InjectionMetadata中定义的inject方法,如下

源代码

@Override
		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			Field field = (Field) this.member;
			Object value;
			if (this.cached) {
				try {
					value = resolvedCachedArgument(beanName, this.cachedFieldValue);
				}
				catch (NoSuchBeanDefinitionException ex) {
					// Unexpected removal of target bean for cached argument -> re-resolve
					value = resolveFieldValue(field, bean, beanName);
				}
			}
			else {
				value = resolveFieldValue(field, bean, beanName);
			}
			if (value != null) {
				ReflectionUtils.makeAccessible(field);
				field.set(bean, value);
			}
		}

 然后调用inject方法;

 源代码

@Override
		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			if (checkPropertySkipping(pvs)) {
				return;
			}
			Method method = (Method) this.member;
			Object[] arguments;
			if (this.cached) {
				try {
					arguments = resolveCachedArguments(beanName);
				}
				catch (NoSuchBeanDefinitionException ex) {
					// Unexpected removal of target bean for cached argument -> re-resolve
					arguments = resolveMethodArguments(method, bean, beanName);
				}
			}
			else {
				arguments = resolveMethodArguments(method, bean, beanName);
			}
			if (arguments != null) {
				try {
					ReflectionUtils.makeAccessible(method);
					method.invoke(bean, arguments);
				}
				catch (InvocationTargetException ex) {
					throw ex.getTargetException();
				}
			}
		}

在这里的代码当中我们也可以看到,是inject也使用了反射技术并且依然是分成字段和方法去处理的。在代码里面也调用了makeAccessible这样的可以称之为暴力破解的方法,但是反射技术本就是为框架等用途设计的。

对于方法的话,本质就是去调用这个方法,因此这里调用的是method.invoke.

getResourceToInject方法的参数就是要注入的bean的名字,这个方法的功能就是根据这个bean的名字去拿到它。

总结:

使用@Autowired注入的bean对于目标类来说,从代码结构上来讲也就是一个普通的成员变量,@Autowired和spring一起工作,通过反射为这个成员变量赋值,将其变为实例对象。


网站公告

今日签到

点亮在社区的每一天
去签到