美文网首页
SpringAOP代理问题

SpringAOP代理问题

作者: 忘净空 | 来源:发表于2016-10-29 09:37 被阅读84次

代码

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方法没有开启事物。

问题解决

http://jinnianshilongnian.iteye.com/blog/1487235

相关文章

  • SpringAOP代理问题

    代码 applicationContext.xml 日志切面 service 测试 问题 代理protected方...

  • spring框架 AOP

    10、 代理模式 为什么要学习代理模式?因为这就是SpringAOP的底层!【SpringAOP 和 Spring...

  • Spring AOP 一

    上一篇讲了jdk动态代理,下面我们来说说SpringAOP。SpringAOP是基于动态代理的,它对动态代理又做了...

  • 面试系列~动态代理实现与原理

    动态代理有JDK动态代理, CGLIB动态代理, SpringAOP动态代理 一,JDK动态代理  jdk动态代理...

  • SpringAOP-jdk动态代理

    静态代理与动态代理 静态代理(如SpringAOP-代理模式中所示)的缺点代理目标的方法越多,代理所委托的方法就越...

  • 10月4号学习情况

    今日 学习情况 看了enum枚举的用法 看了springAOP的概念 解决了昨天出现的问题 熟悉了代理模式的概念 ...

  • 代理模式

    代理模式的典型就是springAOP代理模式的目的有两个:保护目标对象,增强目标对象分类:静态代理和动态代理。 静...

  • Spring_AOP_02——实现原理

    本文主要讲实现AOP的 代理模式原理,以及静态代理,动态代理的区别和具体实现。 对SpringAOP的概念和使用,...

  • Spring学习(五)AOP

    SpringAop使用到了了动态代理模式(有关设计模式见设计模式章节)。JDK动态代理代理的目标类必须要实现接口。...

  • JVM_字节码:字节码层面看看动态代理

    SpringAop是基于动态代理的,主要有2种方式:JDK的动态代理,CGLIB的代理,增加织入的功能。 JDK动...

网友评论

      本文标题:SpringAOP代理问题

      本文链接:https://www.haomeiwen.com/subject/wexeuttx.html