MENU

Java代理模式

June 24, 2020 • Java

Java代理

java代理模式即是:为其他对象提供一种代理以控制对这个对象的访问。代理对象起到中介作用,在不修改对象源码的情况下可以去掉功能服务或者扩展功能。

静态代理

代理和被代理对象在代理之前是确定的,他们继承相同的接口类或者继承相同的抽象类,在程序运行之前,代理类.class文件就已经被创建了。

接口类

package com.qing.proxy;

public interface Moveable {
    void move();
}

被代理对象:

package com.qing.proxy;

import java.util.Random;

public class Car implements Moveable {
    @Override
    public void move() {

        //开始开车
        try {
            Thread.sleep(new Random().nextInt(1000));
            System.out.println("汽车行驶中......");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

继承式静态代理

package com.qing.proxy;

/**
 * 静态代理 继承
 */
public class Car2 extends Car {
    @Override
    public void move() {
        long starttime = System.currentTimeMillis();
        System.out.println("开始开车.....");
        super.move();
        long endtime =System.currentTimeMillis();
        System.out.println("汽车行驶结束,行驶时间"+(endtime-starttime)+"ms");
    }
}

聚合式动态代理


package com.qing.proxy;

/**
 * 静态代理 聚合
 */
public class Car3 implements Moveable{

    public Car3(Car car) {
        this.car = car;
    }

    private Car car;
    @Override
    public void move() {
        long starttime = System.currentTimeMillis();
        System.out.println("开始开车.....");
        car.move();
        long endtime =System.currentTimeMillis();
        System.out.println("汽车行驶结束,行驶时间"+(endtime-starttime)+"ms");
    }
}

聚合要优于继承的方式,在实现功能叠加时继承式的静态代理需要写多个类来实现多功能叠加,而聚合方式的静态代理可以通过相互代理实现功能重用。

动态代理

动态代理即是在代理类和被代理类之间加入事务处理器(InvocationHandler),用于实现扩展功能。

实现JDK动态代理需要java.lang.reflect包下的Proxy类的newProxyInstance方法进行动态创建代理类。

TimeHandler:

 public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

此方法需要三个参数:

  • loader 类加载器
  • interface 实现接口类
  • h 事务管理器

newProxyInstance的实现步骤:

  1. 获取到被代理类的源码
  2. 编译源码,产生新的代理类
  3. 加载类到内存中,创建一个新的代理类对象
  4. 返回代理类对象

Proxy.newProxyInstance方法:

     //查询或生成指定的代理类的Class对象
     Class<?> cl = getProxyClass0(loader, intfs);
    //获取代理类的构造方法
    final Constructor<?> cons = cl.getConstructor(constructorParams);
    
    final InvocationHandler ih = h;
    if (!Modifier.isPublic(cl.getModifiers())) {
        AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {
                cons.setAccessible(true);
                return null;
            }
        });
    }
    //返回创建的实例
    return cons.newInstance(new Object[]{h});

动态代理实现步骤:

  1. 创建一个实现接口InvocationHandler的类且要实现invoke方法
  2. 创建被代理类以及接口
  3. 调用Proxy类的newProxyInstance方法创建代理类
  4. 使用代理类调用方法

TimeHandler:

package com.qing.jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * JDK动态代理
 */
public class TimeHandler implements InvocationHandler {

    public TimeHandler(Object object) {
        super();
        this.target = object;
    }

    private Object target;

    /**
     *
     * @param proxy 被代理对象
     * @param method 被代理对象的方法
     * @param args 方法的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long starttime = System.currentTimeMillis();
        System.out.println("开始开车.....");
        method.invoke(target);
        long endtime =System.currentTimeMillis();
        System.out.println("汽车行驶结束,行驶时间"+(endtime-starttime)+"ms");
        return null;
    }
}

代理类的实现:

Car car = new Car();
        InvocationHandler ih = new TimeHandler(car);
        Class<?> cls = car.getClass();
        //动态创建代理类
        Moveable moveable = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),ih);
        moveable.move();

装饰器模式与代理模式

网上关于两种模式的区别五花八门,在我个人理解中,装饰器模式与代理模式虽然都是对原有对象进行扩展功能,但是装饰器模式的目的是增加功能,代理模式的目的是控制对真实对象的访问,一个侧重于增加另一个侧重于控制