@Autowired 是 Spring 提供的注解,默认的注入方式为 byType (按类型自动注入);@Autowired 注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作;通过 @Autowired的使用来消除 set ,get方法。
@Value
含义:通过set方式注入基本类型与String,set方法可以省略
语法:@Value("数据")/@Value("${key}")
位置:修饰属性,set方法
注意:如果动态获取必须指定加载资源文件
@Autowired
替换:autowire属性,自动装配(按照类型装配,通过set方法,且方法可以省略)
位置:修饰属性,set方法
语法:@Autowired(required="true")
注意:1.如果容器中没有一个可以与之匹配且required属性为true则会报异常
NoSuchBeanDefinitionException
2.如果容器中有多个可以类型可以与之匹配,则自动切换为按照名称装配
3.如果名称也没有匹配,则报异常NoUniqueBeanDefinitionException
@Autowired注解在spring源代码里的定义:
- 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;
- }
通过代码看到Autowired注解可以应用在构造方法,普通方法,参数,字段,以及注解这五种类型的地方,它的保留策略是在运行时。
在Spring源代码当中,Autowired注解位于包org.springframework.beans.factory.annotation之中,实现逻辑位于类:AutowiredAnnotationBeanPostProcessor之中。
核心处理代码如下:
- private InjectionMetadata buildAutowiringMetadata(final Class> clazz) {
- LinkedList
elements = new LinkedList<>(); - Class> targetClass = clazz;//需要处理的目标类
-
- do {
- final LinkedList
currElements = new LinkedList<>(); -
- /*通过反射获取该类所有的字段,并遍历每一个字段,并通过方法findAutowiredAnnotation遍历每一个字段的所用注解,并如果用autowired修饰了,则返回auotowired相关属性*/
-
- ReflectionUtils.doWithLocalFields(targetClass, field -> {
- AnnotationAttributes ann = findAutowiredAnnotation(field);
- if (ann != null) {//校验autowired注解是否用在了static方法上
- if (Modifier.isStatic(field.getModifiers())) {
- if (logger.isWarnEnabled()) {
- logger.warn("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;
- }
- AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
- if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
- if (Modifier.isStatic(method.getModifiers())) {
- if (logger.isWarnEnabled()) {
- logger.warn("Autowired annotation is not supported on static methods: " + method);
- }
- return;
- }
- if (method.getParameterCount() == 0) {
- if (logger.isWarnEnabled()) {
- logger.warn("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 new InjectionMetadata(clazz, elements);
- }
最后这个方法返回的就是包含所有带有autowire注解修饰的一个InjectionMetadata集合。这个类由两部分组成:
- public InjectionMetadata(Class> targetClass, Collection
elements) { - this.targetClass = targetClass;
- this.injectedElements = elements;
- }
一是处理的目标类,二就是上述方法获取到的所以elements集合。
有了目标类,与所有需要注入的元素集合之后,就可以实现autowired的依赖注入逻辑了,实现的方法如下:
- @Override
- public PropertyValues postProcessPropertyValues(
- PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
-
- 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;
- }
它调用的方法是InjectionMetadata中定义的inject方法,如下
- public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
- Collection
checkedElements = this.checkedElements; - Collection
elementsToIterate = - (checkedElements != null ? checkedElements : this.injectedElements);
- if (!elementsToIterate.isEmpty()) {
- for (InjectedElement element : elementsToIterate) {
- if (logger.isTraceEnabled()) {
- logger.trace("Processing injected element of bean '" + beanName + "': " + element);
- }
- element.inject(target, beanName, pvs);
- }
- }
- }
其逻辑就是遍历,然后调用inject方法,inject方法其实现逻辑如下:
-
- protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
- throws Throwable {
-
- if (this.isField) {
- Field field = (Field) this.member;
- ReflectionUtils.makeAccessible(field);
- field.set(target, getResourceToInject(target, requestingBeanName));
- }
- else {
- if (checkPropertySkipping(pvs)) {
- return;
- }
- try {
- Method method = (Method) this.member;
- ReflectionUtils.makeAccessible(method);
- method.invoke(target, getResourceToInject(target, requestingBeanName));
- }
- catch (InvocationTargetException ex) {
- throw ex.getTargetException();
- }
- }
- }
inject也使用了反射技术并且依然是分成字段和方法去处理的。