文档章节

Spring AOP pointCut target与this详解

OttoWu
 OttoWu
发布于 04/22 14:56
字数 1323
阅读 31
收藏 0

「深度学习福利」大神带你进阶工程师,立即查看>>>

在使用Spring时对于target和this的区别,官网和网上的文章均未说明清楚这两者的区别,故详细使用并测试一下。

定义

  • this:切点判断时,判断的是代理类本身是否符合条件。
  • target:切点判断时,判断的是被代理的目标对象是否符合条件。

网上多是这样的解释,那究竟代理类和代理的目标对象有什么区别呢?

首先既然是代理,那么spring中就有两种方式,这两种方式的this和target肯定会存在区别

  1. 基于接口的java动态代理实现(被代理的目标对象必须要实现接口)。
  2. 基于类继承的cglib实现 (被代理的目标对象无需实现接口)

两者的关系可以如下图展示:

enter description here

其中JDK Proxy Class表示是走接口生成的JDK动态代理,CGLIB Proxy Class表示走的继承实现的代理。图中的this就是指向代理类本身,而target则指向的被代理的目标对象,由于@Service是加在具体的Impl实现类上的,所以两者的被代理对象均是Impl实现类。

测试

从上图可以看出 ,似乎使用target的话两者应该是没有什么区别的,下面测试一下:

  • 定义AnimalService接口
public interface AnimalService {
    /**
     * 只有一个简单的叫的方法定义
     */
    void say();
}
  • 定义DogService实现AnimalService接口
@Service("dogService")
public class DogService implements AnimalService {

    @Override
    public void say() {
        System.out.println("bark .....");
    }
}
  • 接着定义切面类,用来动态生成我们的JDK Proxy Class和 CGLIB Proxy Class
@Aspect
@Component
public class AnimalAspect {
    
    @Pointcut("this(com.whl.aop.example.aoptest.service.AnimalService)")
    public void pointCut() {
    }
    
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("begin ....");
        Object result = point.proceed();
        System.out.println("end ....");
        return result;
    }
}

那么到了这里,大家都知道,由于DogService是实现了AnimalService接口的,所以spring会默认使用JDK动态代理来生成代理类,但是这里有个比较有意思的事情,在SpringBoot中却是默认全都是采用CGLIB的,参见这篇文章的分析 https://www.cnblogs.com/coderxiaohei/p/11758239.html

好了,其实也没什么特别的,就是SpringBoot中是将spring.aop.proxy-target-class默认设置成true来强制都启用CGLIB实现代理的。

那既然是测试,这边就需要把两种情况都测试一遍。分别通过在application.propertiesspring.aop.proxy-target-class设置为false(JDK Proxy)和true(使用CGLIB)来进行测试

  • 测试类
@SpringBootTest
@RunWith(SpringRunner.class)
class AnimalServiceTest {

    @Autowired
    @Qualifier("dogService")
    private AnimalService animalService;

    @Test
    void say() {
        animalService.say();
    }

}

首先测试this的情况

直观起见,这里使用表格展示

PointCut JDK Proxy CGLIB Proxy Class
this(com.whl.aop.example.aoptest.service.AnimalService) 成功切入 成功切入
this(com.whl.aop.example.aoptest.service.impl.DogService) 失败 成功切入

可以看到,除了this(DogService) 使用的JDK Proxy之外,其他的都是成功了,都运行显示

begin ....
bark .....
end ....

那么为什么this(DogService) 使用的JDK Proxy不行呢,回到上面的那个图

enter description here

可以看到CGLIB Proxy Class走的是继承关系,那么this也就是CGLIB Proxy Class这个类即是派生自DogService,也是派生自AnimalService,这个很好理解,反编译确定一下,使用arthas可以看到生成了enter description here 一个由CGLIB加强的代理类,查看一下它的源代码


public class DogService$$EnhancerBySpringCGLIB$$bbc4a4b6
extends DogService
implements SpringProxy,
Advised,
Factory {

    // ...不完整,仅截取重要部分
    public final void say() {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            DogService$$EnhancerBySpringCGLIB$$bbc4a4b6.CGLIB$BIND_CALLBACKS(this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor != null) {
            Object object = methodInterceptor.intercept(this, CGLIB$say$0$Method, CGLIB$emptyArgs, CGLIB$say$0$Proxy);
            return;
        }
        super.say();
    }
    // ...不完整,仅截取重要部分
}

可以看到DogService$$EnhancerBySpringCGLIB$$bbc4a4b6是继承自DogService的,那么自然对于这个代理类而言this(DogService)或者this(AnimalService)都是可以切入的了。

那么回过头来看一下JDK Proxy生成的类呢

public final class $Proxy63
extends Proxy
implements AnimalService,
SpringProxy,
Advised,
DecoratingProxy {
// ...不完整,仅截取重要部分
public final void say() {
        try {
            this.h.invoke(this, m3, null);
            return;
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
    // ...不完整,仅截取重要部分
}

$Proxy63是实现的AnimalService那么在this AnimalService是可以成功切入,而在this DogService的时候是无法切入也就比较好理解了,因为该代理类只实现了AnimalService,自然是无法转换判断为DogService。

接下来测试target的情况

直观起见,这里使用表格展示

PointCut JDK Proxy CGLIB Proxy Class
target(com.whl.aop.example.aoptest.service.AnimalService) 成功切入 成功切入
target(com.whl.aop.example.aoptest.service.impl.DogService) 成功切入 成功切入

target的话就都能成功,这个比较好理解,因为不管是JDK Proxy还是CGLIB Proxy Class,被代理的对象都是DogService。

总结:

如果是采用面向接口编程的思想,所有的被代理对象均有实现接口,且在使用过程中均使用接口对象访问 1.当this和target是接口时其实并无区别 2.当this是具体的实现类时,需要谨慎判断当前是使用的JDK proxy(无效)和CGLIB(有效)的区别。 3.当target时,不论是接口还是实现类,并无区别。

OttoWu
粉丝 5
博文 21
码字总数 40773
作品 0
杭州
私信 提问
加载中
请先登录后再评论。
访问安全控制解决方案

本文是《轻量级 Java Web 框架架构设计》的系列博文。 今天想和大家简单的分享一下,在 Smart 中是如何做到访问安全控制的。也就是说,当没有登录或 Session 过期时所做的操作,会自动退回到...

黄勇
2013/11/03
3.7K
8
高效 Java Web 开发框架--JessMA

JessMA 是功能完备的高性能 Full-Stack Web 应用开发框架,内置可扩展的 MVC Web 基础架构和 DAO 数据库访问组件(内部已提供了 Hibernate、MyBatis 与 JDBC DAO 组件),集成了 Action 拦截...

伤神小怪兽
2012/11/13
9.3K
3
Java 反射封装库--Mirror

给一个简单的问题带来光明的解决方案,通常用ReflectionUtil命名。 在几乎所有项目都需要依靠反射来做高级任务。但是,处理Java反射API是痛苦的。问任何使用过反射的人,他会告诉你它是真的令人...

jiangyuan
2012/12/07
2.4K
0
eternal mvc 框架--eternal

spring在设计上真博大精深啊,无论从哪点来说,都非常不错,当然啦大家一直说他的配置麻烦,这应该是人家的设计思想吧,把每个类都看成一个bean,以xml的方式配置关系,就像java的面向对象,...

青青小树
2013/01/09
1.3K
0
疯狂Spring Cloud连载(29)微服务跟踪概述

本文节选自《疯狂Spring Cloud微服务架构实战》 京东购买地址:https://item.jd.com/12256011.html 当当网购买地址:http://product.dangdang.com/25201393.html Spring Cloud教学视频:htt...

杨大仙的程序空间
2018/01/09
566
0

没有更多内容

加载失败,请刷新页面

加载更多

历史上第一个聊天机器人:200 行代码就能欺骗人类感情

在 1964 年至 1966 年间,麻省理工学院人工智能实验室的德裔美国计算机科学家约瑟夫·维森鲍姆(Joseph Weizenbaum)开发了历史上第一个聊天机器人 —— Eliza。 Eliza 的名字源于爱尔兰剧作...

摆摊卖报纸
6分钟前
11
0
WordPress文章页面获取评论次数

页面的评论次数 主要调用在文章的开始,让读者方便的点击,参与评论,这里我们是获取本篇文章的评论次数,不是评论的人数。 通过以下代码轻松实现: <?php if( $posts ) : ?> <?php foreach...

osc_ho1lz6z7
6分钟前
0
0
JavaScript 预编译过程的详细解读

文章目录 JavaScript运行三部曲 JavaScript预编译 01 关于预编译的一些知识点 02 预编译四部曲(局部) 1. 创建AO对象(Activation Object) (执行期上下文) 2. 找形参和变量声明,将变量和形参...

osc_vo0yi5f8
7分钟前
0
0
WordPress页面添加打印功能

页面打印 功能方便我们快速链接打印机,有很多插件,这里介绍代码实现的方法。 1、html添加打印链接 <a href="javascript:printme()" target="_self">打印</a> 2、js函数 在你的wp中引入下面......

osc_hzf6peqc
9分钟前
0
0
wordpress文章页面添加字体增大减小链接

字体的大小 影响读者的视觉感受,我们可以在wordpress的文章页面single.php上通过js添加字体的增大减小按钮,来方便字体大小的调整。 1、在single.php文章页面添加Js <script type="text/jav...

osc_0qnrwmy3
10分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部