Java动态代理(Java Dynamic Proxy)

以下内容翻译自不知名的某个文档


概述

作为client和target之间的中间人(intermediary),代理在很多场合下是很有用的。

为了进一步理解动态代理的作用,我们首先看一个不使用代理机制的实例。


不使用代理的Vehicle例子

public interface IVehicle {
	public void start();
	public void stop();
	public String getName();
}
public class Car implements IVehicle {
	String name;
	
	public Car(String name) {
		this.name = name;
	}
	
	public void start() {
		System.out.println("start(): The car" + name + " started");
	}
	
	public void stop() {
		System.out.println("stop(): The car" + name + " stopped");
	}
	
	public String getName() {
		return this.name;
	}
}
public class Client {
	public static void main(String[] args) {
		IVehicle v = new Car("BMW");
		v.start();
		v.stop();
	}
}
运行结果为

start(): The carBMW started
stop(): The carBMW stopped

本例子的调用关系图为





使用代理的Vehicle例子

记住:使用代理的主要目的是为了更好地控制对target的访问,而不是增强target的功能(functionality)。

代理通过以下方式来实现对target的访问控制:

  • Synchronization
  • Authentication
  • Remote Access
  • Lazy instantiation


public class VehicleProxy implements IVehicle {
	private IVehicle v;
	
	public VehicleProxy(IVehicle v) {
		this.v = v;
	}
	
	public void start() {
		System.out.println("VehicleProxy.start()");
		v.start();
	}
	
	public void stop() {
		System.out.println("VehicleProxy.stop()");
		v.stop();
	}
	
	public String getName() {
		System.out.println("VehicleProxy.getName()");
		return v.getName();
	}
}
public class Client2 {
	public static void main(String[] args) {
		IVehicle car = new Car("BMW");
		IVehicle v = new VehicleProxy(car); 		
		v.start();
		v.stop();
	}	
}
运行结果为

VehicleProxy.start()
start(): The carBMW started
VehicleProxy.stop()
stop(): The carBMW stopped

这个例子中的调用关系为:


以上这个是用代理的例子似乎也达到了我们的目的,现在,我们希望在调用Car的每一个方法的之前和之后,都能打印出一些日志信息,例如传入的参数和输出的结果。但是我们也要考虑到以下事实:

  • Car类及IVehicle接口都是核心业务层面的代码,不能轻易改动;
  • 目前已经有大量代码用到了Car类和IVehicle接口,不能对这些代码进行大规模的变动;
  • Car类和IVehicle里也许有很多方法,我们希望花最小的代价就能为每一个方法增加调用日志
  • 今后为Car类和IVehicle接口增加新的方法时,我们希望在调用这些新增方法时能够自动地增加调用日志


好了,是该看看动态代理的时候了


Java动态代理


什么是Java动态代理

  • 当一个动态代理类dynamic proxy class)在被创建之后,它将实现在运行时被指定的一系列接口
  • 代理接口proxy interface)是一个由代理类(proxy class)实现的接口
  • 代理实例proxy instance)是一个代理类(proxy class)的实例
  • 每一个代理实例都有一个与之关联的invocation handler object(实现了InvocationHandler接口)
  • 如果通过代理接口来调用代理实例上的一个方法,那么该方法调用将被转发(dispatch)至与该代理实例相关联的invocation handler的invoke方法


java.lang.reflect.Proxy类

Proxy类为创建动态代理类和动态代理实例提供的静态方法,同时它也是由这些静态方法创建的动态代理类的父类。

为接口Foo创建动态代理类:

InvocationHandler handler = new MyInvocationHandler(...);
Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), new class[]{foo.class});
Foo foo = proxyClass.getConstructor(new class[]{InvocationHandler.class}).newInstance(new Object[]{handler});

也可以通过下列方式为接口Foo创建动态代理类:

InvocationHandler handler = new MyInvocationHandler(...);
Foo foo = Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[]{Foo.class}, handler);



动态代理实例

我们将前面的例子用动态代理的方式来做如下改造

public interface IVehicle {
	public void start();
	public void stop();
	public String getName();
}
public class Car implements IVehicle {
	String name;
	
	public Car(String name) {
		this.name = name;
	}
	
	@Override
	public void start() {
		System.out.println("start(): The car " + name + " started");
	}
	
	@Override
	public void stop() {
		System.out.println("stop(): The car " + name + " stopped");
	}
	
	@Override
	public String getName() {
		System.out.println("getName(): The car " + name + "'s name is retrieved");
		return this.name;
	}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;

public class VehicleHandler implements InvocationHandler {
	private IVehicle target;
	
	public VehicleHandler(IVehicle target) { 
		this.target = target;
	}
	
	@Override
	public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
		System.out.println("[Before Method Call]  The method " + m.getName() + "() begins with " + Arrays.toString(args));
		Object result =  m.invoke(target, args);
		System.out.println("[After Method Call]  The method " + m.getName() + "() ends with " + result);
		return result;
	}
}
import java.lang.reflect.Proxy;

public class Client {
	public static void main(String[] args) {
		IVehicle car = new Car("Ford");
		IVehicle proxiedCar = (IVehicle) Proxy.newProxyInstance(
				car.getClass().getClassLoader(), 
				car.getClass().getInterfaces(), 
				new VehicleHandler(car));
		
		proxiedCar.start();
		System.out.println("-------------------------------------------");
		String name = proxiedCar.getName();
	}
}

运行结果为

[Before Method Call]  The method start() begins with null
start(): The car Ford started
[After Method Call]  The method start() ends with null
-------------------------------------------
[Before Method Call]  The method getName() begins with null
getName(): The car Ford's name is retrieved
[After Method Call]  The method getName() ends with Ford














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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值