• Spring探究-----AOP配置详解


       1.动态代理实现AOP

         JDK的动态代理要使用到一个类 Proxy 用于创建动态代理的对象,一个接口 InvocationHandler用于监听代理对象的行为,

    其实动态代理的本质就是对代理对象行为的监听

    1.1 业务逻辑接口

    package com.spring.aopproxy;
    /**
     * 业务逻辑接口
     * @author yyx
     * 2019年6月12日
     */
    public interface CalculatePrice {
        /**
         * 不打折
         * 
         * @return
         */
        public double calculate(double price);
    
        /**
         * 打折
         * 
         * @return
         */
        public double calculateDiscount(double price);
    }

    1.2 业务逻辑实现

    package com.spring.aopproxy;
    /**
     * 业务逻辑实现
     * @author yyx
     * 2019年6月12日
     */
    public class CalculatePriceImpl implements CalculatePrice {
        @Override
        public double calculate(double price) {
            return price;
        }
    
        @Override
        public double calculateDiscount(double price) {
            return price*0.8;
        }
    }

    1.3 代理对象的工厂类

    package com.spring.aopproxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.Arrays;
    
    public class CalculateProxy {
        // 要代理的对象
        private CalculatePrice target;
    
        public CalculateProxy(CalculatePrice target) {
            super();
            this.target = target;
        }
    
        public CalculatePrice getLogProxy() {
            CalculatePrice proxy = null;
            // 代理对象由哪一个类加载器加载
            ClassLoader loader = target.getClass().getClassLoader();
            // 代理对象的类型,即其中有哪些方法
            Class[] interfaces = new Class[] { CalculatePrice.class };
            // 当调用代理对象其中的方法时,该执行的代码
            InvocationHandler handler = new InvocationHandler() {
                /**
                 * proxy: 正在返回的那个代理对象。 一般情况下,在invoke方法中都不使用该对象 method: 正在被调用的方法 args: 调用方法时传入的参数
                 */
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    String methodName = method.getName();
                    System.out.println("[before] The method " + methodName + " begins with " + Arrays.asList(args));
                    Object result = method.invoke(target, args);
                    System.out.println("[after] The method ends with " + result);
                    return result;
                }
            };
            proxy = (CalculatePrice) Proxy.newProxyInstance(loader, interfaces, handler);
            return proxy;
        }
    }

    1.4 测试类

    package com.spring.aopproxy;
    
    /**
     * 测试类
     * 
     * @author yyx 2019年6月12日
     */
    public class CalculateMain {
        public static void main(String[] args) {
            //多态创建业务逻辑实现类
            CalculatePrice calculatePrice = new CalculatePriceImpl();
            //获得代理对象
            CalculatePrice proxy = new CalculateProxy(calculatePrice).getLogProxy();
            System.out.println(proxy.calculate(500));
            System.out.println(proxy.calculateDiscount(500));
        }
    }

       2.AspectJ注解实现AOP

        需要额外导入的jar包

    com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
    com.springsource.org.aopalliance-1.0.0.jar
    spring-aspects-4.2.1.RELEASE.jar
    spring-aop-4.2.1.RELEASE.jar

    2.1 业务逻辑接口类

    package com.spring.aopannotation;
    
    /**
     * 业务逻辑接口
     * 
     * @author yyx 2019年6月12日
     */
    public interface CalculatePrice {
        /**
         * 不打折
         * 
         * @return
         */
        public double calculate(double price);
    
        /**
         * 打折
         * 
         * @return
         */
        public double calculateDiscount(double price);
    }

    2.2 业务逻辑实现

    package com.spring.aopannotation;
    
    import org.springframework.stereotype.Component;
    
    /**
     * 业务逻辑实现
     * 
     * @author yyx 2019年6月12日
     */
    @Component("calculatePriceImpl")
    public class CalculatePriceImpl implements CalculatePrice {
        @Override
        public double calculate(double price) {
            return price;
        }
    
        @Override
        public double calculateDiscount(double price) {
            return price * 0.8;
        }
    }

    2.3 切面类

    package com.spring.aopannotation;
    
    import java.util.Arrays;
    import java.util.List;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    
    /**
     * 把这个类声明为一个切面:需要把该类放入到IOC容器中@Component,再声明为一个切面
     * 
     * @author yyx 2019年6月18日
     */
    @Aspect
    @Component
    public class CalculateAspect {
        /**
         * 定义一个方法, 用于声明切入点表达式. 一般地, 该方法中再不需要添入其他的代码. 使用 @Pointcut 来声明切入点表达式.
         * 后面的其他通知直接使用方法名来引用当前的切入点表达式.
         */
        @Pointcut("execution(* com.spring.aopannotation.*.*(..))")
        public void declareJointPointExpression() {
        }
    
        /**
         * 声明该方法是一个前置通知:在目标方法开始之前执行 execution(* com.spring.aopannotation.*.*(..))
         * 
         * @param joinpoint
         */
        @Before("execution(public double com.spring.aopannotation.CalculatePrice.*(double))")
        public void beforeMethod(JoinPoint joinpoint) {
            // 获取加入切面的方法名
            String methodName = joinpoint.getSignature().getName();
            // 获取方法参数
            List<Object> args = Arrays.asList(joinpoint.getArgs());
            System.out.println("The method(beforeMethod) " + methodName + " begins " + args);
        }
    
        /**
         * 后置通知:在目标方法执行后(无论是否发生异常),执行的通知 在后置通知中还不能访问目标方法执行的结果
         * 
         * @param joinpoint
         */
        @After("declareJointPointExpression()")
        public void afterMethod(JoinPoint joinpoint) {
            // 获取加入切面的方法名
            String methodName = joinpoint.getSignature().getName();
            System.out.println("The method(afterMethod) " + methodName + " ends ");
        }
    
        /**
         * 返回通知:在方法法正常结束后执行的代码 返回通知是可以访问到方法的返回值的! 异常情况下不能执行
         */
        @AfterReturning(value = "execution(* com.spring.aopannotation.*.*(..))", returning = "result")
        public void afterReturning(JoinPoint joinpoint, Object result) { // 获取加入切面的方法名
            String methodName = joinpoint.getSignature().getName();
            System.out.println("The method(afterReturning) " + methodName + " ends with " + result);
        }
    
        /**
         * 异常通知: 在目标方法出现异常时会执行的代码. 可以访问到异常对象; 且可以指定在出现特定异常时在执行通知代码
         */
        @AfterThrowing(value = "execution(* com.spring.aopannotation.*.*(..))", throwing = "ex")
        public void afterThrowing(JoinPoint joinpoint, Exception ex) { // 获取加入切面的方法名
            String methodName = joinpoint.getSignature().getName();
            System.out.println("The method(afterThrowing) " + methodName + " occurs exception: " + ex);
        }
    
        /**
         * 环绕通知需要携带 ProceedingJoinPoint 类型的参数. 环绕通知类似于动态代理的全过程: ProceedingJoinPoint
         * 类型的参数可以决定是否执行目标方法. 且环绕通知必须有返回值, 返回值即为目标方法的返回值
         */
        @Around("execution(* com.spring.aopannotation.*.*(..))")
        public Object aroundMethod(ProceedingJoinPoint pjd) {
            Object result = null;
            String methodName = pjd.getSignature().getName();
    
            try {
                // 前置通知
                System.out.println("The method(around) " + methodName + " begins with " + Arrays.asList(pjd.getArgs())); // 执行目标方法
                result = pjd.proceed();
                // 返回通知
                System.out.println("The method(around) " + methodName + " ends with " + result);
            } catch (Throwable e) {
                // 异常通知
                System.out.println("The method(around) " + methodName + " occurs exception:" + e);
                throw new RuntimeException(e);
            }
            // 后置通知
            System.out.println("The method(around) " + methodName + " ends");
    
            return result;
        }
    }

    2.4 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:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        <!-- 配置自动扫描的包 -->
        <context:component-scan base-package="com.spring.aopannotation"></context:component-scan>
    
        <!-- 使Aspjectj注解起作用:自动为匹配的类生成代理对象 -->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    </beans>

    2.5 测试类

    package com.spring.aopannotation;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /**
     * 测试类
     * 
     * @author yyx 2019年6月12日
     */
    public class CalculateMain {
        public static void main(String[] args) {
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-Annotation.xml");
            CalculatePrice calculatePrice = (CalculatePrice) applicationContext.getBean("calculatePriceImpl");
            System.out.println(calculatePrice.calculate(250));
            System.out.println("****************************");
            System.out.println(calculatePrice.calculateDiscount(250));
        }
    }

       3.基于XML配置AOP

    3.1 业务逻辑接口

    package com.spring.aopxml;
    /**
     * 业务逻辑接口
     * @author yyx
     * 2019年6月12日
     */
    public interface CalculatePrice {
        /**
         * 不打折
         * 
         * @return
         */
        public double calculate(double price);
    
        /**
         * 打折
         * 
         * @return
         */
        public double calculateDiscount(double price);
    }

    3.2 业务逻辑实现类

    package com.spring.aopxml;
    /**
     * 业务逻辑实现
     * @author yyx
     * 2019年6月12日
     */
    public class CalculatePriceImpl implements CalculatePrice {
        @Override
        public double calculate(double price) {
            return price;
        }
    
        @Override
        public double calculateDiscount(double price) {
            return price*0.8;
        }
    }

    3.3 切面类

    package com.spring.aopxml;
    
    import java.util.Arrays;
    import java.util.List;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    
    /**
     * 
     * @author yyx 2019年6月19日
     */
    public class CalculateAspect {
        public void beforeMethod(JoinPoint joinpoint) {
            // 获取加入切面的方法名
            String methodName = joinpoint.getSignature().getName();
            // 获取方法参数
            List<Object> args = Arrays.asList(joinpoint.getArgs());
            System.out.println("The method(beforeMethod) " + methodName + " begins " + args);
        }
    
        public void afterMethod(JoinPoint joinpoint) {
            // 获取加入切面的方法名
            String methodName = joinpoint.getSignature().getName();
            System.out.println("The method(afterMethod) " + methodName + " ends ");
        }
    
        public void afterReturning(JoinPoint joinpoint, Object result) { // 获取加入切面的方法名
            String methodName = joinpoint.getSignature().getName();
            System.out.println("The method(afterReturning) " + methodName + " ends with " + result);
        }
    
        public void afterThrowing(JoinPoint joinpoint, Exception ex) { // 获取加入切面的方法名
            String methodName = joinpoint.getSignature().getName();
            System.out.println("The method(afterThrowing) " + methodName + " occurs exception: " + ex);
        }
    
        public Object aroundMethod(ProceedingJoinPoint pjd) {
            Object result = null;
            String methodName = pjd.getSignature().getName();
    
            try {
                // 前置通知
                System.out.println("The method(around) " + methodName + " begins with " + Arrays.asList(pjd.getArgs())); // 执行目标方法
                result = pjd.proceed();
                // 返回通知
                System.out.println("The method(around) " + methodName + " ends with " + result);
            } catch (Throwable e) {
                // 异常通知
                System.out.println("The method(around) " + methodName + " occurs exception:" + e);
                throw new RuntimeException(e);
            }
            // 后置通知
            System.out.println("The method(around) " + methodName + " ends");
    
            return result;
        }
    }

    3.4 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:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        <bean id="calculatePriceImpl" class="com.spring.aopxml.CalculatePriceImpl"></bean>
    
        <!-- 配置切面的bean -->
        <bean id="CalculateAspect" class="com.spring.aopxml.CalculateAspect"></bean>
    
        <!-- 配置切面Aop -->
        <aop:config>
            <!-- 配置切点表达式 -->
            <aop:pointcut expression="execution(* com.spring.aopxml.*.*(..))"
                id="pointcut" />
            <aop:aspect ref="CalculateAspect">
                <aop:before method="beforeMethod" pointcut-ref="pointcut" />
                <aop:after method="afterMethod" pointcut-ref="pointcut" />
                <!-- throwing="ex" returning="result"要和方法参数对应 -->
                <aop:after-throwing method="afterThrowing"
                    pointcut-ref="pointcut" throwing="ex" />
                <aop:after-returning method="afterReturning"
                    pointcut-ref="pointcut" returning="result" />
                <aop:around method="aroundMethod" pointcut-ref="pointcut" />
            </aop:aspect>
        </aop:config>
    </beans>

    3.5 测试类

    package com.spring.aopxml;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /**
     * 测试类
     * 
     * @author yyx 2019年6月12日
     */
    public class CalculateMain {
        public static void main(String[] args) {
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-Aop.xml");
            CalculatePrice calculatePrice = (CalculatePrice) applicationContext.getBean("calculatePriceImpl");
            System.out.println(calculatePrice.calculate(250));
            System.out.println("****************************");
            System.out.println(calculatePrice.calculateDiscount(250));
        }
    }
  • 相关阅读:
    codis安装手册
    引用对象的使用和易产生bug的示例
    shallow copy 和 deep copy 的示例
    [转载] 公知其实就是正常人嘛
    Spring GET请求实体中日期的转换
    [转载] 方方: 借陸遊三個字:錯,錯,錯(3月16日)
    [转载] 英国防疫怪招
    [记录] Disruptor 介绍
    [记录] 重要网址备忘
    [转载] 面对新冠病毒在全球的大流行,我们如何自保?
  • 原文地址:https://www.cnblogs.com/fengfuwanliu/p/10994856.html
Copyright © 2020-2023  润新知