前文《spring Aop前传》讲解了Aop编程范式的来历与工作原理,接下来将会介绍spring Aop作为一个aop的实现。在介绍spring Aop底层工作方式之前,我们抛开spring Aop真正实现,基于当前对spring的认识做一个大胆的假设,在ioc容器中,所有的对象都是bean,spring aop要做的就是将公共模块调用填充到制定bean里面,那么spring aop是在bean已经初始化完成,直接在bean中添加公共模块调用呢?还是依照bean的类型生成代理对象,然后代理对象的对应接口里面调用公共模块和bean对象的对应方法呢?第一种假设应该不太可能,因为bean实例化之后,映射的是一个内存块存放指令;那么就是使用第二种方式,首先使用字节码技术对bean的具体实现生成代理(生成的java字节码加载进jvm初始化后),然后在要增强的类型对应接口增加公共模块和bean对应方法调用。那么带着假设和疑问一起探索spring aop底层实现。
spring aop相关的元数据(集中化的调用位置信息与公共模块信息等)与其他spring应用元数据一样,可使用两种方式进行配置——基于xml和java注解,这两种元数据存储方式各有利弊,官方都说不清最优方案是哪个,xml可以将配置元数据集中在一个或几个文件,而annotation是偏向分散的,但是不需要了解和学习xml相关知识,它是java技术一部分,这章节不是讨论元数据存储与读取方案优劣的,所以元数据处理就暂时打住。这里的元数据以xml存储为例进行探讨spring aop底层工作流程。spring框架在初始化的时候第一个步骤就是读取元数据,第二步就是将读取到的元数据解析成spring框架抽象数据表示,在spring框架中,核心数据抽象表示是beanDefinition,主要是因为面向对象程序是有类型的实例对象组成的,一个beanDefintion就是一个对象的定义。spring aop主元数据配置也将会被解析成beanDefinition,但spring aop定义的bean不是普通的bean,它是一个实现BeanPostProcessor接口的AspectJAwareAdvisorAutoProxyCreator实现。BeanPostProcessor是ioc容器用于处理bean的回调接口,通过这个回调接口你可以自定义bean的特性,spring aop正正是利用这一个接口的postProcessAfterInitialization回调将已经注入依赖的bean包装到使用Cglib生成的代理里面去的。spring框架初始化的第三步是将spring aop定义注册到ioc容器里面去,这部分的定义将会将实例化advisor注册到bean postprocessor,以备ioc容器实例化并将依赖注入bean之后调用postProcessor,postProcessor会利用postProcessor里面的advisor的pointcut Expression,检查是否属于aop横切的范围。如果在spring aop横切范围,那么调用createProxy方法,参数包括已经初始化的bean,这个方法将会创建ProxyFactory实例,ProxyFactory实例对于接口使用java代理(默认,不设置所有使用Cglib代理),对于类使用Cglib的Enhancer生成代理。第四步,ioc容器将 bean postProcessor返回的包装bean(实则cglib根据类生成的代理对象)与beanName注册到ioc容器去,最终开发者拿到的bean通过beanName从ioc容器拿到的bean就是已经处理过的代理对象了。
最后由于spring aop与spring ioc处理过程紧密相连,附上spring ioc初始化过程、spring aop实现过程时序图,并加以简单解释。
图1显示的是spring ioc容器初始化的关键步骤):
1)refresh方法是初始化ioc容器的入口。2)refreshBeanFactory方法用于加载、解析和注册应用元数据到ioc容器。3)prepareBeanFactory方法配置工程饿标准上下文特性,例如classLoader和postprocessor。4)postProcessBeanFactory注册request/session scope。5)invokeBeanFactoryPostProcessors实例化并调用所有注册的BeanFactoryPostProcessor。6)registerBeanPostProcessors实例化并调用所有BeanPostProcessor。7)initApplicationEventMulticaster初始化ApplicationEventMulticaster。8)registerListeners添加实现AppicationListener的bean为listener。9)finishBeanFactoryInitialization完成当前context的bean factory,初始化所有singleton bean,这一步是集中实例化bean的统一入口。10)finishRefresh完成更新context,调用LifecycleProcessor的onRefresh方法,并发布ContextRefreshedEvent事件。从上面的步骤中,可以看出需要先初始化bean post processor(也是初始化成bean),然后才进行singleton 的bean的实例化,这是由于bean post processor是实例化bean的回调接口。
图2显示的是singleton 的bean的初始化过程,主要有几个重要的方法,首先是getBean方法,这个方法是ioc容器对外提供的统一获取bean接口,该接口会先从已经实例化里面获取,存在就不再实例化bean,不存在就获取beanDefinition进行实例化也依赖注入;其次是populateBean方法,这个方法是进行依赖注入的,在进行依赖注入的时候调用getBean方法获取依赖,依赖没有初始化并注册的就进行初始化,它会调用applyPropertyValues方法设置成员域的值(依赖);最后就是aop的处理入口——initializeBean,到了这一步已经将bean实例化并将依赖注入进行,这个方法将会调用applyBeanPostProcessorsAfterInitialization方法,它将会遍历ioc容器的BeanPost Processor,其中就有我们的AspectJAwareAdvisorAutoProxyCreator,这个BeanPostProcessor将会将已经检查初始化的bean是否在定义好的pointcut范围,在的话就会以初始化好的bean为targetSource生成代理对象,也就是说initializeBean方法返回的是一个包装bean,然后将这个包装bean与beanName注册到ioc容器上面去,这样使用beanName获取的bean就是代理对象了。
图3是spring aop创建代理的过程,对于类,底层使用cglib来创建代理。