`

Spring AOP在同一个类里自身方法相互调用时无法拦截

阅读更多
Spring AOP在同一个类里自身方法相互调用时无法拦截。比如下面的代码:
public class SomeServiceImpl implements SomeService
{

    public void someMethod()
    {
        someInnerMethod();
        //foo...
    }

    public void someInnerMethod()
    {
        //bar...
    }
}

两个方法经过AOP代理,执行时都实现系统日志记录。单独使用someInnerMethod时,没有任何问题。但someMethod就有问题了。 someMethod里调用的someInnerMethod方法是原始的,未经过AOP增强的。我们期望调用一次someMethod会记录下两条系统日志,分别是someInnerMethod和someMethod的,但实际上只能记录下someMethod的日志,也就是只有一条。在配置事务时也可能会出现问题,比如someMethod方法是REQUIRED,someInnerMethod方法是 REQUIRES_NEW,someInnerMethod的配置将不起作用,与someMethod方法会使用同一个事务,不会按照所配置的打开新事务。
由于java这个静态类型语言限制,最后想到个曲线救国的办法,出现这种特殊情况时,不要直接调用自身方法,而通过AOP代理后的对象。在实现里保留一个AOP代理对象的引用,调用时通过这个代理即可。比如:
//从beanFactory取得AOP代理后的对象
SomeService someServiceProxy = (SomeService)beanFactory.getBean("someService"); 

//把AOP代理后的对象设置进去
someServiceProxy.setSelf(someServiceProxy); 

//在someMethod里面调用self的someInnerMethod,这样就正确了
someServiceProxy.someMethod();

但这个代理对象还要我们手动set进来,幸好SpringBeanFactory有BeanPostProcessor扩展,在bean初始化前后会统一传递给BeanPostProcess处理,繁琐的事情就可以交给程序了,代码如下,首先定义一个BeanSelfAware接口,实现了此接口的程序表明需要注入代理后的对象到自身。
public class SomeServiceImpl implements SomeService,BeanSelfAware

{

    private SomeService self;//AOP增强后的代理对象

 

    //实现BeanSelfAware接口

    public void setSelf(Object proxyBean)

    {

        this.self = (SomeService)proxyBean

    }

 

    public void someMethod()

    {

        someInnerMethod();//注意这句,通过self这个对象,而不是直接调用的

        //foo...

    }

    public void someInnerMethod()

    {

        //bar...

    }

}

再定义一个BeanPostProcessor,beanFactory中的每个Bean初始化完毕后,调用所有BeanSelfAware的setSelf方法,把自身的代理对象注入自身……
public class InjectBeanSelfProcessor implements BeanPostProcessor
{
 
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
    {
        if(bean instanceof BeanSelfAware)
        {
            System.out.println("inject proxy:" + bean.getClass());
            BeanSelfAware myBean = (BeanSelfAware)bean;
            myBean.setSelf(bean);
            return myBean;
        }
        return bean;
    }
 
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
    {
        return bean;
    }
}

最后,在BeanFactory配置中组合起来,只需要把BeanPostProcesser加进去就可以了,比平常多一行配置而已。
    <!-- 注入代理后的bean到bean自身的BeanPostProcessor... -->
    <bean class=" org.mypackage.InjectBeanSelfProcessor"></bean>

    <bean id="someServiceTarget" class="org.mypackage.SomeServiceImpl" /> 

    <bean id="someService" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target">
            <ref local="someServiceTarget" />
        </property>
        <property name="interceptorNames">
            <list>
                <value>someAdvisor</value>
            </list>
        </property>
    </bean>

    <!-- 调用spring的DebugInterceptor记录日志,以确定方法是否被AOP增强 -->
    <bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor" />

    <bean id="someAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice">
            <ref local="debugInterceptor" />
        </property>
        <property name="patterns">
            <list>
                <value>.*someMethod</value>
                <value>.*someInnerMethod</value>
            </list>
        </property>
    </bean>

这里的someService#someInnerMethod就表现出预期的行为了,无论怎样,它都是经过AOP代理的,执行时都会输出日志信息。
用XmlBeanFactory进行测试需要注意,所有的BeanPostProcessor并不会自动生效,需要执行以下代码:
XmlBeanFactory factory = new XmlBeanFactory(...);
InjectBeanSelfProcessor postProcessor = new InjectBeanSelfProcessor();
factory.addBeanPostProcessor(postProcessor);

http://fyting.iteye.com/blog/109236
分享到:
评论
2 楼 bluseli 2012-08-31  
怎么没有拦截到???
1 楼 bluseli 2012-08-31  
请问下,“XmlBeanFactory进行测试需要注意,所有的BeanPostProcessor并不会自动生效,需要执行以下代码”那我在真正用的时候需要怎么样去做。spriing会自动加载吗

相关推荐

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

    在上述代码中,我们定义了一个名为`SpringAopLog`的切面类,并通过注解指定了哪些方法会在目标方法执行前后被调用。在`afterReturn`方法中,根据不同的方法名来记录不同的日志信息。 #### 四、总结 通过Spring AOP...

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

    标题中的“在自定义Spring AOP中使用EL获取拦截方法的变量值”指的是在Spring的面向切面编程(AOP)中,通过Expression Language(EL,表达式语言)来访问被拦截方法的局部变量值。这通常涉及到Spring的代理机制、...

    Spring使用AOP的三个jar包

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

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

    `Enhancer` 是 CGLIB 的核心类,用于创建代理对象,而 `Callback` 是一个回调接口,它定义了代理对象在方法调用时需要执行的操作。在 Spring AOP 中,`ObjenesisCglibAopProxy` 类负责使用 CGLIB 创建代理对象,它会...

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

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

    spring AOP拦截方法小示例

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

    springaop拦截controller日志

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

    spring aop 拦截实例

    Spring AOP,全称Aspect-Oriented Programming(面向切面编程),是Spring框架的一个重要组成部分。它提供了一种模块化和声明式的方式来处理系统中的交叉关注点,如日志、事务管理、性能监控等。AOP的核心概念是切面...

    简单spring aop 例子

    3. **创建服务类**:定义一个被切面拦截的服务类,例如`UserService`,包含一个方法`sayHello()`: ```java package com.example.service; public class UserService { public void sayHello(String name) { ...

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

    在我们的例子中,我们将定义一个环绕通知(Around Advice),因为它允许我们在方法调用前后进行控制。使用`@Around`注解定义通知,并传入切入点方法名。 ```java @Around("controllerMethods()") public Object ...

    Spring Aop四个依赖的Jar包

    以上配置创建了一个名为`loggingAspect`的切面,其中定义了三个通知:在方法执行前、正常返回后以及抛出异常后分别调用`logBefore`、`logAfterReturning`和`logAfterThrowing`方法。切点表达式`execution(* ...

    spring MVC AOP注解方式如何拦截controller 例子

    本文将详细介绍如何使用AspectJ注解在Spring MVC中实现AOP拦截Controller方法,并提供一个具体的例子。 首先,我们需要了解Spring AOP的基础概念。AOP允许我们定义“切面”,这些切面包含了业务逻辑中横切关注点的...

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

    代理对象在调用方法时会触发InvocationHandler的invoke()方法,从而可以在这个方法中实现对方法调用的拦截。JDK动态代理要求被代理类必须实现一个接口,代理类会实现相同的接口。 Spring框架中的AOP模块使用了动态...

    spring-aop-jar

    在IT领域,Spring框架是一个广泛使用的Java应用框架,它提供了许多功能,包括依赖注入、面向切面编程(AOP)等。"spring-aop-jar"这个主题涉及到Spring框架中的核心组件之一——Spring AOP。这里我们将深入探讨...

    spring aop日志拦截

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

    spring aop 拦截器简单实现

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

    aop切面拦截单个方法实例

    Spring框架是实现AOP的一个流行工具,它提供了两种主要的AOP实现方式:基于代理的AOP(Proxy-based AOP)和基于注解的AOP(Annotation-based AOP)。 1. **基于代理的AOP** 这种方式是Spring最早提供的AOP支持,它...

    spring_aop_拦截实例

    在Spring AOP中,我们通过定义一个实现了`org.springframework.aop.MethodInterceptor`接口的类来创建自定义拦截器。这个类需要实现`invoke`方法,该方法会在目标方法被调用之前和之后执行。 接下来,我们需要将...

    spring-aop实例

    每种类型的的通知都在不同的时间点执行,例如,环绕通知可以在方法调用前后完全控制执行流程。 3. **切点(Pointcut)**:切点是匹配通知应该应用到的方法或类的定义。切点表达式通常基于方法签名、注解或其他条件...

    springAop与spring定时器

    Spring AOP(面向切面编程)是Spring框架中的一个重要组件,它允许我们在不修改源代码的情况下,通过在程序运行时动态地将代码插入到方法调用中,来实现跨切面的关注点,如日志记录、性能监控、事务管理等。而Spring...

Global site tag (gtag.js) - Google Analytics