动态代理
发布日期:2021-05-07 23:14:12 浏览次数:22 分类:原创文章

本文共 5455 字,大约阅读时间需要 18 分钟。

Java的代理模式


提示:以下是本篇文章正文内容,下面案例可供参考

一、什么是代理以及代理模式的作用?

代理就好比我们的代购,比如我们想要在美国的商家买一双球鞋,但是我们不能够直接去美国买,于是我就可以向代购买,代购将从美国买回来的鞋子卖给我们,并且获得利益.

在java中就是类A想要调用类C的方法,但是没有权限来访问类C,但是B有权限访问类C,我们就可以通过调用类B的方法来访问类C,那么类B就是我们所说的代理类.
代理模式的作用就是:

   1.控制访问  即类B有权限访问类C, 例子中就是代购可以去美国买球鞋,但是我们不能   2.增强功能   即类B调用了类C的方法,在此基础之上还能增加自己想要的功能,例子中就是代购买了球鞋,可以增加球鞋的价格               来卖给我们,进而获取利益

二、静态代理

1. 定义业务接口

定义业务接口 ShoeSell(目标接口),其中含有抽象方法 sell(int amount), sell 是目标方法

代码如下(示例):

package jmu.czx.service;public interface ShoeShell {       //定义方法 参数 amount:表示一次购买的数量,暂时不用    //返回值表示一双球鞋的价格。    float sell(int amount);    }

2.定义接口实现类

代码如下(示例):

package jmu.czx.factory;import jmu.czx.service.ShoeShell;public class USAFactory implements ShoeShell {       @Override    public float sell(int amount) {           //可以根据 购买的数量 amount有其他优惠        return 1000;    }}

3.创建代理类

创建A代购

package jmu.czx.daigou;import jmu.czx.factory.USAFactory;import jmu.czx.service.ShoeShell;public class A implements ShoeShell {       private USAFactory usaFactory=new USAFactory();    @Override    public float sell(int amount) {           float price = usaFactory.sell(amount);        //在单价之上增加100元作为利润        return price+100;    }}

创建B代购

package jmu.czx.daigou;import jmu.czx.factory.USAFactory;import jmu.czx.service.ShoeShell;public class B implements ShoeShell {       private USAFactory usaFactory=new USAFactory();    @Override    public float sell(int amount) {           float price=usaFactory.sell(amount);        //在单价之上增加80元作为利润        return price+80;    }}

4.实现代理模式

package jmu.czx;import jmu.czx.daigou.A;import jmu.czx.daigou.B;public class Test {       public static void main(String[] args) {           float price=0.0f;        A a=new A();        price=a.sell(1);        System.out.println("A代购的price为:"+price);        System.out.println("===========================");        B b=new B();        price=b.sell(1);        System.out.println("B代购的price为:"+price);          }}

5.静态代理的缺点

(1) 代码复杂,难于管理
代理类和目标类实现了相同的接口,每个代理都需要实现目标类的方法,这样就出现了大量的代码重复。如果接口增加一个方法,除了所有目标类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
(2) 代理类依赖目标类,代理类过多代理类只服务于一种类型的目标类,如果要服务多个类型。势要为每一种目标类都进行代理,静态代理在程序规模稍大时就无法胜任了,代理类数量过多。
所以这时候就需要我们用到动态代理。

三、动态代理

1. 概念

动态代理是指代理类对象在程序运行时由 JVM 根据反射机制动态生成的。动态代理不需要定义代理类的.java 源文件。动态代理其实就是 jdk 运行期间,动态创建 class 字节码并加载到 JVM。动态代理的实现方式常用的有两种:使用 JDK 代理代理,与通过 CGLIB 动态代理。

而本文主要讲的是JDK动态代理,需要用到 InvocationHandler 接口 ,Method 类 ,
Proxy

接下来对静态代理进行改写,来实现动态代理,可以先记住语法,背下来也行,以后再慢慢理解

2.InvocationHandler接口 ,Method类 ,Proxy类作用

(1) InvocationHandler 接口
InvocationHandler 接口叫做调用处理器,负责完调用目标方法,并增强功能。通 过 代 理 对 象 执 行 目 标 接 口 中 的 方 法 , 会 把 方 法 的 调 用 分 派 给 调 用 处 理 器 (InvocationHandler)的实现类,执行实现类中的 invoke()方法,我们需要把功能代理写在 invoke()方法中

接口中只有一个方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable    proxy:代表生成的代理对象    method:代表目标方法    args:代表目标方法的参数

(2) Method 类
invoke()方法的第二个参数为 Method 类对象,该类有一个方法也叫 invoke(),可以调用
目标方法。这两个 invoke()方法,虽然同名,但无关。

public Object invoke ( Object obj, Object... args) obj:表示目标对象args:表示目标方法参数,就是其上一层 invoke 方法的第三个参数

该方法的作用是:调用执行 obj 对象所属类的方法,这个方法由其调用者 Method 对
象确定。
在代码中,一般的写法为
method.invoke(target, args);
其中,method 为上一层 invoke 方法的第二个参数。这样,即可调用了目标类的目标
方法
(3) Proxy 类
通 过 JDK 的 java.lang.reflect.Proxy 类 实 现 动 态 代 理 , 会 使 用 其 静 态 方 法
newProxyInstance(),依据目标对象、业务接口及调用处理器三者,自动生成一个动态代理对

public static newProxyInstance ( ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) loader:目标类的类加载器,通过目标对象的反射可获取interfaces:目标类实现的接口数组,通过目标对象的反射可获取handler:调用处理器。

3.步骤

jdk 动态代理是代理模式的一种实现方式,其只能代理接口。
实现步骤
1、新建一个接口,作为目标接口
2、为接口创建一个实现类,是目标类 (到这边都和之前的代码步骤是一样的)

3、创建类实现 java.lang.reflect.InvocationHandler 接口,调用目标方法并增加其他功能代码

package jmu.czx.daigou;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class MySellHandler implements InvocationHandler {       private  Object target=null;  //定义目标对象    public MySellHandler(Object target) {           //使用构造方法传入目标对象,给目标对象提供代理功能        this.target = target;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {           Object res = null;        res = method.invoke(target,args);    //执行目标方法,进行访问控制        if(res!=null)        {               float price =(float)res;            res=price+25; //在目标方法执行之后,增强功能,即提高价格        }        return res;    }    }

4、创建动态代理对象,使用 Proxy.newProxyInstance()方法,并把返回值强制转为接口类型

package jmu.czx;import com.bjpowernode.service.UsbSell;import jmu.czx.daigou.A;import jmu.czx.daigou.B;import jmu.czx.daigou.MySellHandler;import jmu.czx.factory.USAFactory;import jmu.czx.service.ShoeShell;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;public class Test {       public static void main(String[] args) {   //        float price=0.0f;//        A a=new A();//        price=a.sell(1);//        System.out.println("A代购的price为:"+price);//        System.out.println("===========================");//        B b=new B();//        price=b.sell(1);//        System.out.println("B代购的price为:"+price);          //创建代理        ShoeShell target= new  USAFactory();          //创建调用处理器        InvocationHandler handler= new MySellHandler(target);        //创建jdk动态代理         ShoeShell usa=(ShoeShell) Proxy.newProxyInstance(target.getClass().getClassLoader(),                target.getClass().getInterfaces(),handler);         //通过代理对象执行业务方法,实现利润增加        float price=usa.sell(1);        System.out.println("A代购的price为:"+price);    }}

4.总结

动态代理在spring,mybatis等框架中都会用到需要好好掌握
我的第一篇博客,有很多不足的地方,希望大家能够提意见进行改进。

上一篇:Spring整合mybatis用阿里连接池的配置错误
下一篇:mqtt.fx软件使用教程(连接阿里云)

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2025年03月24日 10时15分31秒