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
分享到:
相关推荐
在上述代码中,我们定义了一个名为`SpringAopLog`的切面类,并通过注解指定了哪些方法会在目标方法执行前后被调用。在`afterReturn`方法中,根据不同的方法名来记录不同的日志信息。 #### 四、总结 通过Spring AOP...
标题中的“在自定义Spring AOP中使用EL获取拦截方法的变量值”指的是在Spring的面向切面编程(AOP)中,通过Expression Language(EL,表达式语言)来访问被拦截方法的局部变量值。这通常涉及到Spring的代理机制、...
即使你没有直接使用AspectJ语法编写切面,Spring的AOP代理也可以利用这个库进行代理对象的创建,以实现方法调用前后的通知(advises)。这个库对于那些希望在不改变源代码的情况下,通过AOP增强已有类的行为的开发者...
`Enhancer` 是 CGLIB 的核心类,用于创建代理对象,而 `Callback` 是一个回调接口,它定义了代理对象在方法调用时需要执行的操作。在 Spring AOP 中,`ObjenesisCglibAopProxy` 类负责使用 CGLIB 创建代理对象,它会...
例如,可能会有一个自定义的MyBatis拦截器用于分页查询,一个Spring AOP切面用于记录操作日志,Spring事务管理确保数据的一致性,而反射工具类可能用于动态加载配置或处理某些通用的反射任务。通过这些组件的组合,...
这个“spring AOP拦截方法小示例”是一个实际应用,展示了如何使用Spring AOP来拦截特定层的所有方法,并在调用前后以及出现异常时执行自定义逻辑。 首先,让我们了解AOP的基本概念。AOP的核心是切面(Aspect),它...
"springaop拦截controller日志"这个主题旨在讲解如何使用Spring AOP来拦截Controller层的方法调用,并在方法执行前后记录相关日志。 首先,了解Spring AOP的基本概念。AOP是一种编程范式,它允许程序员定义“切面”...
Spring AOP,全称Aspect-Oriented Programming(面向切面编程),是Spring框架的一个重要组成部分。它提供了一种模块化和声明式的方式来处理系统中的交叉关注点,如日志、事务管理、性能监控等。AOP的核心概念是切面...
3. **创建服务类**:定义一个被切面拦截的服务类,例如`UserService`,包含一个方法`sayHello()`: ```java package com.example.service; public class UserService { public void sayHello(String name) { ...
在我们的例子中,我们将定义一个环绕通知(Around Advice),因为它允许我们在方法调用前后进行控制。使用`@Around`注解定义通知,并传入切入点方法名。 ```java @Around("controllerMethods()") public Object ...
以上配置创建了一个名为`loggingAspect`的切面,其中定义了三个通知:在方法执行前、正常返回后以及抛出异常后分别调用`logBefore`、`logAfterReturning`和`logAfterThrowing`方法。切点表达式`execution(* ...
本文将详细介绍如何使用AspectJ注解在Spring MVC中实现AOP拦截Controller方法,并提供一个具体的例子。 首先,我们需要了解Spring AOP的基础概念。AOP允许我们定义“切面”,这些切面包含了业务逻辑中横切关注点的...
代理对象在调用方法时会触发InvocationHandler的invoke()方法,从而可以在这个方法中实现对方法调用的拦截。JDK动态代理要求被代理类必须实现一个接口,代理类会实现相同的接口。 Spring框架中的AOP模块使用了动态...
在IT领域,Spring框架是一个广泛使用的Java应用框架,它提供了许多功能,包括依赖注入、面向切面编程(AOP)等。"spring-aop-jar"这个主题涉及到Spring框架中的核心组件之一——Spring AOP。这里我们将深入探讨...
在Spring MVC框架中,AOP(面向切面编程)是一种强大的工具,用于实现日志拦截,特别是对于controller层的操作。AOP允许我们定义横切关注点,这些关注点可以是如日志记录、事务管理、权限检查等通用功能,它们在程序...
它是一个实现了`org.springframework.aop.MethodBeforeAdvice`、`org.springframework.aop.AfterReturningAdvice`或`org.springframework.aop.ThrowsAdvice`等接口的对象,可以在方法调用前后执行自定义逻辑。...
Spring框架是实现AOP的一个流行工具,它提供了两种主要的AOP实现方式:基于代理的AOP(Proxy-based AOP)和基于注解的AOP(Annotation-based AOP)。 1. **基于代理的AOP** 这种方式是Spring最早提供的AOP支持,它...
在Spring AOP中,我们通过定义一个实现了`org.springframework.aop.MethodInterceptor`接口的类来创建自定义拦截器。这个类需要实现`invoke`方法,该方法会在目标方法被调用之前和之后执行。 接下来,我们需要将...
每种类型的的通知都在不同的时间点执行,例如,环绕通知可以在方法调用前后完全控制执行流程。 3. **切点(Pointcut)**:切点是匹配通知应该应用到的方法或类的定义。切点表达式通常基于方法签名、注解或其他条件...
Spring AOP(面向切面编程)是Spring框架中的一个重要组件,它允许我们在不修改源代码的情况下,通过在程序运行时动态地将代码插入到方法调用中,来实现跨切面的关注点,如日志记录、性能监控、事务管理等。而Spring...