自学内容网 自学内容网

AOP基础-动态代理

1.动态代理

1.需求分析

image-20240219204601816

2.动态代理的核心

动态代理主要用于对实现了接口的对象的方法调用前后进行拦截,以执行一些额外的操作,那么就要对这个接口进行动态代理

如安全检查、日志记录、事务处理等,而不需要修改原有类的代码。

3.代码实例
1.Vehicle.java
package com.sxs.spring.proxy;

/**
 * @author 孙显圣
 * @version 1.0
 */
public interface Vehicle {
    public void run();
}

2.Car.java
package com.sxs.spring.proxy;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class Car implements Vehicle{
    @Override
    public void run() {
        System.out.println("小汽车在路上running。。。。。。");
    }
}

3.Ship.java
package com.sxs.spring.proxy;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class Ship implements Vehicle {
    @Override
    public void run() {
        System.out.println("大轮船在路上running。。。。。。");
    }
}

4.VehicleProxyProvider.java(动态代理模板)
package com.sxs.spring.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class VehicleProxyProvider {
    //1.一个接口属性,需要使用构造方法传入实现接口的目标对象
    private Vehicle target_vehicle;

    public VehicleProxyProvider(Vehicle target_vehicle) {
        this.target_vehicle = target_vehicle;
    }

    //2.编写方法,使用Java的Proxy类动态创建并返回目标对象的代理对象
    public Vehicle getProxy() {
        //类加载器和接口信息都使用目标对象反射获取即可
        ClassLoader classLoader = target_vehicle.getClass().getClassLoader();
        Class<?>[] interfaces = target_vehicle.getClass().getInterfaces();
        //4.匿名内部类实现接口,返回对象
        InvocationHandler invocationHandler = new InvocationHandler() {
            /**
             * 这个方法是在通过代理对象调用任何接口方法时被自动调用的。它允许在调用目标对象的方法前后执行自定义逻辑
             * @param proxy 代理对象
             * @param method 代理对象要调用的那个方法
             * @param args 方法的参数
             * @return 执行invoke方法后的结果
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //方法前的额外操作
                System.out.println("交通工具开始运行了。。。。。。");
                //调用方法
                Object result = method.invoke(target_vehicle, args);
                //方法后的额外操作
                System.out.println("交通工具停止运行了。。。。。。");
                return result;
            }
        };
        /**
         *     public static Object newProxyInstance(
         *     ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
         *     这个方法有三个参数
         *     ClassLoader loader:用于定义代理类的类加载器(一般使用目标对象的类加载器)
         *     Class<?>[] interfaces:代理类需要实现的接口列表,这使得代理对象可以被安全地转换为这些接口中的任何一个
         *     InvocationHandler h:InvocationHandler接口的实现类(使用匿名内部类传入)
         */
        //3.使用Proxy.newProxyInstance来返回代理对象
        Vehicle proxy = (Vehicle) Proxy.newProxyInstance(classLoader,
                interfaces, invocationHandler);
        return proxy;
    }
}

5.测试使用
package com.sxs.spring.proxy;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class Test {

    @org.junit.jupiter.api.Test
    public void proxy() {
        Vehicle vehicle = new Ship();
        //创建代理类的实例,传入实现了接口的目标对象
        VehicleProxyProvider vehicleProxyProvider = new VehicleProxyProvider(vehicle);
        //获取代理对象
        Vehicle proxy = vehicleProxyProvider.getProxy();
        //使用代理对象执行方法
        proxy.run();
    }
}

image-20240219212314525

2.动态代理深入—横切关注点

1.需求分析

image-20240220092730232

2.四个横切关注点
  • 前置通知
  • 返回通知
  • 异常通知
  • 最终通知
3.代码实例
1.Cal.java
package com.sxs.spring.proxy;

/**
 * 计算数量的接口
 *
 * @author 孙显圣
 * @version 1.0
 */
public interface Cal {
    public double getSub(double num1, double num2);
    public double getSum(double num1, double num2);
}

2.CalImpl.java
package com.sxs.spring.proxy;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class CalImpl implements Cal{
    @Override
    public double getSub(double num1, double num2) {
        System.out.println("方法内部打印:" + (num1 - num2));
        return num1 - num2;
    }

    @Override
    public double getSum(double num1, double num2) {
        System.out.println("方法内部打印:" + (num1 + num2));
        return num1 + num2;
    }
}

3.VehicleProxyProvider02.java
package com.sxs.spring.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class VehicleProxyProvider02 {
    //1.传入目标对象
    private Cal cal;

    public VehicleProxyProvider02(Cal cal) {
        this.cal = cal;
    }

    //2.编写方法获取动态代理对象
    public Cal getProxy() {
        //获取类加载器
        ClassLoader classLoader = cal.getClass().getClassLoader();
        //获取接口信息
        Class<?>[] interfaces = cal.getClass().getInterfaces();
        //4.匿名内部类实现接口返回对象
        InvocationHandler invocationHandler = new InvocationHandler() {
            Object result = null;
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                try {
                    System.out.println("方法执行开始-日志-方法名-" + method.getName()
                            + "-参数" + Arrays.asList(args)); //1.横切关注点-前置通知
                    result = method.invoke(cal, args);
                    System.out.println("方法执行正常结束-日志-方法名-" + method.getName()
                            + "-结果-result=" + result); //2.横切关注点-返回通知
                } catch (Exception e) {
                    System.out.println("方法出现异常-日志-方法名-" + method.getName()
                    + "-异常类型=" + e.getClass().getName()); //3.横切关注点-异常通知
                } finally {
                    System.out.println("方法最终结束-日志-方法名-" +
                            method.getName()); //4.横切关注点-最终通知
                    return result; //返回方法的执行结果
                }
            }
        };
        //3.返回动态代理对象
        Cal proxy = (Cal) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        return proxy; //返回动态代理对象
    }
}

4.测试
    @org.junit.jupiter.api.Test
    public void VehicleProxyProvider02Test() {
        CalImpl cal = new CalImpl();
        VehicleProxyProvider02 vehicleProxyProvider02 = new VehicleProxyProvider02(cal);
        Cal proxy = vehicleProxyProvider02.getProxy();
        proxy.getSub(3,1);
        System.out.println("===========================================");
        proxy.getSum(2,4);
    }

image-20240220100957232

3.AOP问题引出

1.问题提出

image-20240220101224618

2.土方法解决
修改VehicleProxyProvider02.java
package com.sxs.spring.proxy03;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class VehicleProxyProvider02 {
    //1.传入目标对象
    private Cal cal;

    public VehicleProxyProvider02(Cal cal) {
        this.cal = cal;
    }

    public void before(Method method, Object[] args) {
        System.out.println("方法执行开始-日志-方法名-" + method.getName()
                + "-参数" + Arrays.asList(args)); //1.横切关注点-前置通知
    }
    public void after(Method method, Object result) {
        System.out.println("方法执行正常结束-日志-方法名-" + method.getName()
                + "-结果-result=" + result); //2.横切关注点-返回通知
    }

    //2.编写方法获取动态代理对象
    public Cal getProxy() {
        //获取类加载器
        ClassLoader classLoader = cal.getClass().getClassLoader();
        //获取接口信息
        Class<?>[] interfaces = cal.getClass().getInterfaces();
        //4.匿名内部类实现接口返回对象
        InvocationHandler invocationHandler = new InvocationHandler() {
            Object result = null;
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                try {
                    before(method, args);
                    result = method.invoke(cal, args);
                    after(method, result);
                } catch (Exception e) {
                    System.out.println("方法出现异常-日志-方法名-" + method.getName()
                    + "-异常类型=" + e.getClass().getName()); //3.横切关注点-异常通知
                } finally {
                    System.out.println("方法最终结束-日志-方法名-" +
                            method.getName()); //4.横切关注点-最终通知
                    return result; //返回方法的执行结果
                }
            }
        };
        //3.返回动态代理对象
        Cal proxy = (Cal) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        return proxy; //返回动态代理对象
    }
}

3.极简AOP
1.SunAOP.java
package com.sxs.spring.proxy03;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class SunAOP {
    public static void before(Method method, Object[] args) {
        System.out.println("方法执行开始-日志-方法名-" + method.getName()
                + "-参数" + Arrays.asList(args)); //1.横切关注点-前置通知
    }

    public static void after(Method method, Object result) {
        System.out.println("方法执行正常结束-日志-方法名-" + method.getName()
                + "-结果-result=" + result); //2.横切关注点-返回通知
    }
}

2.修改VehicleProxyProvider02.java

image-20240220102615893


原文地址:https://blog.csdn.net/m0_64637029/article/details/138014295

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!