代码
applicationContext.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="aop"/>
<aop:aspectj-autoproxy />
</beans>
日志切面
@Aspect
@Service
public class LogAspect {
/**
* Pointcut
* 定义Pointcut,Pointcut的名称为aspectjMethod(),此方法没有返回值和参数
* 该方法就是一个标识,不进行调用
*/
@Pointcut("execution(* aop.ServiceA.*(..))")
private void aspectjMethod() {
}
@Around(value = "aspectjMethod()")
public void aroundAdvice(ProceedingJoinPoint pjp) throws ServiceException {
try {
System.out.println("记录日志开始!!!!");
pjp.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
}
service
@Service
public class ServiceA {
protected void methodA() {
System.out.println("A");
}
protected void methodB() {
System.out.println("B");
}
protected void methodC() {
System.out.println("C");
}
}
测试
public class Test {
public static void main(String[] args) {
//启动Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取service组件
ServiceA service = (ServiceA) context.getBean("serviceA");
//以普通的方式调用UserService对象的三个方法
service.methodA();
}
}
问题
代理protected方法
<aop:aspectj-autoproxy />没有接口默认使用的CGLib动态代理技术织入增强,按照这个切点@Pointcut("execution(* aop.ServiceA.*(..))"),protected方法应该被代理。
**运行结果:**
A
没有被代理,这个什么问题呢?
如果将其中一个方法改为public呢?
**运行结果:**
记录日志开始!!!!
A
这个时候怎么又被代理了?
问题分析
public static boolean canApply(Pointcut pc, Class targetClass, boolean hasIntroductions) {
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set classes = new HashSet(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
for (Iterator it = classes.iterator(); it.hasNext();) {
Class clazz = (Class) it.next();
Method[] methods = clazz.getMethods();
for (int j = 0; j < methods.length; j++) {
if ((introductionAwareMethodMatcher != null &&
introductionAwareMethodMatcher.matches(methods[j], targetClass, hasIntroductions)) ||
methodMatcher.matches(methods[j], targetClass)) {
return true;
}
}
}
return false;
}
Method[] methods = clazz.getMethods();只能拿到public方法。所以只能带有有public方法的类。
@Transactional
在使用代理的时候,@Transactional 注解应该只被应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,系统也不会报错, 但是这个被注解的方法将不会执行已配置的事务设置。
方法中嵌套方法代理失效
问题描述
public void methodA() {
System.out.println("A");
methodB();
}
按道理说应该输出:
记录日志开始!!!!
A
记录日志开始!!!!
B
**运行结果:**
记录日志开始!!!!
A
B
methodB();没有被代理
问题分析
我们使用AOP进行代理,当执行proxy类的a方法时,会进行拦截(开启事物),紧接着逻辑走到target类上a方法,而后调用target类的b方法。此时需要明白,它调用的是target类上的b方法,而不是proxy类的b方法。要知道,针对方法b的横切逻辑,只植入到了proxy类上的方法b中。所以target类的a方法中所调用的b方法没有开启事物。
网友评论