您的位置:首页 > 编程语言 > Java开发

Java动态代理

2020-06-29 04:26 225 查看

代理模式

代理模式就是代理对象完成用户的请求,屏蔽用户对真是对象的访问。
打个比方,在早些年间我们要买电脑,都是直接跟电脑生产厂家进行交易,我们付款给生产厂家,然后厂家发货给我们。随着生产厂家的业务发展,用户越来越多,对商品的销售和售后需要付出更多的财力和物力。这时,一些人洞察了这一机遇,就搞了了一个叫代理商/经销商的东西出来,如某宝,某东。后来,我们如果再想买电脑,就不是直接跟电脑厂家交易了,而是代理商跟生产厂家进行联系,我们再跟代理商进行交易。对商品的售后,也不再是买家跟厂家进行联系了,而是买家跟代理商联系了。对于买家而言,这个中间商就是对生产厂家进行了代理。

静态代理

要说动态代理,有必要先了解下静态代理,静态代理和动态代理的主要区别前者的代理类需要程序员手动编码,而后者的代理类是自动生成的。
代码实现

  1. 创建IProducer接口,定义销售商品规范
public interface IProducer {
/**
* 销售商品
* @param maney
*/
void sale(float maney);
}
  1. 创建Producer类,定义生产厂家
public class Producer implements IProducer {
public void sale(float maney) {
System.out.println("销售了商品,并拿到了钱:"+maney);
}
}
  1. 创建StaticProxy类,定义静态代理类
public class StaticProxy implements IProducer {
private IProducer producer;
public StaticProxy(IProducer producer){
this.producer=producer;
}
public void sale(float maney) {
producer.sale(maney*0.8f);
}
}
  1. 测试(我这里使用的是单元测试,需要导入Juni依赖)
public class TestStaticProxy {
IProducer producer=new Producer();
StaticProxy staticProxy=new StaticProxy(producer);
@Test
public void TestStaticProxy(){
//用户直接通过代理商购买商品,花了10000块,
// 生产厂家得到了8000块,还有2000块是代理商的活动经费
//毕竟人家也要吃饭嘛
staticProxy.sale(10000f);
}
}

控制台打印信息:销售了商品,并拿到了钱:8000.0

JDK动态代理机制

代码实现

  1. 创建一个JDKDynamicProxy类,用来获取代理类对象
public class JDKDynamicProxy {
IProducer producer=new Producer();
/**
* 获取动态代理类对象
* @return
*/
public IProducer getProxy(){
IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
producer.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Float money = (Float) args[0];
method.invoke(producer,money*0.8f);
return null;
}
});
return proxyProducer;
}
}
  • 要求
    被代理类至少实现一个接口
  • 创建方式
    Proxy.newProxyInstance(三个参数)
  • newProxyInstance方法三个参数
    ClassLoader:和被代理对象使用相同的类加载器
    Interface:和被代理对象具有相同的行为,实现相同的接口
    InvocationHandler:如何代理
  • InvocationHandler中的invoke方法详解
    执行被代理对象的任何方法都会经过该方法
    参数:
    proxy:代理对象的引用
    method:当前执行的被代理对象的方法的方法对象
    args:执行被代理对象的方法所需的参数
    返回值:当前执行的被代理对象的方法的返回值
  1. 测试
public class TestJDKDynamicProxy {
JDKDynamicProxy jdkDynamicProxy=new JDKDynamicProxy();
@Test
public void testJDKDynamicProxy(){
//获取代理对象
IProducer proxyProducer = jdkDynamicProxy.getProxy();
//执行此方法最终会执行InvocationHandler的的invoke方法
proxyProducer.sale(10000f);
}
}

控制台打印信息:销售了商品,并拿到了钱:8000.0
3. JDK动态代理的缺陷

  • 被代理类必须实现接口
  • 如果被代理类实现多个接口,在创建代理类对象时应该转向哪个类型
    正是由于有这么多缺陷,于是有了CGLib动态代理

CGLib动态代理

  1. 要使用CGLib动态代理需要引入第三发依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency>
  1. 创建CGLibProxy类,来获取代理对象
public class CGLibProxy {
Producer producer=new Producer();
public Producer getProxy(){
Producer proxyProducer  = (Producer) Enhancer.create(this.producer.getClass(), new MethodInterceptor() {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Float money = (Float) objects[0];
method.invoke(CGLibProxy.this.producer, money*0.8f);
return null;
}
});
return proxyProducer;
}
}
  • 要求
    被代理类不能是最终类
  • 用到的类
    Enhancer
  • 用到的方法
    create(Class,Callback)
  • 方法参数
    Class:被代理类字节码
    Callback:如何代理
  1. 测试
public class TestCGLibProxy {
CGLibProxy cgLibProxy=new CGLibProxy();
@Test
public void testCGLibProxy(){
Producer proxyProducer = cgLibProxy.getProxy();
proxyProducer.sale(12000f);
}
}

控制台打印销售了商品,并拿到了钱:9600.0

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: