【关于Spring那些事】——带你了解Spring AOP的代理模式

一、静态代理

静态代理,代理类和被代理的类实现了同样的接口,只能代理特定的类。

  1. 定义一个接口
public interface Service {
    
    
    public void delete();
    public void update();
    public void insert();
}
  1. 被代理类
public class StudentServiceImpl implements Service {
    
    
    @Override
    public void delete() {
    
    
        System.out.println("删除学生信息!!!");
    }

    @Override
    public void update() {
    
    
        System.out.println("修改学生信息!!!");
    }

    @Override
    public void insert() {
    
    
        System.out.println("添加学生信息!!!");
    }
}
  1. 代理类
public class StaticProxy implements Service {
    
    

    private Service service;

    public StaticProxy(Service service) {
    
    
        this.service = service;
    }

    public void delete() {
    
    
        open();
        service.delete();
        commit();
    }

    public void update() {
    
    
        open();
        service.update();
        commit();
    }

    public void insert() {
    
    
        open();
        service.insert();
        commit();
    }

    public void open(){
    
    
        System.out.println("开启事务!!!");
    }
    public void commit(){
    
    
        System.out.println("提交事务!!!");
    }

}

4.测试类

public class Test {
    
    
    public static void main(String[] args) {
    
    
        //被代理类
        StudentServiceImpl student = new StudentServiceImpl();
        //被代理类的代理对象
        StaticProxy proxy = new StaticProxy(student);
        //通过代理对象调用被代理类的方法
        proxy.delete();
    }
}

运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1tskzJql-1650096958348)(img_1.png)]

被代理类只需负责自己特定的业务,而代理类则负责业务的扩展,比如执行被代理类的方法前要开启事务,执行之后要提交事务,我们就不需要给每个方法都添加开启事务和提交事务。
代理类就会负责完成这些工作。

静态代理的优缺点:

  1. 优点:
  • 被代理类只需负责核心业务
  • 业务逻辑的扩展更加方便
  • 通用代码放到代理类中,提高了代码的复用性
  1. 缺点:
  • 被代理类太多,就会导致工作量变大,开发效率降低

二、动态代理

动态代理,由AOP框架动态生成的一的对象,对象可以作为目标对象使用。
动态代理有两种方式:

  • JDK动态代理
  • CGLIB代理

2.1 JDK动态代理

基于接口的动态代理,只能为实现了接口的类动态代理对象

  • 创建一个接口并创建一个它的实现类并重写它的方法。
  • 创建一个类实现InvocationHandler接口,并重写invoke方法
public class JdkDynamicProxy implements InvocationHandler {
    
    
    //被代理的对象
    private Object object;

    public JdkDynamicProxy(Object object) {
    
    
        this.object = object;
    }
    //产生代理对象,返回代理对象
    public Object getProxy(){
    
    
        //1.获取被代理对象的类加载器
        ClassLoader classLoader = object.getClass().getClassLoader();
        //2.获取被代理对象实现的所有接口
        Class<?>[] interfaces = object.getClass().getInterfaces();
        //3.创建代理对象
        //classloader:类加载器来定义代理类
        //interfaces:代理类实现的接口列表
        //this:调度方法调用的调用处理函数
        Object o = Proxy.newProxyInstance(classLoader, interfaces,this);
        return o;
    }
    //处理代理实例,返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        log(method.getName());
        Object invoke = method.invoke(object,args);
        return invoke;
    }
    //定义一个打印日志的方法
    public void log(String msg){
    
    
        System.out.println("执行了"+ msg +"方法!");
    }
}
  • 测试
public class DynamicProxyTest {
    
    
    public static void main(String[] args) {
    
    
        //创建被代理类对象
        StudentServiceImpl studentService = new StudentServiceImpl();
        //创建代理对象,产生的代理对象可以强转成被代理对象实现的接口类型
        JdkDynamicProxy jdkDynamicProxy = new JdkDynamicProxy(studentService);
        Service proxy = (Service) jdkDynamicProxy.getProxy();
        //使用代理对象调方法,不会执行调用的方法,而是进入到创建代理对象时指定的invoke方法
        //调用的方法作为一个参数,传给invoke方法
        proxy.delete();
    }
}

运行结果:
在这里插入图片描述

2.2 CGLib代理

使用JDK动态代理的对象必须是实现了一个或多个接口的,如果要对没有实现接口的类创建代理对象,就要使用CGLIB代理。
基于类的动态代理—CGlib

  • CGLib是一个高性能开源的代码生成包,因在Spring的核心包中已包含CGLib所需要的包,所以不再需要添加依赖。
  • 创建一个StudentServiceImpl 类,并添加增删改方法。
  • 创建一个类,实现MethodInterceptor接口,并重写intercept方法。
/**
 * CGLIB代理
 */
public class CGLibDynamicProxy implements MethodInterceptor {
    
    

    private Object object;

    public CGLibDynamicProxy(Object object) {
    
    
        this.object = object;
    }
    //创建并返回代理对象
    //该代理对象是通过被代理类的子类来创建的
    public Object getProxy(){
    
    
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(object.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    
    
        log(method.getName());
        Object invoke = method.invoke(object, args);
        return invoke;
    }

    //定义一个打印日志的方法
    public void log(String msg){
    
    
        System.out.println("执行了"+ msg +"方法!");
    }
}
  • 测试
public class DynamicProxyTest {
    
    
    public static void main(String[] args) {
    
    
        //创建被代理类对象
        StudentServiceImpl studentService = new StudentServiceImpl();
        //创建代理对象,产生的代理对象可以强转成被代理类类型
        CGLibDynamicProxy cgLibDynamicProxy = new CGLibDynamicProxy(studentService);
        StudentServiceImpl proxy = (StudentServiceImpl) cgLibDynamicProxy.getProxy();
        //使用代理对象调方法,不会执行调用的方法,而是进入到创建代理对象时指定的intercept方法
        //将调用的方法以及方法中的参数传给intercept方法
        proxy.insert();
    }
}

运行结果:
在这里插入图片描述
动态代理的优点:

  • 被代理类只需负责核心业务;
  • 业务逻辑的扩展更加方便;
  • 通用代码放到代理类中,提高了代码的复用性;
  • 一个动态代理 , 一般代理某一类业务;
  • 一个动态代理可以代理多个类,代理的是接口。

猜你喜欢

转载自blog.csdn.net/weixin_52986315/article/details/124215461