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));
    }
}
原文地址:https://www.cnblogs.com/fengfuwanliu/p/10994856.html