java中代理模式 之 jdk动态代理模式

简介:

什么是动态代理

动态代理是一种在运行时创建代理对象的机制,它允许在不修改目标对象代码的情况下,对

目标对象的方法进行增强或拦截。

静态代理与动态代理的对比

静态代理

  • 在编译时就已经确定了代理类和被代理类的关系,需要为每个被代理的类手动创建一个代理类。

  • 当被代理的类较多或者接口方法发生变化时,需要编写大量的代理类代码,维护成本较高。

动态代理

  • 代理类是在运行时动态生成的,无需手动编写代理类代码。
  • 需要指定接口和处理器,就可以在运行时创建代理对象,更加灵活和方便。

动态代理的实现方式

Java 反射机制实现动态代理

在 Java 中,主要有两种基于反射机制实现动态代理的方式:JDK 动态代理和 CGLIB 动态代理。

JDK 动态代理

  • 原理 :JDK 动态代理是基于接口的代理方式,它通过 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口来实现。Proxy 类用于创建代理对象,InvocationHandler 接口用于定义代理对象。

jdk动态代理代码实现:

首先创建一个接口:

javascript 复制代码
public interface Service{
        void add();
        void delete();
        void update();
        void query();
}

创建一个目标对象实现这个接口:

java 复制代码
 
public class ServiceImpl implements Service{
    @Override
    public void add() {
        System.out.println("add...");
    }
 
    @Override
    public void delete() {
        System.out.println("delete...");
    }
 
    @Override
    public void update() {
        System.out.println("update...");
    }
    @Override
    public void query() {
        System.out.println("query...");
    }
}

开始写测试代码

java 复制代码
public class Client {
    public static void main(String[] args) {
        //创建目标对象
        OrderService target = new OrderServiceImpl();
  
        //创建代理对象
        Proxy.newProxyInstance(参数1,参数2,参数3)
    }
}

Proxy.newProxyInstance()参数介绍

注:代理对象底层是jdk自动创建的

参数一:ClassLoader 类加载器(经类加载器运行的类才能在虚拟机上运行),jdk要求

代理对象类加载器必须和目标对象一致,所以要传target.getClass().getClassLoader()

参数二:要传一个接口,就是目标对象实现的接口,所以传target.getClass.getInterfaces()

参数三:InvocationHandle调用处理器,是一个接口,你要对源程序的增强就写在该接口的实

现类里。

因为第三个参数的特殊性,所以我们现在要自己写一个实现类作为第三个参数。

InvocationHandle实现类

java 复制代码
public class InvocationHandleImpl implements InvoCationHandle{
    private Object target;
    public InvocationHandleImpl(Object target){
        this.target = target;
    }

    /**
    *参数1:传进来一个代理对象,不常用    
    *参数2:传入需要调用目标对象的方法
    *参数3:传入目标方法上的实参
    */
    @Override
    public Object invoke( Object Proxy,Method method,Object[] args){
        //这个接口的目的是为了写增强代码
        long begin = System.currentTimeMillis();

        //调用方法
        method.invoke(target,args)

        long end = System.currentTimeMillis();
        System.out.println((end-begin)+"ms");

        //注意这个invoke方法的反回值,如果代理对象调用代理方法之后,需要返回结果的话,invoke方

        法必须将目标方法执行结果继续返回
        return invoke;
    }
}

传参执行代理:

java 复制代码
public class Client {
    public static void main(String[] args) {
        //创建目标对象
        Service target = new ServiceImpl();
  
        //创建代理对象
        Service ServiceProxy = (Service)Proxy.newProxyInstance(target.getClass().getClassLoader(),
                                                        target.getClass().getInterfaces(),
                                                        new InvocationHandleImp(target));
        //调用方法
        ServicePoxy.add();
        ServicePoxy.delete();
        ServicePoxy.update();
        ServicePoxy.query();
    }
}

优缺点:

优点:

1.面向接口编程

2.自动编写代理类,无需手动编写,代码简洁

3.动态性强,继承方便

缺点:

1.只能代理实现接口的类

2.性能开销打

3.维护和调试难度大

相关推荐
向阳2566 分钟前
SpringBoot+vue前后端分离整合sa-token(无cookie登录态 & 详细的登录流程)
java·vue.js·spring boot·后端·sa-token·springboot·登录流程
巷北夜未央12 分钟前
Python每日一题(14)
开发语言·python·算法
XiaoLeisj23 分钟前
【MyBatis】深入解析 MyBatis XML 开发:增删改查操作和方法命名规范、@Param 重命名参数、XML 返回自增主键方法
xml·java·数据库·spring boot·sql·intellij-idea·mybatis
风象南24 分钟前
SpringBoot实现数据库读写分离的3种方案
java·spring boot·后端
振鹏Dong30 分钟前
策略模式——本质是通过Context类来作为中心控制单元,对不同的策略进行调度分配。
java·策略模式
ChinaRainbowSea39 分钟前
3. RabbitMQ 的(Hello World) 和 RabbitMQ 的(Work Queues)工作队列
java·分布式·后端·rabbitmq·ruby·java-rabbitmq
雾月5540 分钟前
LeetCode 914 卡牌分组
java·开发语言·算法·leetcode·职场和发展
Y.O.U..1 小时前
今日八股——C++
开发语言·c++·面试
melck1 小时前
liunx日志查询常用命令总结
java·服务器·网络
守护者1701 小时前
JAVA学习-练习试用Java实现“实现一个Hadoop程序,使用Hive进行复杂查询和数据筛查”
java·学习