Spring AOP(Aspect Orient Programming),AOP翻译过来就是面向切面编程,它体现的是一种编程思想,是对面向对象编程(OOP)的一种补充。
在实际业务开发过程中,有一些代码,跟业务没有任何关系,但在很多地方又会用到,比如:记录日志、计算执行时间、事务、权限验证等等,这些代码跟我们实际业务没有一丁点关系,但在许多的地方又会用到,我们传统的方式,肯定是通过复制粘贴把它粘进需要用到的地方,但这样做,会对原本的业务代码块造成很高侵入性,使代码的阅读性、可维护性变得很糟糕,所以就延伸出来了AOP的概念,它不是针对于某个编程语言、某段代码、而是体现了一种编程思想,通过切面的方式将非业务代码切入到核心业务处理流程中,减少对业务代码的修改,降低对业务代码的侵入程度。
Spring作为一个Bean对象的管理框架,提供了AOP功能集成的扩展接口(比如:事务)。
AOP是借助了动态代理的实现机制,通过为需要被切入的对象生成动态代理的方式来实现的。动态代理相关原理请参考笔者另一篇博客———设计模式——动态代理
AOP用到的一些专业术语
AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
可以插入增强处理的连接点。
切面是通知和切点的结合。
引入允许我们向现有的类添加新的方法或者属性。
将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。
在Spring对Bean对象的创建过程中,会将已实例化但尚未初始化的 Bean对象(半成品),最先放入到三级缓存(singletonFactories)中,而在放入的时候,并不是放入的一个实例对象那么简单,它是将获取这个半成品的工厂方法给放入了三级缓存中,然后再对这个半成品进行属性填充、初始化等操作,这里也是解决循环依赖的核心所在,在后续代码执行中,就可以通过beanName在三级缓存中,获取到这个ObjectFactory对象,通过调用ObjectFactory的getObject方法,获取之前创建的半成品。
而对于AOP对象的动态代理对象的创建,也就是在这个从三级缓存(半成品) 放入 二级缓存(成品的动态代理)过程中的进行处理的。
以下doCreateBean方法里省略了部分代码
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException{ ... // 判断当前bean是否需要提前曝光:单例&允许循环依赖&当前bean正在创建中,检测循环依赖 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isTraceEnabled()) { logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } // 为避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } ...
allowCircularReferences这个值默认等于true。以上代码调用了addSingletonFactory方法,实际上它是向三级缓存中添加了一个lambd表达式
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); // 使用singletonObjects进行加锁,保证线程安全 synchronized (this.singletonObjects) { // 如果单例对象的高速缓存【beam名称-bean实例】没有beanName的对象 if (!this.singletonObjects.containsKey(beanName)) { // 将beanName,singletonFactory放到单例工厂的缓存【bean名称 - ObjectFactory】 this.singletonFactories.put(beanName, singletonFactory); // 从早期单例对象的高速缓存【bean名称-bean实例】 移除beanName的相关缓存对象 this.earlySingletonObjects.remove(beanName); // 将beanName添加已注册的单例集中 this.registeredSingletons.add(beanName); } } }
lambd表达式里面的方法,getEarlyBeanReference(beanName, mbd, bean)方法源码
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { // 默认最终公开的对象是bean,通过createBeanInstance创建出来的普通对象 Object exposedObject = bean; // mbd的systhetic属性:设置此bean定义是否是"synthetic",一般是指只有AOP相关的pointCut配置或者Advice配置才会将 synthetic设置为true // 如果mdb不是synthetic且此工厂拥有InstantiationAwareBeanPostProcessor if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { // 遍历工厂内的所有后处理器 for (BeanPostProcessor bp : getBeanPostProcessors()) { // 如果bp是SmartInstantiationAwareBeanPostProcessor实例 if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; // 让exposedObject经过每个SmartInstantiationAwareBeanPostProcessor的包装 exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName); } } } // 返回最终经过层次包装后的对象 return exposedObject; }
三级缓存中添加的是一个获取对象的lambd表达式,所以这个表达式只是添加进去了,并不会立刻运行,以上就是lambd表达式里面的内容
在lambd表达式里面,我们看到SmartInstantiationAwareBeanPostProcessor这样的一个接口,它属性BPP。
对于每个Bean对象都会遍历BPP,如果是BPP是SmartInstantiationAwareBeanPostProcessor的实现类,就会运行它的getEarlyBeanReference(exposedObject, beanName)方法。
而对于开启了AOP注解(@EnableAspectJAutoProxy)功能的项目,会添加一个AnnotationAwareAspectJAutoProxyCreator,它就属性SmartInstantiationAwareBeanPostProcessor(BPP)
看到这里,大家就应该明白了,AOP功能也是通过对BPP的扩展来实现的。
AnnotationAwareAspectJAutoProxyCreator继承了父类AbstractAutoProxyCreator中的getEarlyBeanReference方法
/** * 放到集合中,然后判断要不要包装,其实就是在循环依赖注入属性的时候如果有AOP代理的话,也会进行代理,然后返回 * @param bean the raw bean instance * @param beanName the name of the bean * @return */ @Override public Object getEarlyBeanReference(Object bean, String beanName) { Object cacheKey = getCacheKey(bean.getClass(), beanName); this.earlyProxyReferences.put(cacheKey, bean); return wrapIfNecessary(bean, beanName, cacheKey); }
核心代码wrapIfNecessary(bean, beanName, cacheKey),到此,我们大致明白了,AOP的基本处理流程了(其实因为AnnotationAwareAspectJAutoProxyCreator属于BPP,在执行BPP的后置处理器有时候也有机会执行wrapIfNecessary方法,并返回代理对象)
/** * 先判断是否已经处理过,是否需要跳过,跳过的话直接就放进advisedBeans里,表示不进行代理,如果这个bean处理过了,获取通知拦截器,然后开始进行代理 * * Wrap the given bean if necessary, i.e. if it is eligible for being proxied. * @param bean the raw bean instance * @param beanName the name of the bean * @param cacheKey the cache key for metadata access * @return a proxy wrapping the bean, or the raw bean instance as-is */ protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // 如果已经处理过,直接返回 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } // 这里advisedBeans缓存了已经进行了代理的bean,如果缓存中存在,则可以直接返回 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } // 这里isInfrastructureClass()用于判断当前bean是否为Spring系统自带的bean,自带的bean是 // 不用进行代理的;shouldSkip()则用于判断当前bean是否应该被略过 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { // 对当前bean进行缓存 this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. // 获取当前bean的Advices和Advisors Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); // 对当前bean的代理状态进行缓存 if (specificInterceptors != DO_NOT_PROXY) { // 对当前bean的代理状态进行缓存 this.advisedBeans.put(cacheKey, Boolean.TRUE); // 根据获取到的Advices和Advisors为当前bean生成代理对象 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); // 缓存生成的代理bean的类型,并且返回生成的代理bean this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
Spring AOP生成代理类时JDK代理和CGLIB代理的选择
/** * 真正的创建代理,判断一些列条件,有自定义的接口的就会创建jdk代理,否则就是cglib * @param config the AOP configuration in the form of an * AdvisedSupport object * @return * @throws AopConfigException */ @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { // 这段代码用来判断选择哪种创建代理对象的方式 // config.isOptimize() 是否对代理类的生成使用策略优化 其作用是和isProxyTargetClass是一样的 默认为false // config.isProxyTargetClass() 是否使用Cglib的方式创建代理对象 默认为false // hasNoUserSuppliedProxyInterfaces目标类是否有接口存在 且只有一个接口的时候接口类型不是SpringProxy类型 if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { // 上面的三个方法有一个为true的话,则进入到这里 // 从AdvisedSupport中获取目标类 类对象 Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } // 判断目标类是否是接口 如果目标类是接口的话,则还是使用JDK的方式生成代理对象 // 如果目标类是Proxy类型 则还是使用JDK的方式生成代理对象 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } // 配置了使用Cglib进行动态代理或者目标类没有接口,那么使用Cglib的方式创建代理对象 return new ObjenesisCglibAopProxy(config); } else { // 使用JDK的提供的代理方式生成代理对象 return new JdkDynamicAopProxy(config); } }
Spring AOP生成动态代理大致流程如下
两种代理方式执行逻辑
AOP代理方式有两种:JDK代理 和 CGLIB代理
JdkDynamicAopProxy类是实现了反射中的InvocationHandler接口
所以调用过程中的核心执行方法在invoke方法中
invoke方法中核心代码块
// We need to create a method invocation... // 将拦截器封装在ReflectiveMethodInvocation,以便于使用其proceed进行处理 MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. // 执行拦截器链 retVal = invocation.proceed();
看得出来,它的执行是交给一个MethodInvocation去执行的,而ReflectiveMethodInvocation是一个执行器链,里面根据我们的配置有可能包含了以下五种通知
采用责任链模式对自定义配置的五种通知进行依次调用