关于spring:不多bbSpringAOP源码解析切就完事了

2次阅读

共计 10348 个字符,预计需要花费 26 分钟才能阅读完成。

一、AOP、SpringAOP、AspectJ 的区别

AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编程,通过预编译形式和运行期间动静代理实现程序性能的对立保护的一种技术。利用 AOP 能够对业务逻辑的各个局部进行隔离,从而使得业务逻辑各局部之间的耦合度升高,进步程序的可重用性,同时进步了开发的效率。

文有文的,没用过的确很懵,然而用过之后,不说清晰,起码有点意思了。

Spring AOP:

它基于动静代理来实现。默认的,如果应用接口的,用 JDK 提供的动静代理实现,如果没有接口,应用 CGLIB 实现。大家肯定要明确背地的意思,包含什么时候会不必 JDK 提供的动静代理,而用 CGLIB 实现。Spring 3.2 当前,spring-core 间接就把 CGLIB 和 ASM 的源码包含进来了,这也是为什么咱们不须要显式引入这两个依赖 Spring 的 IOC 容器和 AOP 都很重要,Spring AOP 须要依赖于 IOC 容器来治理。如果你是 web 开发者,有些时候,你可能须要的是一个 Filter 或一个 Interceptor,而不肯定是 AOP。Spring AOP 只能作用于 Spring 容器中的 Bean,它是应用纯正的 Java 代码实现的,只能作用于 bean 的办法。Spring 提供了 AspectJ 的反对,前面咱们会独自介绍怎么应用,一般来说咱们用纯的 Spring AOP 就够了。很多人会比照 Spring AOP 和 AspectJ 的性能,Spring AOP 是基于代理实现的,在容器启动的时候须要生成代理实例,在办法调用上也会减少栈的深度,使得 Spring AOP 的性能不如 AspectJ 那么好。

AspectJ:

AspectJ 出身也是名门,来自于 Eclipse 基金会,link:https://www.eclipse.org/aspectj

属于动态植入,它是通过批改代码来实现的,它的植入机会能够是:

Compile-time weaving:编译期织入,如类 A 应用 AspectJ 增加了一个属性,类 B 援用了它,这个场景就须要编译器的时候就进行植入,否则没法编译类 B。Post-compile weaving:也就是曾经生成了 .class 文件,或曾经达成 jar 包了,这种状况咱们须要加强解决的话,就要用到编译后织入。Load-time weaving:指的是在加载类的时候进行织入,要实现这个期间的织入,有几种常见的办法。1、自定义类加载器来干这个,这个应该是最容易想到的方法,在被织入类加载到 JVM 前去对它进行加载,这样就能够在加载的时候定义行为了。2、在 JVM 启动的时候指定 AspectJ 提供的 agent:-javaagent:xxx/xxx/aspectjweaver.jar。

AspectJ 无能很多 Spring AOP 干不了的事件,它是 AOP 编程的齐全解决方案。Spring AOP 致力于解决的是企业级开发中最广泛的 AOP 需要(办法织入),而不是力求成为一个像 AspectJ 一样的 AOP 编程齐全解决方案。

因为 AspectJ 在理论代码运行前实现了植入,所以大家会说它生成的类是没有额定运行时开销的。

二、AOP 要害术语

  • 切面(Aspect):也就是咱们定义的专一于提供辅助性能的模块,比方平安治理,日志信息等。
  • 连接点(JoinPoint):切面代码能够通过连接点切入到失常业务之中,图中每个办法的每个点都是连接点。
  • 切入点(PointCut):一个切面不须要告诉所有的连接点,而在连接点的根底之上减少切入的规定,抉择须要加强的点,最终真正告诉的点就是切入点。
  • 告诉办法(Advice):就是切面须要执行的工作,次要有五种告诉:before,after,afterReturning,afterThrowing,around。
  • 织入(Weaving):将切面利用到指标对象并创立代理对象的过程,SpringAOP 抉择在指标对象的运行期动态创建代理对
  • 引入(introduction):在不批改代码的前提下,引入能够在运行期为类动静地增加办法或字段。

三、告诉的五种类型

  • 前置告诉 Before:指标办法调用之前执行的告诉。
  • 后置告诉 After:指标办法实现之后,无论如何都会执行的告诉。
  • 返回告诉 AfterReturning:指标办法胜利之后调用的告诉。
  • 异样告诉 AfterThrowing:指标办法抛出异样之后调用的告诉。
  • 盘绕告诉 Around:能够看作后面四种告诉的综合。

四、切入点表达式

下面提到:连接点减少切入规定就相当于定义了切入点,当然切入点表达式分为两种:within 和 execution,这里次要学习 execution 表达式。

  • 写法:execution(拜访修饰符 返回值 包名. 包名……类名. 办法名(参数列表))
  • 例:execution(public void com.smday.service.impl.AccountServiceImpl.saveAccount())
  • 拜访修饰符能够省略,返回值能够应用通配符 * 匹配。
  • 包名也能够应用 匹配,数量代表包的层级,以后包能够应用.. 标识,例如 *..AccountServiceImpl.saveAccount()
  • 类名和办法名也都能够应用 匹配: ...*()
  • 参数列表应用.. 能够标识有无参数均可,且参数可为任意类型。

全通配写法: .(…)

通常状况下,切入点该当设置在业务层实现类下的所有办法: com.smday.service.impl..*(..)。

五、AOP 利用场景

  • 记录日志
  • 监控性能
  • 权限管制
  • 事务管理

六、AOP 源码剖析

SpringBean 的生命周期

写了好多篇文章,每次都要来回顾一下 SpringBean 的生命周期,可见它真的非常重要。

  • Spring 的残缺生命周期。
  • Spring 解决循环依赖,对实例化之后,初始化之前动了手脚。

Spring 的 Aop 又是在哪实现的对指标对象的代理呢?咱们大略也可能想到,其实就是在执行回调的时候。依照常规,先温习一下,从 getBean 开始到返回 Bean 经验了什么:

回顾完 SpringBean 的创立流程之后,咱们以注解形式 @EnableAspectJAutoProxy 配置 Aop 开启 @Aspectj 为例,进行一波 AOP 的流程总结:

AOP 的流程总结

通过源码能够发现,其实是通过 @EnableAspectJAutoProxy 注解注入了一个 AnnotationAwareAspectJAutoProxyCreator,但这个类中其实并没有重写 postProcessAfterInitialization(),最终实现其实是在 AbstractAutoProxyCreator 中。

具体干的事件,我曾经通过一张图总结进去了,如果想要理解更加具体的信息,无妨关上源码,能够看的更加清晰一些。

AnnotationAwareAspectJAutoProxyCreator 的注册

首先是对 AnnotationAwareAspectJAutoProxyCreator 的注册环节:【在此不作赘述】

class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {
    @Override
    @Nullable
     // 1. 注册 proxy creator
 public BeanDefinition parse(Element element, ParserContext parserContext) {AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
 extendBeanDefinition(element, parserContext);
 return null;
 }
}

applyBeanPostProcessorsAfterInitialization 入口

AbstractAutowireCapableBeanFactory.java

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    // 如果 bean 实现了 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 接口, 回调
 invokeAwareMethods(beanName, bean);
 Object wrappedBean = bean;
 //aop 在 init-method 之前并没有进行操作, 目前还是原来那个对象
 if (mbd == null || !mbd.isSynthetic()) {
 //BeanPostProcessor 的 postProcessBeforeInitialization 回调
 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
 }
 // 解决 bean 中定义的 init-method 或 bean 实现了 InitializingBean , 调用 afterPropertiesSet() 办法
 invokeInitMethods(beanName, wrappedBean, mbd);
 if (mbd == null || !mbd.isSynthetic()) {
 //BeanPostProcessor 的 postProcessAfterInitialization 回调 留神这里!wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
 }
 return wrappedBean;
}
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
    throws BeansException {    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        //AnnotationAwareAspectJAutoProxyCreator
 Object current = processor.postProcessAfterInitialization(result, beanName);
 if (current == null) {return result;}
 result = current;
 }
 return result;// 返回 [可能代理后的] 后果
}

AbstractAutoProxyCreator 的次要办法

//SpringAop 在 IOC 容器创立 bean 实例的最初对 bean 进行解决, 进行代理加强, AbstractAutoProxyCreato    
@Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);        if (this.earlyProxyReferences.remove(cacheKey) != bean) {return wrapIfNecessary(bean, beanName, cacheKey);// 这个办法将返回代理类
        }    }    return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 返回匹配以后 bean 的所有的 advisor, advice, interceptor
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 在这里创立代理
        Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

createProxy 过程

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
    // 创立 ProxyFactory 实例
 ProxyFactory proxyFactory = new ProxyFactory();
 proxyFactory.copyFrom(this);
 // 在 schema-based 配置形式里, 能够将 proxy-target-class="true", 这样不论有没有接口都应用 cglib
 if (!proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) {proxyFactory.setProxyTargetClass(true);
 }
 else {evaluateProxyInterfaces(beanClass, proxyFactory);
 }
 }
 // 返回以后 bean 的 advisors 数组
 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
 proxyFactory.addAdvisors(advisors); // 设置 advisors 数组
 proxyFactory.setTargetSource(targetSource);//targetSource 携带了实在实现的信息
 customizeProxyFactory(proxyFactory);
 proxyFactory.setFrozen(this.freezeProxy);
 if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);
 }
 return proxyFactory.getProxy(getProxyClassLoader());//getProxy(getProxyClassLoader())这一步创立代理
}

JDK 动静代理和 CGLIB 动静代理何时应用

这一步产生分歧的中央在 ProxyFactory 的 getProxy 办法,在 getProxy 之前,首先须要执行 createAopProxy,而 createAopProxy 办法又被这个 AopProxyFactory 调用:

protected final synchronized AopProxy createAopProxy() {if (!this.active) {activate();    }    // 创立 AopProxy 之前, 须要一个 AopProxyFactory
 return getAopProxyFactory().createAopProxy(this);
}
// ProxyCreatorSupport
// 这个 aopProxyFactory 用于创立 aopProxy, 之后能够用 aopProxy.getProxy(classLoader)创立代理
public ProxyCreatorSupport() {this.aopProxyFactory = new DefaultAopProxyFactory();
}

也就是最初会走到 DefaultAopProxyFactory 中

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (!IN_NATIVE_IMAGE &&
        (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {throw new AopConfigException();        }        // 如果要代理的类自身就是接口, 应用 JDK 动静代理        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);
        }        //jdk 动静代理基于接口, 只有接口中的办法才会被加强, cglib 基于类继承, 如果办法应用了 final 或者 private 润饰, 也不能加强        return new ObjenesisCglibAopProxy(config);
    }    else {// 如果有接口,会跑到这个分支        return new JdkDynamicAopProxy(config);
    }}

总结:

  • 如果被代理的指标实现了一个或多个自定义的接口,那么就会应用 JDK 动静代理。
  • 如果没有实现任何接口,则应用 CGLIB 实现代理。
  • 如果设置 proxy-target-class=true 或 <property name=”proxyTargetClass” value=”true”/> 则不论有没有实现接口都会应用 CGLIB。

七、JDK 动静代理的实现

最终的最终,都会走到真正创立代理对象的流程上:

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
    // 获取代理接口
 Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
 // 查找代理指标的接口是否定义 equals 和 hashcode 办法
 findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
 // 应用 jdk 动静代理创立代理对象
 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

第一个参数:classLoader。

第二个参数:实现的接口。

第三个参数:InvocationHandler 实例。

而自身 JdkDynamicAopProxy 本就实现了 InvocationHandler,因而传入 this。至此,当调用被代理类的办法的时候,都会最终调用代理类实现的 invoke 办法,在这个办法中定义横切的逻辑。

public interface InvocationHandler {public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;}
  • proxy:代理对象的援用。
  • method:以后执行的办法。
  • args:以后执行办法所需的参数。
  • return:和被代理对象有雷同的返回值。
@Override
@Nullablepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {     // 当生成的代理类对外提供服务的时候, 都会导入到这个 invoke 办法中
    Object oldProxy = null;    boolean setProxyContext = false;
        TargetSource targetSource = this.advised.targetSource;    Object target = null;    try {if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            // 对 equals 办法的代理
            return equals(args[0]);
        }        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {// 对 hashCode()办法的代理
            return hashCode();}        //...
 Object retVal;
 // 如果设置了 exposeProxy, 将 proxy 放入 ThreadLocal 中
 if (this.advised.exposeProxy) {oldProxy = AopContext.setCurrentProxy(proxy);
 setProxyContext = true;
 }
 // Get as late as possible to minimize the time we "own" the target,
 // in case it comes from a pool.
 target = targetSource.getTarget();
 Class<?> targetClass = (target != null ? target.getClass() : null);
 // 获取指标办法的拦挡链,蕴含所有要执行的 advice
 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
 // 检查一下这个链上是不是有 advice,如果没有的话,能够跳过创立 MethodInvocation
 if (chain.isEmpty()) { //chain 如果是空的, 示意不须要被加强,间接调用指标办法
 Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
 }
 else {
 // 如果 chain 里有 advice 执行办法, 失去返回值
 MethodInvocation invocation =
 new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
 // 沿着拦截器链,执行告诉
 retVal = invocation.proceed();}
 // 对返回值的解决
 Class<?> returnType = method.getReturnType();
 if (retVal != null && retVal == target &&
 returnType != Object.class && returnType.isInstance(proxy) &&
 !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {retVal = proxy;}
 else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {throw new AopInvocationException();
 }
 return retVal;
 }
 finally {if (target != null && !targetSource.isStatic()) {
 // 开释指标对象
 targetSource.releaseTarget(target);
 }
 if (setProxyContext) {
 // 存储代理对象
 AopContext.setCurrentProxy(oldProxy);
 }
 }
}

八、总结

以 @AspectJ 注解形式为例

  • 首先,根据 <aop:aspectj-autoproxy> 或 @EnableAspectJAutoProxy,Spring 会在容器启动的时候注册名叫 internalAutoProxyCreator 的 AnnotationAwareAspectJAutoProxyCreator。
  • 在 bean 实例化实现,属性拆卸实现之后,开始执行回调办法,这时取出所有的 BeanPostProcessor,执行其 postProcessAfterInitialization 办法,筹备开始对指标对象代理的创立。
  • 首先创立一个代理工厂 ProxyFactory,设置一系列的属性,如所有的告诉办法,增强器,拦截器和指标类等注入代理工厂,再调用 ProxyFactory.getProxy(classLoader)获取代理。
  • 通过判断是用 JDK 动静代理还是 CGLIB 创立不同的 AopProxy,最初获取 getProxy。

如果感觉本文对你有帮忙点赞珍藏关注我一起学习提高!

正文完
 0