美文网首页
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代理问题

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