
本文共 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等框架中都会用到需要好好掌握
我的第一篇博客,有很多不足的地方,希望大家能够提意见进行改进。
发表评论
最新留言
关于作者
