Spring AOP

一、代理

public interface Calculator {
    //加
    int add(int a, int b);
    //减
    int sub(int a, int b);
    //乘
    int mul(int a, int b);
    //除
    int div(int a, int b);
}

1.1 静态代理

public class CalculatorImpl implements Calculator {
    @Override
    public int add(int a, int b) {
        int res = a+b;
        System.out.println("方法内部 result = " + res);
        return res;

    }

    @Override
    public int sub(int a, int b) {
        int res = a-b;
        System.out.println("方法内部 result = " + res);
        return res;
    }

    @Override
    public int mul(int a, int b) {
        int res = a*b;
        System.out.println("方法内部 result = " + res);
        return res;
    }

    @Override
    public int div(int a, int b) {
        int res = a/b;
        System.out.println("方法内部 result = " + res);
        return res;
    }
}
public class CalProxy implements Calculator {

    //把被代理目标对象传递进来
    private Calculator calculator;

    public CalProxy(Calculator calculator) {
        this.calculator = calculator;
    }

    @Override
    public int add(int a, int b) {
        System.out.println("[日志] add 方法开始了,参数是:"+a+","+b);
        int result = calculator.add(a,b);
        System.out.println("[日志] add 方法结束了,返回值是:"+result);
        return result;
    }

    @Override
    public int sub(int a, int b) {
        System.out.println("[日志] sub 方法开始了,参数是:"+a+","+b);
        int result = calculator.sub(a,b);
        System.out.println("[日志] sub 方法结束了,返回值是:"+result);
        return result;
    }

    @Override
    public int mul(int a, int b) {
        System.out.println("[日志] mul 方法开始了,参数是:"+a+","+b);
        int result = calculator.mul(a,b);
        System.out.println("[日志] mul 方法结束了,返回值是:"+result);
        return result;
    }

    @Override
    public int div(int a, int b) {
        System.out.println("[日志] div 方法开始了,参数是:"+a+","+b);
        int result = calculator.div(a,b);
        System.out.println("[日志] div 方法结束了,返回值是:"+result);
        return result;
    }
}

 1.2 动态代理

/*动态代理*/
public class ProxyFactory {
    //目标对象
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    //返回代理对象
    public Object getProxy(){
        /*
        * 三个参数
        * 1.classLoader加载动态生成代理类的类加载器
        * 2.interface目标对象实现的所有接口的class类型数组
        * 3.handler设置代理对象实现目标对象方法的过程
        * */
        ClassLoader classLoader = target.getClass().getClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        InvocationHandler handler = new InvocationHandler(){
            /*
            * proxy:代理对象
            * method:需要重写目标对象的方法
            * args:方法的参数
            * */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //调用方法前日志的输出
                System.out.println("[动态代理][日志]:" + method.getName() + ",参数:" + Arrays.toString(args));
                //调用目标的方法
                Object res = method.invoke(target, args);
                //调用方法后日志的输出
                System.out.println("[动态代理][日志]:" + method.getName() + ",结果:" + res);
                return res;
            }
        };
        return Proxy.newProxyInstance(classLoader, interfaces, handler);
    }
}

测试

    @Test
    public void test(){
        //1.创建动态代理对象
        ProxyFactory proxyFactory = new ProxyFactory(new CalculatorImpl());
        Calculator proxy = (Calculator) proxyFactory.getProxy();
        proxy.add(3,5);
    }

二、AOP

通过预编译方式和运行期动态代理方式实现,在不修改源代码的情况下,给程序动态统一添加额外功能的一种技术。

jdk动态代理和cglib动态代理:

        有接口使用jdk代理,生成接口实现类代理对象--代理对象和目标对象实现同样的接口

        没有接口使用cglib代理,生成子类代理对象---通过继承被代理的目标类

2.1 添加依赖

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>6.0.2</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>6.0.2</version>
    </dependency>

2.2 Calculate接口和实现类

public interface Calculator {
    //加
    int add(int a, int b);
    //减
    int sub(int a, int b);
    //乘
    int mul(int a, int b);
    //除
    int div(int a, int b);
}
public class CalculatorImpl implements Calculator {
    @Override
    public int add(int a, int b) {
        int res = a+b;
        System.out.println("方法内部 result = " + res);
        return res;

    }

    @Override
    public int sub(int a, int b) {
        int res = a-b;
        System.out.println("方法内部 result = " + res);
        return res;
    }

    @Override
    public int mul(int a, int b) {
        int res = a*b;
        System.out.println("方法内部 result = " + res);
        return res;
    }

    @Override
    public int div(int a, int b) {
        int res = a/b;
        System.out.println("方法内部 result = " + res);
        return res;
    }
}

 2.3 创建切面类

配置文件

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--开启组件扫描,要扫描的包名写的越具体越好,因为越具体扫描花费的时间越少-->
    <context:component-scan base-package="com.hait"/>
    <!--开启Aspectj自动代理,为目标对象生成代理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

切面类 

@Aspect //切面类
@Component //ioC容器
public class LogAspect {
    //设置切入点和通知类型
    //1.通知类型:
    // 前置@Before(value="execution(权限修饰符  方法返回值  增强方法的全类名.方法名(参数类型))")
    //* com.hait.dao.impl.CalculatorImpl.*(..)表示包中的所有类的所有方法任意参数类型
    @Before(value = "execution(* com.hait.dao.impl.*.*(..))")
    public void beforeMethod(JoinPoint joinPoint){
        String method = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        System.out.println("Logger-->前置通知,方法名:"+method+"参数:"+ Arrays.toString(args));
    }
    // 返回@AfterReturning()
    @AfterReturning(value = "execution(* com.hait.dao.impl.*.*(..))",returning = "res")
    public void afterReturning(JoinPoint joinPoint,Object res){
        String method = joinPoint.getSignature().getName();
        System.out.println("Logger-->返回通知,方法名:"+method+",返回值:"+res);
    }
    // 异常@AfterThrowing()---目标方法出现异常时执行
    @AfterThrowing(value = "execution(* com.hait.dao.impl.*.*(..))",throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint,Exception ex){
        String method = joinPoint.getSignature().getName();
        System.out.println("Logger-->异常通知,方法名:"+method+",异常:"+ex);
    }

    // 后置@After()
    @After(value = "execution(* com.hait.dao.impl.*.*(..))")
    public void afterMethod(JoinPoint joinPoint){
        String method = joinPoint.getSignature().getName();
        System.out.println("Logger-->后置通知,方法名:"+method);
    }
    // 环绕@Around()
    @Around(value = "execution(* com.hait.dao.impl.*.*(..))")
    public Object aroundMethod(ProceedingJoinPoint joinPoint){
        String method = joinPoint.getSignature().getName();
        String args = joinPoint.getArgs().toString();

        System.out.println("Logger-->环绕通知,方法名:"+method);
        Object res = null;
        try {
            System.out.println("Logger-->环绕通知----目标方法之前执行");
            //调用目标方法
            res = joinPoint.proceed();

            System.out.println("Logger-->环绕通知----目标方法之后执行");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("Logger-->环绕通知----目标方法出现异常执行");
        }finally {
            System.out.println("Logger-->环绕通知----目标方法执行完毕执行");
        }
        return res;
    }

}

 测试

    @Test
    public void test02() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        Calculator calculator = ac.getBean(Calculator.class);
        calculator.div(3, 0);
    }

 没有异常的话

三、重用切入点表达式

    //重用切入点表达式
    @Pointcut(value = "execution(* com.hait.dao.impl.*.*(..))")
    public void pointCut(){

    }

    // 后置@After()
    /*如果pointCut方法不在本类中,那么value的值是方法的全路径
     *@After(value = "com.hait.annoaop.LogAspect.pointCut()")
     */
    @After(value = "pointCut()")
    public void afterMethod(JoinPoint joinPoint){
        String method = joinPoint.getSignature().getName();
        System.out.println("Logger-->后置通知,方法名:"+method);
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尢词

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值