• spring AOP之proceedingjoinpoint和joinpoint区别(获取各对象备忘)、动态代理机制及获取原理代理对象、获取Mybatis Mapper接口原始对象


    现在AOP的场景越来越多,所以我们有必要理解下和AOP相关的一些概念和机制。基础知识和原理类大家搜索spring aop/aspectj,有大量现成的可以参考,基本上只要理解了jdk动态代理、cglib字节码动态生成代理就足够了,而且必须知道这个代理类是spring托管的(如果是自己创建的代理类,是无法被拦截的,此时只能使用过滤器/拦截器机制,他们本身是链式的,跟代理无关),所以这里就不重复废话了。
    import org.aspectj.lang.reflect.SourceLocation;  
    public interface JoinPoint {  
       String toString();         //连接点所在位置的相关信息  
       String toShortString();     //连接点所在位置的简短相关信息  
       String toLongString();     //连接点所在位置的全部相关信息  
       Object getThis();         //返回AOP代理对象,也就是com.sun.proxy.$Proxy18
       Object getTarget();       //返回目标对象,一般我们都需要它或者(也就是定义方法的接口或类,为什么会是接口呢?这主要是在目标对象本身是动态代理的情况下,例如Mapper。所以返回的是定义方法的对象如aoptest.daoimpl.GoodDaoImpl或com.b.base.BaseMapper<T, E, PK>)
       Object[] getArgs();       //返回被通知方法参数列表  
       Signature getSignature();  //返回当前连接点签名  其getName()方法返回方法的FQN,如void aoptest.dao.GoodDao.delete()或com.b.base.BaseMapper.insert(T)(需要注意的是,很多时候我们定义了子类继承父类的时候,我们希望拿到基于子类的FQN,这直接可拿不到,要依赖于AopUtils.getTargetClass(point.getTarget())获取原始代理对象,下面会详细讲解)
       SourceLocation getSourceLocation();//返回连接点方法所在类文件中的位置  
       String getKind();        //连接点类型  
       StaticPart getStaticPart(); //返回连接点静态部分  
      }  
     
     public interface ProceedingJoinPoint extends JoinPoint {  
           public Object proceed() throws Throwable;  
           public Object proceed(Object[] args) throws Throwable;  
     } 
    JoinPoint.StaticPart:提供访问连接点的静态部分,如被通知方法签名、连接点类型等:
    public interface StaticPart {  
       Signature getSignature();    //返回当前连接点签名  
       String getKind();          //连接点类型  
       int getId();               //唯一标识  
       String toString();         //连接点所在位置的相关信息  
       String toShortString();     //连接点所在位置的简短相关信息  
       String toLongString();     //连接点所在位置的全部相关信息  
    }

    环绕通知 ProceedingJoinPoint 执行proceed方法的作用是让目标方法执行,这也是环绕通知和前置、后置通知方法的一个最大区别。

     Proceedingjoinpoint 继承了 JoinPoint 。是在JoinPoint的基础上暴露出 proceed 这个方法。proceed很重要,这个是aop代理链执行的方法。

      暴露出这个方法,就能支持 aop:around 这种切面(而其他的几种切面只需要用到JoinPoint,这跟切面类型有关), 能决定是否走代理链还是走自己拦截的其他逻辑。建议看一下 JdkDynamicAopProxy的invoke方法,了解一下代理链的执行原理。
    典型的用法如下:
        public Object around(ProceedingJoinPoint point) throws Throwable {
            Signature signature = point.getSignature();
    // AopUtils.getTargetClass(point.getTarget())获取原始对象,例如对于Mapper而言,它获取的是具体代理的Mapper如com.b.mapper.DefaultDsMapper(如果前者继承了后者的话)而不是定义该方法的Mapper如com.b.base.BaseMapper<Info, InfoExample, InfoKey>,如下图 Type[] types
    = AopUtils.getTargetClass(point.getTarget()).getGenericInterfaces(); // getGenericInterfaces方法能够获取类/接口实现的所有接口 Annotation nologgingAnno = ((Class)types[0]).getAnnotation(Nologging.class); // type是所有类型的父接口 MethodSignature methodSignature = (MethodSignature)signature; Method targetMethod = methodSignature.getMethod();

     

    现在来补充下Java中Type接口与Class类的区别联系。

    package java.lang.reflect;
    
    /**
     * Type is the common superinterface for all types in the Java
     * programming language. These include raw types, parameterized types,
     * array types, type variables and primitive types.
     *
     * @since 1.5
     */
    public interface Type {
        /**
         * Returns a string describing this type, including information
         * about any type parameters.
         *
         * @implSpec The default implementation calls {@code toString}.
         *
         * @return a string describing this type
         * @since 1.8
         */
        default String getTypeName() {
            return toString();
        }
    }

    其主要的子类包括:

    总结来说:

    • Type是一个接口。
    • Type是Java中所有类型的父接口,有一些子类,如上所示。
    • Type包括:raw type(原始类型,对应Class),parameterized types(参数化类型), array types(数组类型), type variables(类型变量) and primitive types(基本类型,对应Class).
    • Type是JDK1.5引入的,主要是为了泛型。

    Type接口与Class类的区别联系

    • Type是Class的父接口。
    • Class是Type的子类。

      提示:因为AOP是基于动态代理生成,如果想要仔细研究生成的代理类长什么样,可以设置系统参数-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true,这样就会保存所有自动生成的代理类(注:生产环境严禁使用)。

    参考:https://blog.csdn.net/cxh5060/article/details/45151863(拦截自定义注解,需要注意的是,标准的AOP表达式@annotation(com.xxx.yyy.annotation.CustomAnnotation)只能拦截实现类方法上的注解,无法拦截接口上的注解,如有需根据接口方法上的注解拦截的需求,需使用spring bean生命周期的BeanPostProcessor动态生成代理,而不是采用简单的AOP实现

    https://www.cnblogs.com/akaneblog/p/6720513.html(jdk动态代理手工编写,一般框架使用,比如spring aop、mybatis中logger也使用了动态代理)

    https://www.cnblogs.com/haiq/p/4304615.html、https://blog.csdn.net/xlgen157387/article/details/82497594(cglib vs jdk动态代理性能参考)

    https://blog.csdn.net/u010061691/article/details/50857798(进一步加了解释,实际上InvocationHandler是要被明确调用的,只不过在AOP中通常被框架调用了,如果是应用自己编写的话,则需要代码中通过InvocationHandler.getProxy,然后强转、再调用。https://dzone.com/articles/java-dynamic-proxies)

    https://dzone.com/articles/cglib-missing-manual(cglib手册)

  • 相关阅读:
    Atitit 趋势管理之道 attilax著
    Atitit 循环处理的新特性 for...else...
    Atitit 2017年的技术趋势与未来的大技术趋势
    atitit 用什么样的维度看问题.docx 如何了解 看待xxx
    atitit prj mnrs 项目中的几种经理角色.docx
    Atitit IT办公场所以及度假村以及网点以及租房点建设之道 attilax总结
    Atitit 工具选型的因素与方法 attilax总结
    Atitit.团队文化建设影响组织的的一些原理 法则 定理 效应 p826.v4
    Atiitt 管理方面的误区总结 attilax总结
    Atitit 未来趋势把控的书籍 attilax总结 v3
  • 原文地址:https://www.cnblogs.com/zhjh256/p/10694165.html
Copyright © 2020-2023  润新知