AOP一个demo就够了-注解失效记录

调用this使aop失效

曾在工作中遇到过自定义了一个@logable的日志注解,对manager层进行拦截记录日志,其中有一个方法中调用了内部的一个方法,该方法本身也有修改操作,用作复用。
结果日志中始终没有打印调用方法的日志。
好奇之下进行研究,发现aop无法拦截住内部方法的调用原因可见此demo, 理解了原因,我当时是直接注入了自身服务进行调用,发现日志就可以拦截到了。
希望可以帮助到有此困惑的小伙伴。我会陆续将以前记录的东西持续分享出来。

记录的一个demo

这是记录的一个比较简单的demo,可以初步了解到aop拦截的原理以及验证了我工作用使用aop注解失效的问题

测试类

package com.sunyard.unified.csrt.spring.aop.test;
  
import com.sunyard.unified.csrt.spring.aop.ICustomerService;
import com.sunyard.unified.csrt.spring.aop.impl.CustomerServiceImpl;
import com.sunyard.unified.csrt.spring.aop.proxy.CustomerServiceProxy;

/**
 * @author chaotan.liu
 * @version 1.0
 * @date 2020/7/24 8:51
 * 在开发基于 Spring 的应用的过程中碰到了一个让我困惑了好久的问题,我在一个 Service 类的 doSomething1() 方法中通过
 * this.doSomething2(); 语句调用了同一个类中的 doSomething2 方法,运行时通过调试发现 doSomething1 方法的执行前
 * 后正常地执行了自定义的 around 装备,但是在 doSomething2 方法执行前后并未如我所期望的那样执行自定义的 around advice 。
 * 今天终于恍然大悟,把它当作笔记写下来。Spring 的代理实现有两种:一是基于 JDK Dynamic Proxy 技术而实现的;二是基于 CGLIB
 * 技术而实现的。今天的目标是探索基于 JDK Dynamic Proxy 的动态代理。首先来看看如何自己动手实现一个对 Service Bean 对象的动态代理。
 * 为了能够更清楚地看到 Spring AOP 动态代理的本质,我决定不使用 JDK 中提供的 Dynamic Proxy API,就使用最普通的 java 代码来
 * 模拟一个动态代理实例。
 */
public class TestProxy {  
      
    public static void main(String[] args) {  
        // 创建代理目标对象。对于Spring来说,这一工作  
        // 是由Spring DI容器完成的。  
        ICustomerService serviceProxyTarget = new CustomerServiceImpl();
  
        // 创建代理对象。对于Spring来说,这一工作  
        // 也是由Spring DI容器完成的。  
        CustomerServiceProxy serviceProxy = new CustomerServiceProxy();
        serviceProxy.setCustomerService(serviceProxyTarget);  
        ICustomerService serviceBean = (ICustomerService) serviceProxy;  
  
        // 调用业务逻辑操作  
        serviceBean.doSomething1();  
    }


    /**
     * 现在以调试方式运行这个应用,你会发现在 doSomething1() 中调用 doSomething2() 方法的
     * 时候并未去执行CustomerServiceProxy 类的 doBefore()、doAfter() 方法。再来看看这句
     * 关键代码:doSomething2(); 把它隐含的意思也表达出来吧:this.doSomething2(); 哦,我
     * 明白了,在 CustomerServiceImpl 类中 this 关键字表示的是当前这个CustomerServiceImpl
     * 类的实例。那程序当然就会去执行 CustomerServiceImpl 类中的 doSomething2() 方法了,而不
     * 会去执行 CustomerServiceProxy 类中的 doSomething2() 方法!!
     * 在使用 Spring AOP 的时候,我们从 IOC 容器中获取的 Service Bean 对象其实都是代理对象,
     * 而不是那些 Service Bean 对象本身,也就是说获取的并不是被代理对象或代理目标。当我在自己的
     * Service 类中使用 this 关键字嵌套调用同类中的其他方法时,由于 this 关键字引用的并不是该
     * Service Bean 对象的代理对象,而是其本身,故 Spring AOP 是不能拦截到这些被嵌套调用的方法的。
     */
}  

业务接口

package com.sunyard.unified.csrt.spring.aop;

public interface ICustomerService {
    public void doSomething1();  
    public void doSomething2();
} 

业务实现

package com.sunyard.unified.csrt.spring.aop.impl;


import com.sunyard.unified.csrt.spring.aop.ICustomerService;

public class CustomerServiceImpl implements ICustomerService {
  
    public void doSomething1() {  
  
        System.out.println("Inside CustomerServiceImpl.doSomething1()");  
  
        this.doSomething2();
        new CustomerServiceImpl().doSomething2();
  
    }  
  
    public void doSomething2() {  
  
        System.out.println("Inside CustomerServiceImpl.doSomething2()");  
  
    }  
  
}  

代理类实现

package com.sunyard.unified.csrt.spring.aop.proxy;


import com.sunyard.unified.csrt.spring.aop.ICustomerService;

public class CustomerServiceProxy implements ICustomerService {
  
    private ICustomerService customerService;  
  
    public void setCustomerService(ICustomerService customerService) {  
        this.customerService = customerService;  
    }  
  
    public void doSomething1() {  
        doBefore();  
        customerService.doSomething1();

        doAfter();  
    }  
  
    public void doSomething2() {  
        doBefore();  
        customerService.doSomething2();  
        doAfter();  
    }  
  
    private void doBefore() {  
        // 例如,可以在此处开启事务  
        System.out.println("方法执行前.");
    }  
  
    private void doAfter() {  
        // 例如,可以在此处提交或回滚事务、释放资源等等  
        System.out.println("方法执行后...");
    }  
  
}  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值