zoukankan      html  css  js  c++  java
  • AOP之proceedingjoinpoint和joinpoint区别

    现在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手册)

    spring aop支持(https://www.cnblogs.com/V1haoge/p/9560803.html

  • 相关阅读:
    使用jaxb用xsd生成java类
    EMF保存CDATA
    windows builder里面的可伸缩面板
    使用eclipse open type对话框
    eclipse中toolbar位置的系统URI
    bzoj 4414 数量积 结论题
    bzoj 4402 Claris的剑 组合数学
    bzoj 4206 最大团 几何+lis
    bzoj 3676 [Apio2014]回文串 回文自动机
    bzoj 3670 [Noi2014]动物园 kmp
  • 原文地址:https://www.cnblogs.com/muzhongjiang/p/13301920.html
Copyright © 2011-2022 走看看