Spring AOP 之代理模式

一、静态代理

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

  1. 定义一个接口

    public interface Service {
     public void delete();
     public void update();
     public void insert();
    }
  2. 被代理类

    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("添加学生信息!!!");
     }
    }
  3. 代理类

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();
    }
}

运行结果:

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

静态代理的优缺点:

  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();
      }
    }

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

  • 被代理类只需负责核心业务;

  • 业务逻辑的扩展更加方便;

  • 通用代码放到代理类中,提高了代码的复用性;

  • 一个动态代理 , 一般代理某一类业务;

  • 一个动态代理可以代理多个类,代理的是接口。

全部评论
感谢学霸的分享呀
点赞
送花
回复
分享
发布于 2022-10-23 12:02 陕西

相关推荐

头像
不愿透露姓名的神秘牛友
05-29 11:22
点赞 评论 收藏
转发
3 4 评论
分享
牛客网
牛客企业服务