如何理解动态代理机制?

生活中的代理

例子:比如一家美国大学,可以对全世界招生,留学中介就是代理,帮美国大学招生。


代理的特点
  1. 中介和他们代理的做事是一样:招生。
  2. 中介是学校的代理,学校是目标。
  3. 流程为,家长->中介->学校。
  4. 中介是代理,需要收取费用。

为什么找代理
  1. 中介是专业的。
  2. 家长没有办法接触到学校。

开发中的代理

例子1:A类想调用C类,但是C类禁止访问,只能在AC中间创建B类作为代理。
C的结果给B,B给A。


例子2:登录需要手机验证码,我们没有能力发送短信,移动联通有能力发短信。
移动联通有子公司提供发送短信的业务,于是我们->子公司->移动联通发短信。


代理模式

代理模式的定义

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。


代理模式的作用
  1. 功能增强:在你原有的功能上新增加功能。
  2. 控制访问:代理类不让你访问目标类。

代理的实现方式

静态代理

  • 代理类是自己手工实现的。
  • 代理的目标是确定的。
  • 特点:实现简单,容易理解。

例子:用户购买U盘,商家代理某个品牌的U盘。商家卖U盘,厂家提供。用户(客户端)->代理类(商家)->目标(厂家)。

步骤:

  1. 创建接口实现卖U盘的方法,即厂家和商家要做的事情。
  2. 创建商家类实现卖U盘的方法。
  3. 创建厂家类实现卖U盘的方法。
  4. 创建一个客户端类,调用商家方法去买U盘。

代码:

//厂家商家都要实现的功能
public interface UsbSaleService {
    //提供买U盘的数量,返回价格
    float sell(int i);
}
//厂家,不接受用户直接购买
class UsbFactory implements UsbSaleService{
    @Override
    public float sell(int i) {
        //厂家发货,一个2GU盘20元
        return i*20f;
    }
}
//商家,代理U盘的销售
class Taobao implements UsbSaleService{
    //指定代理的厂家
    private UsbFactory usbFactory=new UsbFactory();
    @Override
    public float sell(int i) {
        //向厂家发送订单,厂家发货
        //代理加价,一个U盘加10元,增强功能
        return usbFactory.sell(i)+i*10f;
    }
}
//用户购买
class shop{
    public static void main(String[] args) {
        //控制访问
        Taobao taobao=new Taobao();
        System.out.println(taobao.sell(5));
    }
}

静态代理优缺点:
缺点:

  1. 目标类增加,代理类会成倍的增加,即代理类数量过多。
  2. 功能类增加方法后导致目标类、代理类都需要修改,影响较大。

优点:

  1. 功能增强。
  2. 访问控制,解耦。

动态代理

在程序执行过程中,使用jdk反射机制,创建代理类对象,并动态的指定要代理的目标类,无需用户创建对象。

总结

Image.png

复习反射

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class InflectTest {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        /*创建对象执行
        helloImpl hello=new helloImpl();
        hello.sayHello("张三");
        */
        /*通过反射执行
        Hello h=new HelloImpl();
        Method method=Hello.class.getMethod("sayHello", String.class);
        Object res=method.invoke(h,"李四");
        */
    }
}
class HelloImpl implements Hello{
    @Override
    public void sayHello(String name) {
        System.out.println("你好,"+name);
    }
}
interface Hello{
    public void sayHello(String name);
}

如何实现动态代理

Image [3].png


Image.png


Image [2].png


Image [3].png


//参数1:jdk提供的代理对象无需赋值
//参数2:jdk提供的目标类的方法
//参数3:目标类方法的参数
public Object invoke(Object proxy, Method method, Object[] args)    throws Throwable;

Image.png


Image [2].png


案例一:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Random;

interface Moveable {
    void move();
}
public class Car implements Moveable {
    @Override
    public void move() {
        try {
            Thread.sleep(new Random().nextInt(1000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
class TimeHandler implements InvocationHandler {
    public TimeHandler(Object target) {
        super();
        this.target = target;
    }
    private Object target;
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long starttime = System.currentTimeMillis();
        method.invoke(target);
        long endtime = System.currentTimeMillis();
        System.out.println("汽车行驶时间:" +(endtime - starttime) + "毫秒!");
        return null;
    }
}
class Test {
    public static void main(String[] args) {
        Car car = new Car();
        InvocationHandler h = new TimeHandler(car);
        Class<?> cls = car.getClass();
        Moveable m = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h);
        m.move();
    }
}

Image [4].png

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface UsbSell{
    float sell(int sum);
}
class Factory implements UsbSell{
    @Override
    public float sell(int sum) {
        return sum*100f;
    }
}
class MySellHandle implements InvocationHandler{
    private Object target;
    MySellHandle(Object target){
        this.target=target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object res=method.invoke(target,args);
        return (Float)res+(int)args[0]*5;
    }
}
public class JDKModel {
    public static void main(String[] args) {
        UsbSell usbSell=new Factory();
        InvocationHandler handler=new MySellHandle(usbSell);
        UsbSell proxy=(UsbSell) Proxy.newProxyInstance(usbSell.getClass().getClassLoader(),usbSell.getClass().getInterfaces(),handler);
        System.out.println(proxy.sell(10));
    }
}

实际开发中动态代理的应用


JDK动态代理,必须有接口。
CGLib动态代理,必须能被继承,即class不能是 final。


我在校大二期间接过私活,一元秒杀抢购系统。
这个系统有两个特点,一没有文档,二没有源码。只有一堆运行在Tomcat上的class文件和html文件。除了新增的CUID等功能外,还要调用之前人写的代码。因为不敢动之前人写的代码,所以就先反编译,然后继承重写指定方法,测试没问题后在修改AJAX的URL。上一个人不开发了,所以不用考虑代码变动问题。最主要的是发现要重写的太多了,评估了一下工作量,要继承重写几十个ServiceImpl,后来就直接用动态代理来做的。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值