`
m635674608
  • 浏览: 5027457 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

Spring AOP无法拦截内部方法调用

    博客分类:
  • java
 
阅读更多

假设一个接口里面有两个方法:

package demo.long;

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

接口实现类如下:

package demo.long.impl;

import demo.long.CustomerService; 

public class CustomerServiceImpl implements CustomerService {  

    public void doSomething1() {  
        System.out.println("CustomerServiceImpl.doSomething1()");  
        doSomething2();  
    }  

    public void doSomething2() {  
        System.out.println("CustomerServiceImpl.doSomething2()");  
    }  

}

现在我需要在CustomerService接口的每个方法被调用时都在方法前执行一些逻辑,所以需要配置一个拦截器:

package demo.long;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class CustomerServiceInterceptor {

    @Before("execution(* demo.long..*.*(..))")
    public void doBefore() {
        System.out.println("do some important things before..."); 
    }
}

把Bean加到Spring配置中

<aop:aspectj-autoproxy />

<bean id="customerService" class="demo.long.impl.CustomerServiceImpl" />
<bean id="customerServiceInterceptor" class="demo.long.CustomerServiceInterceptor" />

如果现在外部对象调用CustomerService的doSomething1()方法的时候,会发现只有doSomething1()方法执行前打印了“do some important things before...”,而doSomething1()内部调用doSomething2()时并没有打印上述内容;外部对象单独调用doSomething2()时会打印上述内容。

public class CustomerServiceTest {

    @Autowired
    ICustomerService customerService;

    @Test
    public void testAOP() {
        customerService.doSomething1();
    }
}

原因分析

拦截器的实现原理就是动态代理,实现AOP机制。Spring 的代理实现有两种:一是基于 JDK Dynamic Proxy 技术而实现的;二是基于 CGLIB 技术而实现的。如果目标对象实现了接口,在默认情况下Spring会采用JDK的动态代理实现AOP,CustomerServerImpl正是这种情况。

JDK动态代理生成的CustomerServiceImpl的代理类大致如下:

public class CustomerServiceProxy implements CustomerService {  

    private CustomerService customerService;  

    public void setCustomerService(CustomerService customerService) {  
        this.customerService = customerService;  
    }  

    public void doSomething1() {  
        doBefore();  
        customerService.doSomething1();  
    }  

    public void doSomething2() {  
        doBefore();  
        customerService.doSomething2();  
    }  

    private void doBefore() {  
        // 例如,可以在此处开启事务或记录日志
        System.out.println("do some important things before...");  
    }  

}

客户端程序使用代理类对象去调用业务逻辑:

public class TestProxy {  

    public static void main(String[] args) {  
        // 创建代理目标对象
        // 对于Spring来说,这一工作是由Spring容器完成的。  
        CustomerService serviceProxyTarget = new CustomerServiceImpl();  

        // 创建代理对象
        // 对于Spring来说,这一工作也是由Spring容器完成的。 
        CustomerServiceProxy serviceProxy = new CustomerServiceProxy();  
        serviceProxy.setCustomerService(serviceProxyTarget);  
        CustomerService serviceBean = (CustomerService) serviceProxy;  

        // 调用业务逻辑操作  
        serviceBean.doSomething1();  
    }  
}

执行main方法,发现doSomething1()中调用doSomething2()方法的时候并未去执行CustomerServiceProxy类的doBefore()方法。其实doSomething2()等同于this.doSomething2(),在CustomerServiceImpl类中this关键字表示的是当前这个CustomerServiceImpl类的实例,所以程序会去执行CustomerServiceImpl对象中的doSomething2()方法,而不会去执行CustomerServiceProxy类对象中的 doSomething2()方法。

在使用Spring AOP的时候,我们从IOC容器中获取的Bean对象其实都是代理对象,而不是那些Bean对象本身,由于this关键字引用的并不是该Service Bean对象的代理对象,而是其本身,因此Spring AOP是不能拦截到这些被嵌套调用的方法的。

解决方案

  1. 修改类,不要出现“自调用”的情况:这是Spring文档中推荐的“最佳”方案;
  2. 若一定要使用“自调用”,那么this.doSomething2()替换为:((CustomerService) AopContext.currentProxy()).doSomething2();此时需要修改spring的aop配置:
    <aop:aspectj-autoproxy expose-proxy="true" />
http://www.jianshu.com/p/6534945eb3b5
分享到:
评论

相关推荐

    spring aop切面拦截指定类和方法实现流程日志跟踪

    本节将详细介绍如何使用Spring AOP实现流程日志跟踪,主要关注于如何通过AOP拦截特定的类和方法来进行日志记录。 ##### 3.1 配置Spring AOP 在Spring配置文件中定义切面和切入点表达式是非常关键的一步。一般来说...

    在自定义spring aop中使用el获取拦截方法的变量值。

    在Spring AOP中,EL可以帮助我们访问被拦截方法的局部变量,这对于处理复杂的逻辑或者需要获取方法内部状态的情况非常有用。 要实现这个功能,我们需要创建一个自定义的Aspect(切面),并在其中定义一个Pointcut...

    Spring Mvc AOP通过注解方式拦截controller等实现日志管理

    本教程将详细介绍如何利用注解来配置和使用AOP来拦截Controller层的方法,以便记录执行过程中的相关信息,实现日志管理。 一、Spring AOP基础 AOP是Spring框架的核心组件之一,它允许程序员定义“切面”,这些切面...

    spring AOP拦截方法小示例

    这个“spring AOP拦截方法小示例”是一个实际应用,展示了如何使用Spring AOP来拦截特定层的所有方法,并在调用前后以及出现异常时执行自定义逻辑。 首先,让我们了解AOP的基本概念。AOP的核心是切面(Aspect),它...

    死磕Spring之AOP篇 - Spring AOP两种代理对象的拦截处理(csdn)————程序.pdf

    Spring AOP 是一种面向切面编程的技术,它允许我们在不修改源代码的情况下,对应用程序的特定部分(如方法调用)进行增强。在 Spring 中,AOP 的实现主要依赖于代理模式,有两种代理方式:JDK 动态代理和 CGLIB 动态...

    springaop拦截controller日志

    "springaop拦截controller日志"这个主题旨在讲解如何使用Spring AOP来拦截Controller层的方法调用,并在方法执行前后记录相关日志。 首先,了解Spring AOP的基本概念。AOP是一种编程范式,它允许程序员定义“切面”...

    Spring源代码解析(七):Spring_AOP中对拦截器调用的实现.doc

    总的来说,Spring AOP中的拦截器调用实现是通过`JdkDynamicAopProxy`的`invoke()`方法作为入口,这个方法处理了特殊方法、内部服务调用、目标对象获取、拦截器链的执行等一系列操作。拦截器链的执行顺序是由`Advisor...

    spring aop日志拦截

    在Spring MVC框架中,AOP(面向切面编程)是一种强大的工具,用于实现日志拦截,特别是对于controller层的操作。AOP允许我们定义横切关注点,这些关注点可以是如日志记录、事务管理、权限检查等通用功能,它们在程序...

    ssh2登陆+spring aop做拦截

    在 Spring 中,我们可以通过注解或 XML 配置来定义切面,比如 @Before、@After 和 @Around 通知,用于在方法调用前、后或环绕执行自定义逻辑。 结合 SSH2 登录与 Spring AOP,我们可以创建一个安全的系统,其中 SSH...

    mybatis 拦截器 + spring aop切面 + spring事务+ 反射工具类

    例如,可能会有一个自定义的MyBatis拦截器用于分页查询,一个Spring AOP切面用于记录操作日志,Spring事务管理确保数据的一致性,而反射工具类可能用于动态加载配置或处理某些通用的反射任务。通过这些组件的组合,...

    Spring使用AOP的三个jar包

    即使你没有直接使用AspectJ语法编写切面,Spring的AOP代理也可以利用这个库进行代理对象的创建,以实现方法调用前后的通知(advises)。这个库对于那些希望在不改变源代码的情况下,通过AOP增强已有类的行为的开发者...

    spring aop 拦截实例

    在提供的压缩包中,可能包含了一个或多个测试类(Tests),这些测试类通常用来验证AOP拦截器的功能。它们可能包含模拟业务场景的方法,这些方法会被切面拦截并执行相应的通知。通过运行这些测试,我们可以确保AOP...

    简单spring aop 例子

    4. **测试**:在测试类中,创建Spring容器并调用`UserService`的方法,你会看到日志信息先于方法执行输出。 以上就是Spring AOP的基本用法。在实际项目中,你可以根据需求定义不同的通知类型,如`@After`、`@Around...

    spring aop 拦截器简单实现

    它是一个实现了`org.springframework.aop.MethodBeforeAdvice`、`org.springframework.aop.AfterReturningAdvice`或`org.springframework.aop.ThrowsAdvice`等接口的对象,可以在方法调用前后执行自定义逻辑。...

    详解Spring AOP 拦截器的基本实现

    具体到Spring AOP拦截器的代码实现,本文通过创建TestInterceptor类来演示。这个类继承自HandlerInterceptorAdapter,然后重写其中的afterCompletion、postHandle等方法。在这个类中,可以在相应方法中添加自定义的...

    spring_aop_拦截实例

    在Spring框架中,AOP(面向切面编程)是一种强大的工具,它允许程序员定义横切关注点,如日志、事务...通过理解并应用AOP拦截实例,开发者能够更好地管理和控制应用程序的各个层面,从而提高软件的可维护性和灵活性。

    Spring AOP 拦截器 Advisor

    拦截器是 AOP 的一种实现方式,它在方法调用前、后或异常发生时执行自定义逻辑。 Advisor 在 Spring AOP 中扮演了中介的角色。它包含两部分:Advice 和 Pointcut。Advice 描述了在特定的 Pointcut 下要执行的操作,...

    Spring Aop四个依赖的Jar包

    在Spring AOP中,我们无需深入到每个方法的实现细节,而是可以定义“切面”,在合适的时机(如方法调用前、后、异常发生时等)执行特定的逻辑。这样,业务代码和关注点(如日志、事务管理等)得以分离,提高了代码的...

    SpringAOP之探秘(动态代理、责任链模式、注解使用)

    你可能会看到如何通过Spring AOP自定义代理类,以及如何利用JDK动态代理和CGLIB来拦截并增强方法的执行。 3. **第六章_cache-demo.zip**:此示例可能进一步扩展了缓存相关的实现,包括不同类型的缓存策略、缓存更新...

    反射实现 AOP 动态代理模式(Spring AOP 的实现原理)

    Spring AOP允许开发者定义切面,并在这些切面中指定拦截的方法。Spring AOP支持不同的代理策略,包括JDK动态代理和CGLIB代理。如果被代理的类没有实现接口,Spring AOP会采用CGLIB来生成代理对象。CGLIB(Code ...

Global site tag (gtag.js) - Google Analytics