前言
前面系列文章分析了一把SpringIoc的源码,是不是云里雾里,感觉并没有跟实际开发搭上半毛钱关系?看了一遍下来,对我的提升在哪?意义何在?如果没点收获,那浪费时间来看这个作甚,玩玩游戏不香?
这段玩笑话可不是真的玩笑,提升需要自己去把握,意义也需要自己去挖掘。纸上得来终觉浅,绝知此事要躬行。最好是跟着代码调试一遍才会留下自己的印象,这过程收获的会比你想象中的要多。看山是山,看水是水。看山不是山,看水不是水。看山还是山,看水还是水。
话不多说,既然这里是讲解
Autowired的原理,那么这篇文章就会暂时先摒弃本系列文章开始所使用的xml配置方式,投入到注解驱动的怀抱。这两者对比而言,注解模式已经开始走向了自动装配,后续的SpringBoot更是彻底走上了自动装配这条路。在正式分析之前,先来简单说一下传统的装配和自动装配的区别。
传统装配:配置量大,配置复杂,需要手动维护的地方多。
自动装配:只需要简单配置,不需要维护大量的配置,Spring会根据你现有的要求提前给你配置好需要的东西,省略了很多手动的维护。
那废话少说,下面搞个例子分析一下吧。
代码样例
例子很简单,建两个Service,利用
Autowired给其中一个注入,启动容器,查看是否能够成功注入。先整个UserService,这个类只有一个sayHi()方法。
/***
authorCodegitz*date/6/1**/ComponentpublicclassUserService{ publicvoidsayHi(Stringname){ System.out.println("hi"+name); }}再新建个ManagerService,前面的UserService会注入到这里,然后greet()方法会调用UserService#sayHi()方法。
/***
authorCodegitz*date/6/1**/ComponentpublicclassManagerService{ Autowired privateUserServiceuserService; publicvoidgreet(Stringname){ userService.sayHi(name); }}万事俱备,只欠东风,搞个启动类AutowiredApplication,看是否能够够实现注入。
/***
authorCodegitz*date/6/:19**/publicclassAutowiredApplication{ publicstaticvoidmain(String[]args){ AnnotationConfigApplicationContextapplicationContext=newAnnotationConfigApplicationContext("io.codegitz.inject"); ManagerServicemanagerService=(ManagerService)applicationContext.getBean("managerService"); managerService.greet("codegitz"); }}启动之后可以看到注入成功。
运行结束查看输出,符合逾期。
上面就是一个简单的注入例子,日常的业务开发是不是经常这样写,终于看到点跟业务相关的逻辑,那接下来就分析一下它的原理。
源码分析
这篇文章主要是展示一个过程,所以debug展示的图片较多
这里就不遮遮掩掩了,实现
Autowired注解功能的是一个后置处理器AutowiredAnnotationBeanPostProcessor,这个处理器的postProcessMergedBeanDefinition()方法会对标注了Autowired进行预处理,然后调用postProcessProperties()进行注入,这里分两步,预处理和真正注入,这个处理器是在什么时候执行的呢?可以参考文章SpringIoc源码分析系列--Bean实例化过程(二)里面MergedBeanDefinitionPostProcessor的应用那一节。预处理
我们先看预处理,直接定位到这里的实现代码位置,在AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors()方法里。调试的时候加上条件,这样一步到位节省很多时间。
跟进方法,这里也一样,加上条件bdpinstanceofAutowiredAnnotationBeanPostProcessor,聚焦目标一步到位。
进入postProcessMergedBeanDefinition()方法,显然这里的实现是AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition()里。预处理方法postProcessMergedBeanDefinition()会比真正的注入方法postProcessProperties()先执行,因此调用postProcessProperties()时都是直接拿缓存。
可以看到这里会先调用findAutowiringMetadata()方法,findAutowiringMetadata()方法会找出一个bean加了
Autowired注解的字段(包括父类的),并且该方法做了缓存,这个方法的核心逻辑就是先从缓存中获取已经解析好的注入点信息,很明显,在原型情况下才会使用缓存,接下来创建注入点的核心逻辑在buildAutowiringMetadata()方法中。跟进findAutowiringMetadata()方法,可以看到这里第一次进来是没有缓存的,这里会采用一个双重校验的方式去解决线程安全问题,接下来就是真正创建注入点。
跟进buildAutowiringMetadata()方法,这个方法将
Autowired注解标注的方法以及字段封装成InjectionMetadata在后续阶段会调用InjectionMetadata#inject()方法进行注入。先贴一下这个方法的代码,可以看到这里会分别去处理属性和方法上面的注解,我们这里只是使用了属性的注入,因此我们