精华内容
下载资源
问答
  • Autowired注解

    千次阅读 2019-01-28 16:17:27
    spring项目中我们经常使用到spring的一个注解@Autowired,这个注解是用于实现spring的一个特性,IOC(Inversion of Control)控制反转,spring将项目中的实体进行集中管理,然后通过@Autowired注解作为标识,以自动...

    spring项目中我们经常使用到spring的一个注解@Autowired,这个注解是用于实现spring的特性,IOC(Inversion of Control)控制反转和DI依赖注入,spring将项目中的实体进行集中管理,然后通过@Autowired注解作为标识,以自动注入的方式来给实体注入属性,这些操作都是基于java反射机制来实现的。

    因为前段时间学习了反射的一些知识,遂尝试使用反射知识来简单实现@Autowired的注入功能。

    自定义注入注解@CustomAutowired

    用于标识需要被注入的属性

    import java.lang.annotation.*;
    
    @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface CustomAutowired {
    }

    User

    需要被注入的类,User有个私有属性name

    public class User {
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    

     Company

    被注入User实例对象的Company

    public class Company {
    
        @CustomAutowired
        private User user;
    
        public void getUserName(){
            System.out.println(user.getName());
        }
    }

     MainTest

    import java.lang.annotation.Annotation;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    public class MainTest {
    
        public static void main(String[] args) {
            try {
                //获取Company的Class
                Class companyClass = Company.class;
    
                //新建compant对象实例
                Object company = companyClass.newInstance();
                //获取Company中所有的字段
                Field[] fields = companyClass.getDeclaredFields();
    
                //开始循环
                for (int i = 0; i < fields.length; i++) {
                    //获取字段
                    Field tempField = fields[i];
                    //获取字段上的注解
                    Annotation[] annotations = tempField.getAnnotations();
                    //循环注解
                    for (int j = 0; j < annotations.length; j++) {
                        //获取字段上注解的类型
                        Class tempAnnotationClass = annotations[j].annotationType();
                        //判断如果注解的类型是自定义的注入注解
                        if(tempAnnotationClass == CustomAutowired.class){
                            //获取字段的类型
                            Class fieldClass = tempField.getType();
                            //新建字段的实例对象
                            Object fieldObject = fieldClass.newInstance();
                            //如果字段类型是我新建的User的类型的话
                            if(fieldClass == User.class){
                                //获取User类中的name属性字段
                                Field nameField = fieldClass.getDeclaredField("name");
                                //因为User里的name字段是private的,所以要先设置访问权限为true
                                nameField.setAccessible(true);
                                //然后再给name字段设值
                                nameField.set(fieldObject,"呆某人");
    
                                //Company中的User字段也是private,所以也需要设置权限
                                tempField.setAccessible(true);
                                //最后给company实例对象中的user字段赋值
                                tempField.set(company,fieldObject);
                            }
                        }
                    }
                }
    
                //获取Company中的所有方法
                Method[] methods = companyClass.getMethods();
                //开始循环
                for (int i = 0; i < methods.length; i++) {
                   //找到方法名是getUserName的方法
                   if("getUserName".equals(methods[i].getName())){
                       //进行调用
                       methods[i].invoke(company,null);
                   }
                }
    
            }catch (Exception e){
                e.printStackTrace();
            }
    
        }
    }

    首先获取到Company类对象,然后创建Company对象实例,然后获取到Company中的字段数组,开始循环字段数组,如果该字段上有@CustomAutowired注解,则实例化该字段,如果该字段是User类的话,获取它的name字段,然后给name字段赋值,再将实例化后的User对象赋值给Company对象中的User字段,这样就达到了属性注入的效果。最后循环Company中的方法,调用getUserName方法,输出结果。这就是我通过反射机制来简单实现的注入的功能。

     运行结果

     

    展开全文
  • Spring不但支持自己的@Autowired注解,还支持几个由JSR-250规范定义的注解(如@Resource)。相同点@Autowired注解和@Resource注解均可以标注在字段上或者属性的setter方法上(下面的其中一种即可)。@Autowiredprivate ...

    8cc0a485fdc612e7a0acdec11028af32.png

    Spring不但支持自己的@Autowired注解,还支持几个由JSR-250规范定义的注解(如@Resource)。

    cc317aaecf7d24b007c2da215254e177.png

    相同点

    @Autowired注解和@Resource注解均可以标注在字段上或者属性的setter方法上(下面的其中一种即可)。

    @Autowiredprivate UserService userService;@Resourceprivate OrderService orderService;private ProductService productService;private ConsignmentService consignmentService;@Autowiredpublic void setProductService(ProductService productService){      this.productService = productService;}@Resource(name="congsignmentService")public void setConsignmentService(ConsignmentService consignmentService){      this.consignmentService= consignmentService;}
    不同点● @Autowired注解默认按照类型(byType)注入。默认情况下,必须要求依赖对象必须存在,如果允许为null,则需要设置它的required属性为false。如果我们想按照名称注入,则可以结合@Qualifier注解一起使用。@Resource注解默认按照名称(byName)注入,同时也提通过类型注入,名称可以通过name属性进行指定。● 在Spring bean生命周期过程中,@Autowired注解通过后置处理器AutowiredAnnotationBeanPostProcessor解析;@Resource注解通过后置处理器CommonAnnontationBeanPostProcessor解析。@Resource注解装配顺序
      1. 如果同时指定了name和type,则从Spring上下文中找到唯一的bean进行装配,找不到则抛出异常。

      2. 如果指定了name,则从Spring上下文查找名称(id)匹配的bean进行装配,找不到则抛出异常。

      3. 如果指定了type,则从Spring上下文找到类型匹配的唯一bean进行装配,找不到或者找到多个都会抛出异常。

      4. 如果既没有指定name也没有指定type,则自动安装byName进行装配;如果没有匹配则回退为一个原始类型进行匹配,如果匹配则自动装配。

    推荐使用@Resource注解在字段上,这样就不用写setter方法,并且这个注解是属于J2EE的,减少了与Spring耦合,代码比较优雅。

    1d5aff65e9054503fc8d3315f8541b79.png

    END

    6b3781ea7c38fc76d53f998bd28808df.png

    扫码关注我们

    获得更多

    精彩资讯

    展开全文
  • 面试官:Spring框架中的@Autowired注解可以标注在哪些地方?小小白:@Autowired注解可以被标注在构造函数、属性、setter方法或配置方法上,用于实现依赖自动注入。面试官:有没有研究过@Autowired注解的实现原理?...

    daf6faa0fb0274881c6f12bf68647337.png

    面试官:Spring框架中的@Autowired注解可以标注在哪些地方?

    小小白:@Autowired注解可以被标注在构造函数、属性、setter方法或配置方法上,用于实现依赖自动注入。

    面试官:有没有研究过@Autowired注解的实现原理?

    小小白:看过它的实现源码。

    面试官:那你说一下@Autowired注解的工作原理?

    小小白:@Autowired注解的作用是由AutowiredAnnotationBeanPostProcessor实现的,查看该类的源码会发现它实现了MergedBeanDefinitionPostProcessor接口,进而实现了接口中的postProcessMergedBeanDefinition方法,@Autowired注解正是通过这个方法实现注入类型的预解析,将需要依赖注入的属性信息封装到InjectionMetadata类中,InjectionMetadata类中包含了哪些需要注入的元素及元素要注入到哪个目标类中,在Spring容器启动的过程中初始化单例bean的时候通过populateBean方法实现对属性的注入。

    public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
    
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        if (beanType != null) {
            InjectionMetadata metadata = this.findAutowiringMetadata(beanName, beanType, (PropertyValues)null);
            metadata.checkConfigMembers(beanDefinition);
        }
    }
    
    public class InjectionMetadata {
    	private static final Log logger = LogFactory.getLog(InjectionMetadata.class);
    	private final Class<?> targetClass;
    	private final Collection<InjectedElement> injectedElements;
    	private volatile Set<InjectedElement> checkedElements;

    面试官:AutowiredAnnotationBeanPostProcessor类的postProcessMergedBeanDefinition方法是在什么时候被调用的?

    小小白:Spring容器在启动的时候会执行AbstractApplicationContext类的refresh方法,在refresh方法执行的过程中先注册AutowiredAnnotationBeanPostProcessor,然后在对非延迟初始化的单例bean进行初始化时,会间接调用。具体实现细节分析如下。

    	public void refresh() throws BeansException, IllegalStateException {
    		synchronized (this.startupShutdownMonitor) {
    			// Prepare this context for refreshing.
    			prepareRefresh();
    
    			// Tell the subclass to refresh the internal bean factory.
    			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    			// Prepare the bean factory for use in this context.
    			prepareBeanFactory(beanFactory);
    
    			try {
    				// Allows post-processing of the bean factory in context subclasses.
    				postProcessBeanFactory(beanFactory);
    
    				// Invoke factory processors registered as beans in the context.
    				invokeBeanFactoryPostProcessors(beanFactory);
    
    				// Register bean processors that intercept bean creation.
    				// 重点看这里:在这里对AutowiredAnnotationBeanPostProcessor注册
    				registerBeanPostProcessors(beanFactory);
    
    				// Initialize message source for this context.
    				initMessageSource();
    
    				// Initialize event multicaster for this context.
    				initApplicationEventMulticaster();
    
    				// Initialize other special beans in specific context subclasses.
    				onRefresh();
    
    				// Check for listener beans and register them.
    				registerListeners();
    
    				// Instantiate all remaining (non-lazy-init) singletons.
    				// 重点看这里:对非延迟初始化的单例bean进行初始化
    				finishBeanFactoryInitialization(beanFactory);
    
    				// Last step: publish corresponding event.
    				finishRefresh();
    			}
    
    			catch (BeansException ex) {
    				if (logger.isWarnEnabled()) {
    					logger.warn("Exception encountered during context initialization - " +
    							"cancelling refresh attempt: " + ex);
    				}
    
    				// Destroy already created singletons to avoid dangling resources.
    				destroyBeans();
    
    				// Reset 'active' flag.
    				cancelRefresh(ex);
    
    				// Propagate exception to caller.
    				throw ex;
    			}
    
    			finally {
    				// Reset common introspection caches in Spring's core, since we
    				// might not ever need metadata for singleton beans anymore...
    				resetCommonCaches();
    			}
    		}
    	}

    refresh方法中registerBeanPostProcessors(beanFactory)完成了对AutowiredAnnotationBeanPostProcessor的注册,当执行finishBeanFactoryInitialization(beanFactory)方法对非延迟初始化的单例bean进行初始化时,会执行到AbstractAutowireCapableBeanFactory类的doCreateBean方法,在这个方法中有如下这么一段代码。

    synchronized (mbd.postProcessingLock) {
    	if (!mbd.postProcessed) {
    		try {
    			applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
    		}
    		catch (Throwable ex) {
    			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    					"Post-processing of merged bean definition failed", ex);
    		}
    		mbd.postProcessed = true;
    	}
    }

    在这段代码中会执行applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName),深入到这个applyMergedBeanDefinitionPostProcessors方法中。

    protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
    	for (BeanPostProcessor bp : getBeanPostProcessors()) {
    		if (bp instanceof MergedBeanDefinitionPostProcessor) {
    			MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
    			bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
    		}
    	}
    }

    可以看到,if的条件判断逻辑是否属于MergedBeanDefinitionPostProcessor,而AutowiredAnnotationBeanPostProcessor正好实现了MergedBeanDefinitionPostProcessor接口,所以在这里调用AutowiredAnnotationBeanPostProcessor类的postProcessMergedBeanDefinition方法。

    面试官:你在说一下注入的过程?

    小小白:使用AutowiredFieldElement实现对标注在属性上的注入,使用AutowiredMethodElement对标注在方法上的注入。注入过程:根据需要注入的元素的描述信息,按类型或名称查找需要的依赖值,如果依赖没有实例化先实例化依赖,然后使用反射进行赋值。

    面试官:@Resource或者@Autowired注解有什么区别?

    小小白:虽然@Resource和@Autowired都可以书写标注在属性或者该属性的setter方法之上,但是@Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入;@Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在如果允许为null,可以设置它required属性为false,如果想按照名称来注入,则需要结合@Qualifier一起使用;@Resource注解是由JDK提供,而@Autowired是由Spring提供。

    往期推荐:

    大厂都聊分布式系统,面试不知道分布式锁如何聊下去

    面试官:SpringBoot中关于日志工具的使用,我想问你几个常见问题

    面试被问为什么使用Spring Boot?答案好像没那么简单

    面试官:Spring框架内置了哪些可扩展接口,咱们一个一个聊
    Spring声明式事务处理的实现原理,来自面试官的穷追拷问
    Spring MVC相关面试题就是无底洞,反正我是怕了
    说实话,面试这么问Spring框架的问题,我快扛不住了
    没使用加号拼接字符串,面试官竟然问我为什么
    面试官一步一步的套路你,为什么SimpleDateFormat不是线程安全的
    都说ThreadLocal被面试官问烂了,可为什么面试官还是喜欢继续问
    Java注解是如何玩转的,面试官和我聊了半个小时
    如何去除代码中的多次if而引发的一连串面试问题
    String引发的提问,我差点跪了
    就写了一行代码,被问了这么多问题
    面试官:JVM对锁进行了优化,都优化了啥?
    synchronized连环问

    展开全文
  • ,还好我机智,灵机一动回了句:Spring 注解的工作流程倒还没有看到,但是我知道@Autowired注解的工作流程,后面不用说了一顿巴拉,面试官都连连点头。面试中要活用转移话题,要避免回答 ”不知道“,要引导面试官掉...

    ef3f61180d2046c879388be7b68f98a9.png

    面试中碰到面试官问:”Spring 注解是如果工作的?“,当前我一惊,完了这不触及到我的知识误区了吗?,还好我机智,灵机一动回了句:Spring 注解的工作流程倒还没有看到,但是我知道@Autowired注解的工作流程,后面不用说了一顿巴拉,面试官都连连点头。

    面试中要活用转移话题,要避免回答 ”不知道“,要引导面试官掉入你擅长的技术,然后才有机会教他作人。

    @Autowired 相关的类

    @Autowired 注解的主要功能就是完成自动注入,使用也非常简单(Spring都安排好了),但是要想知道 @Autowired 注解的内部现实,就需要看一下Spring源码了。接下来一步步的解剖 @Autowired 的实现原理,首先理一下与 @Autowired 注解相关的类,然后一步步的跟踪源码,直到理解 @Autowired 的原理。

    AutowiredAnnotationBeanPostProcessor 类

    AutowiredAnnotationBeanPostProcessor是实现 @Autowired 功能的主要类,它有一些方法是会用解析 @Autowired 注解并实现自动注入的功能,下面是它的继承图:

    e34552e7c58b2634414683e39addab31.png

    从上图可以发现 AutowiredAnnotationBeanPostProcessor 最上层是 BeanPostProcessor 是一个后处理器,当然除了后处理器外中间还有InstantiationAwareBeanPostProcessor和MergedBeanDefinitionPostProcessor:

    InstantiationAwareBeanPostProcessor 接口

    postProcessBeforeInstantiation方法

    在Bean实例化之前调用,可以返回一个Bean实例,默认返回null。

    @Nullabledefault Object postProcessBeforeInstantiation(Class<?> beanClass, String 
    beanName) throws BeansException {      return null;}

    postProcessAfterInstantiation方法

    在Bean创建完成后,设置属性之前调用。

    default boolean postProcessAfterInstantiation(Object bean, String 
    beanName) throws BeansException {      return true;}

    postProcessProperties方法

    @Nullable default PropertyValues postProcessProperties(PropertyValues pvs, Object 
    bean, String beanName)            throws BeansException {      return null;}

    Bean创建完后,设置属性之前调用

    先记住 InstantiationAwareBeanPostProcessor 接口,后面会跟踪调用它的地方,就很容易理解了。

    MergedBeanDefinitionPostProcessor

    MergedBeanDefinitionPostProcessor 也是一个继承 BeanPostProcessor 接口的后处理器,它的主要作用就是可以处理操作BeanDefinition对象,由于Bean的实例化是通过 BeanDefinition 的, 通过操作BeanDefinition ,这样可以使Bean的实例化时发生一些变化。

    MergedBeanDefinitionPostProcessor 只有两个方法

    postProcessMergedBeanDefinition方法

    void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, 
    Class<?> beanType, String beanName);

    Bean的BeanDefinition 被合并后调用此方法。

    resetBeanDefinition

    default void resetBeanDefinition(String beanName) {}

    当一个BeanDefinition被重置后调用 。

    AutowireCapableBeanFactory 接口

    AutowireCapableBeanFactory继承自BeanFactory,除了提供基础的Bean操作外,从接口的名字就可以推断出的它还有自动注入的能力。AutowireCapableBeanFactory 提供四种注入模型:

    • AUTOWIRE_NO: 没有显示的定义注入模型
    • AUTOWIRE_BY_NAME: 通过Bean名称注入
    • AUTOWIRE_BY_TYPE: 通过Bean的类型注入
    • AUTOWIRE_CONSTRUCTOR:通过Bean的构造方法注入

    AutowireCapableBeanFactory 接口有不少方法,但大部分都是跟自动注入的相关。@Autowired 的主要功能就是在Bean实例化后,为其设置属性,所以在 AutowireCapableBeanFactory 接口有一个createBean方法,用于创建Bean并设置Bean的属性:

    <T> T createBean(Class<T> beanClass) throws BeansException;

    createBean方法,它的调用时机是创建Bean的时候,稍后会说到它的调用时机。

    AbstractAutowireCapableBeanFactory

    4913296415f52bba589a7220e2447311.png

    AbstractAutowireCapableBeanFactory 继承 AbstractBeanFactory并实现了AutowireCapableBeanFactory接口,所以它也实现了AutowireCapableBeanFactory中的createBean方法。

    public <T> T createBean(Class<T> beanClass) throws BeansException {     
    
    // Use prototype bean definition, to avoid registering bean as dependent bean.      
    
    RootBeanDefinition bd = new RootBeanDefinition(beanClass);      
    bd.setScope(SCOPE_PROTOTYPE);     
    
    bd.allowCaching = ClassUtils.isCacheSafe(beanClass, getBeanClassLoader());      
    
    return (T) createBean(beanClass.getName(), bd, null);}

    Bean创建的生命周期

    通过了解Bean创建的生命周期,才可以将上面与 @Autowired 相关的类串起来,首先这里不会过多的介绍Bean的创建细节,只关注自动注入相关的代码。

    Bean的创建过程

    Spring中默认的Bean都是懒加载的,所以一个Bean的创建会从调用getBean方法开始,如果不考虑缓存、上层容器的情况,Bean的创建会经过以下方法:

    • getBean:BeanFactory的方法,获取Bean实例
    • doGetBean:获取Bean的实例,获取顺序依次为:单例池、父容器,如果从以上2种途径都没获取到Bean实例就会创建新的
    • createBean:创建 Bean,这里的createBean,跟上面介绍的是一回事
    • doCreateBean:创建Bean实例
    • populateBean:设置Bean属性

    以上流程中的getBean和doGetBean不多作说明了, 重点关注createBean前面提到AbstractAutowireCapableBeanFactory.createBean方法,所以说你在调用getBean方法获取Bean的实例时,如果这个Bean实例还没有被创建,那么createBean就会被调用。

    通过简单的说明Bean创建的生命周期,就能找到 @Autowired 注解实现的入口,接下来再继续跟踪createBean方法。

    收集注入元信息

    收集注入元信息的步骤的,其实就是调用AutowiredAnnotationBeanPostProcessor类方法来实现的。

    Bean 创建之前

    以下是createBean方法,在Bean创建之前调用postProcessBeforeInstantiation的地方。为是阅读方便省略了一些代码,大致的流程就是:

    • 首先调用 resolveBeforeInstantiation 方法,执行 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation方法
    • 如果postProcessBeforeInstantiation返回Bean实例那么直接返回这个实例,如果返回nul 继续调用doCreateBean
    @Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
          throws BeanCreationException {
     
       ...
    
       try {
          // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
          Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
          if (bean != null) {
             return bean;
          }
       }
       catch (Throwable ex) {
            ...
       }
       
         ...
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        ...
       
       ...
     }
       
     @Nullable
    protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
       Object bean = null;
       if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
          // Make sure bean class is actually resolved at this point.
          if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
             Class<?> targetType = determineTargetType(beanName, mbd);
             if (targetType != null) {
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                   bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
             }
          }
          mbd.beforeInstantiationResolved = (bean != null);
       }
       return bean;
    }

    这里 AutowiredAnnotationBeanPostProcessor 的 postProcessBeforeInstantiation 的方法会被调用,由于AutowiredAnnotationBeanPostProcessor 并没有重写这个方法,所以什么都不做。

    操作 BeanDefinition

    上面说过 postProcessBeforeInstantiation 方法返回 null 的话会继续执行doCreateBean方法:

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
          throws BeanCreationException {
    
    
       // Allow post-processors to modify the merged bean definition.
       synchronized (mbd.postProcessingLock) {
          if (!mbd.postProcessed) {
             try {
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
             }
             catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                      "Post-processing of merged bean definition failed", ex);
             }
             mbd.postProcessed = true;
          }
       }
    
      ...
     populateBean(beanName, mbd, instanceWrapper);
     ...

    在 doCreateBean 方法中,会调用调用applyMergedBeanDefinitionPostProcessors方法:

    protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
       for (BeanPostProcessor bp : getBeanPostProcessors()) {
          if (bp instanceof MergedBeanDefinitionPostProcessor) {
             MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
             bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
          }
       }

    MergedBeanDefinitionPostProcessor接口上面提到到的,AutowiredAnnotationBeanPostProcessor 实现了这个接口所以直接进入到 AutowiredAnnotationBeanPostProcessor 中的 postProcessMergedBeanDefinition方法:

    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
       InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
       metadata.checkConfigMembers(beanDefinition);
    }

    查找注入元数据

    接着继续进入到findAutowiringMetadata,findAutowiringMetadata 会调用buildAutowiringMetadata方法创建注入元数据,然后将元数据缓存到injectionMetadataCache属性中:

    private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
       // Fall back to class name as cache key, for backwards compatibility with custom callers.
       String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
       // Quick check on the concurrent map first, with minimal locking.
       InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
       if (InjectionMetadata.needsRefresh(metadata, clazz)) {
          synchronized (this.injectionMetadataCache) {
             metadata = this.injectionMetadataCache.get(cacheKey);
             if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                ...
                metadata = buildAutowiringMetadata(clazz);
                this.injectionMetadataCache.put(cacheKey, metadata);
             }
          }
       }
       return metadata;
    }

    创建注入元数据

    仔细查看buildAutowiringMetadata方法的实现,它会反射类的方法和属性,同时还会向上查找父类,然后生成InjectionMetadata。

    private InjectionMetadata buildAutowiringMetadata(final 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<>();
    
    			ReflectionUtils.doWithLocalFields(targetClass, field -> {
    				MergedAnnotation<?> ann = findAutowiredAnnotation(field);
    				if (ann != null) {
    					if (Modifier.isStatic(field.getModifiers())) {
    						if (logger.isInfoEnabled()) {
    							logger.info("Autowired annotation is not supported on static fields: " + field);
    						}
    						return;
    					}
    					boolean required = determineRequiredStatus(ann);
    					currElements.add(new AutowiredFieldElement(field, required));
    				}
    			});
    
    			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));
    				}
    			});
    
    			elements.addAll(0, currElements);
    			targetClass = targetClass.getSuperclass();
    		}
    		while (targetClass != null && targetClass != Object.class);
    
    		return InjectionMetadata.forElements(elements, clazz);
    	}

    小结

    收集注入元数据过程,首先调用AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition方法,然后调用findAutowiringMetadata方法查找元数据,如果找到相应类的注入元数据 ,就会调用buildAutowiringMetadata方法创建InjectionMetadata,最后将新创建的注入元数据保存在injectionMetadataCache缓存起来。

    设置Bean属性

    收信完注入元数据后,Bean的属性还是没有注入的,还需要将执行属性注入。还是在doCreateBean方法中,收集完注入元数据后,紧接着会调用populateBean:

    protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
       
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
    
    PropertyDescriptor[] filteredPds = null;
    if (hasInstAwareBpps) {
       if (pvs == null) {
          pvs = mbd.getPropertyValues();
       }
       for (BeanPostProcessor bp : getBeanPostProcessors()) {
          if (bp instanceof InstantiationAwareBeanPostProcessor) {
             InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
             PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
             if (pvsToUse == null) {
                if (filteredPds == null) {
                   filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                }
                pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                if (pvsToUse == null) {
                   return;
                }
             }
             pvs = pvsToUse;
          }
       }
       }
    }

    可以看到在populateBean中会调用InstantiationAwareBeanPostProcessor.postProcessProperties方法,由于已经知道 AutowiredAnnotationBeanPostProcessor 是实现 InstantiationAwareBeanPostProcessor 的,所以可以直接查看实现方法:

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

    postProcessProperties就很简单的,查找 InjectMetadata,然后调用 InjectMetadata.inject方法。到这里其实就已经知道@Autowire的实现机制了,接下来就是根据InjectionMetadata中的信息实现属性注入了。

    如果需要深入研究的话,有兴趣的还可以继续往下看。

    总结

    本文大致讲解了 @Autowire 相关的类与实现的机制,@Autowire 注解的实现主要是理解AutowiredAnnotationBeanPostProcessor类,还有收集注入元数据、设置注入属性的调用时机。

    通过查看AutowiredAnnotationBeanPostProcessor类源码,相信你也可以自定义注入功能。


    感谢大家看到最后,我是不务正业的程序汪,文章每天持续更新!欢迎大家指出我的文章的不足之处,也欢迎大家关注、点赞+转发。

    展开全文
  • 面试官:Spring框架中的@Autowired注解可以标注在哪些地方?小小白:@Autowired注解可以被标注在构造函数、属性、setter方法或配置方法上,用于实现依赖自动注入。面试官:有没有研究过@Autowired注解的实现原理?...
  • @Resource与@Autowired注解的区别

    万次阅读 多人点赞 2017-01-10 16:21:13
    同事:没错,但是现在都使用@Autowired。我:我研究一下。 在大学,学习J2EE实训时一直使用的是@Resource注解,后来我就养成习惯了。现在对这两个注解做一下解释: @Resource默认按照名称方式进行bean匹配,@A
  • spring Autowired注解

    2019-09-22 20:41:24
    每个bean在实例化的时候,都会照例检测本类中是否存在Autowired注解的Filed.对此类声明的所有Field一一对比.看是否是存在需要的注解,这个注解条件为Autowired注解是其中之一. 如果有满足条件的Field,那么就通过...
  • @Autowired注解

    2020-09-10 23:31:11
    @Autowired注解 @Autowired的用法和作用 这个注解就是spring可以自动帮你把bean里面引用的对象的setter/getter方法省略,它会自动帮你set/get。 <bean id="userDao" class="..."/> <bean id=...
  • 在我们写controller或者Service层的时候,需要注入很多的mapper接口或者另外的service接口,这时候就会写很多的@AutoWired注解,代码看起来很乱 lombok提供了一个注解: @RequiredArgsConstructor(onConstructor =...
  • 上一遍文章中有简单的介绍@Autowired注解的使用,没有查看的同学可以点击查看,但是那偏文章只介绍了@Autowired注解的一种使用方式,当然也是常用的方式就是@Autowired注解加在成员变量上,今天将介绍另外的几种使用...
  • @Autowired注解与@Resource注解的区别 Spring不但支持自己定义的@AutoWired注解,还支持JSR-250规范定义的几个注解。如:@Resource、@PostConstruct及@PreDestroy
  • 自定义@Autowired注解

    2021-04-18 08:50:46
    前言介绍 ...2.Autowired注解类 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @Inherited @Documented public @interface Autowired { } 3.UserController类 public class UserCo
  • @Autowired注解与@Resource注解的区别

    千次阅读 2020-07-30 11:00:14
    Spring不但支持自己定义的@Autowired注解,还支持由JSR-250规范定义的几个注解。如:@Resource、@PostConstruct及@PreDestroy。 @Resource和@Autowired注解都是用来实现依赖注入的。只是@AutoWried按byType自动注入...
  • Autowired注解闲谈

    2017-03-28 19:12:24
    早上看到一个朋友的个人空间说到自己面试被问及@autowired的实现。结果是卡壳了,回来之后觉得应该是反射之类的方式实现。个人感觉他说的也不能算错,不过不是我想看到的答案,自己...Autowired注解Autowired是个注解类
  • title: Spring框架——@Autowired注解用法详解 date: 2020-03-22 08:38:03 tags: Spring 框架 Spring 框架中的 @Autowired 注解 ​ 在使用注解进行 Spring 项目的开发时,我们经常会用到Autowired注解,它可以对类...
  • Spring @Autowired注解

    千次阅读 2015-07-27 23:20:19
    @Autowired注解提供更细粒度地控制在何处以及如何使用自动装配时应完成。 @Autowired注解可以用于自动装配的bean的setter方法​​就像@Required注解,构造函数,属性或具有任意名称和/或多个参数的方法。 @...
  • Resource注解和Autowired注解的区别

    千次阅读 2016-12-01 10:05:37
    Resource注解和Autowired注解的区别
  • Spring5:@Autowired注解、@Resource注解和@Service注解
  • 关于 @Autowired注解与@Resource注解 ** 1、@Autowired 由Spring提供,只按照byType注入。 2、@Resource 由J2EE提供,@Resource默认按byName自动注入,也提供按照byType 注入。 3、使用区别 a:@Autowired与@...
  • 下面小编就为大家带来一篇基于Spring@Autowired注解与自动装配详谈。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 手写Spring的Autowired注解 定义Autowired @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @Inherited @Documented public @interface Autowired { } 定义UserService public class UserService ...
  • Spring @Autowired注解使用@Autowired 自动装载1. Constructors 中使用2. 传统的setter方法中使用3. 任意方法上使用4. 注入一组特定类型的bean5. 结合`@Primary、@Qualifier`注入特定类型的bean6. 泛型注入 @...
  • IDEA使用@Autowired注解报红

    千次阅读 2019-08-19 10:11:25
    在使用IDEA工具时,使用@Autowired注解会报红,我们可以通过设置可以取消使用@Autowired注解时的提醒 File-settings-Inspections
  • Java中的@Resource注解和@Autowired注解的解析 我们经常会遇到用@Autowired注解注入对象是会出现weak warning的现象,而换成了@Resource注解就没有警告了。这引起了我的好奇:Spring属于第三方的,J2EE是Java自己的...
  • 使用@Autowired注解警告Field injection is not recommended

    万次阅读 多人点赞 2018-07-18 10:57:57
    在使用spring框架中的依赖注入注解@Autowired时,idea报了一个警告 大部分被警告的代码都是不严谨的地方,所以我深入了解了一下。 被警告的代码如下: @Autowired UserDao userDao; 警告内容是 Field ...
  • Spring中@Autowired注解、@Resource注解的区别 Spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource、@PostConstruct以及@PreDestroy。  @Resource的作用相当...
  • Spring5:@Autowired注解、@Resource注解和@Service注解 作者文章不错 https://www.cnblogs.com/xrq730/p/5313412.html
  • @Resource注解和@Autowired注解的区别

    千次阅读 2018-07-23 20:34:52
    @Resource注解(javax.annotation.Resource;...@Autowired注解(org.springframework.beans.factory.annotation.Autowired)是spring的注解;@Autowired注解默认按照类型方式进行bean装配 Spring属于第三方...
  • 在同一个controller中使用多个service时,每个service都需要引入@Autowired注解 @Autowired private ShoppingCartService shoppingCartService = null; @Autowired private BookService bookService = null;

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 11,231
精华内容 4,492
关键字:

autowired注解