一、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;}
@Overridepublic 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中

@Overridepublic 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动静代理的实现

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

@Overridepublic 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。

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