在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。
示例:
public class DynamicProxyTest {
interface UserService {
public abstract void add();
}
interface UserService2 {
public abstract void add2();
}
static class UserServiceImpl implements UserService, UserService2 {
public void add() {
System.out.println("----- add -----");
}
public void add2() {
System.out.println("----- add 2-----");
}
}
static class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
super();
this.target = target;
}
public Object getProxy() {
/**
* Thread.currentThread().getContextClassLoader(: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
* arget.getClass().getInterfaces(): 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
* this: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
*/
return Proxy.newProxyInstance(Thread.currentThread()
.getContextClassLoader(), target.getClass().getInterfaces(),
this);
}
/**
* proxy: 我们所代理的那个真实对象
* method: 我们所要调用真实对象的某个方法的Method对象
* args: 调用真实对象某个方法时接受的参数
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("----- before -----");
Object result = method.invoke(target, args);
System.out.println("----- after -----");
return result;
}
}
/**
* @param args
*/
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
MyInvocationHandler invocationHandler = new MyInvocationHandler(
userService);
UserService proxy = (UserService) invocationHandler.getProxy();
proxy.add();
((UserService2)proxy).add2();
}
}
执行结果:
----- before -----
----- add -----
----- after -----
----- before -----
----- add 2-----
----- after -----
代理实现过程中的问题说明:
1. 这个代理对象是由谁且怎么生成的?
Proxy.newProxyInstance方法的实现里会通过创建一个代理类,并返代理实例供我们使用
- invoke方法是怎么调用的?
我们拿的的代理类是在编译过程中有jdk自动生成的. 类里会实现各个接口的方法,实现的方法里会调用invoke,例如:
public final void add()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
- invoke和add方法有什么对应关系?
实现InvocationHandler 这个接口的实例会有invoke方法,并且会执行
Object result = method.invoke(target, args);
通过得到执行后的返回值,add方法就在此时被真正的实例调用add方法
- 生成的代理对象是什么样子的?
编译成功后可以去$Proxy0.class文件查看内容
总结:
一个典型的动态代理创建对象过程可分为以下四个步骤:
1、通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(…);
2、通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
3、通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4、通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
为了简化对象创建过程,Proxy类中的newInstance方法封装了2~4,只需两步即可完成代理对象的创建。
生成的ProxySubject继承Proxy类实现Subject接口,实现的Subject的方法实际调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的的方法(Object result=method.invoke(proxied,args))
动态代理与混型的应用
示例代码:
public class DynamicProxyMixin {
class TwoTuple<A, B> {
public A first;
public B second;
public TwoTuple(A a, B b) {
this.first = a;
this.second = b;
}
}
interface TimeStamped {
long getStamped();
}
static class TimeStampedImpl implements TimeStamped {
private final long date;
public TimeStampedImpl() {
date = new Date().getTime();
}
public long getStamped() {
return date;
}
}
interface SerialNumbered {
long getSerialNumbered();
}
static class SerialNumberedImpl implements SerialNumbered {
private static long counter = 1;
private final long serialNumber = counter++;
public long getSerialNumbered() {
return serialNumber;
}
}
interface Basic {
void set(String val);
String get();
}
static class BasicImpl implements Basic {
private String value;
public void set(String val) {
value = val;
}
public String get() {
// TODO Auto-generated method stub
return value;
}
}
static class MixinProxy implements InvocationHandler {
Map<String, Object> delegateByMethodMap;
private MixinProxy(TwoTuple<Object, Class<?>> ...pairs) {
delegateByMethodMap = new HashMap<String, Object>();
for (TwoTuple<Object, Class<?>> pair : pairs) {
for (Method method : pair.second.getMethods()) {
String methodName = method.getName();
if (!delegateByMethodMap.containsKey(methodName)) {
delegateByMethodMap.put(methodName, pair.first);
}
}
}
}
public Object invoke(Object proxy, Method method, Object[] arg2)
throws Throwable {
String methodName = method.getName();
return method.invoke(delegateByMethodMap.get(methodName), arg2);
}
public static Object newInstance(TwoTuple<Object, Class<?>> ...pairs){
Class[] interfaces = new Class[pairs.length];
for (int i = 0, count = interfaces.length; i < count; i++) {
interfaces[i] = (Class) pairs[i].second;
}
ClassLoader loader = pairs[0].first.getClass().getClassLoader();
return Proxy.newProxyInstance(loader, interfaces, new MixinProxy(pairs));
}
}
/**
* @param args
*/
public static void main(String[] args) {
Object proxyObject = MixinProxy.newInstance(new TwoTuple(new BasicImpl(), Basic.class),
new TwoTuple(new TimeStampedImpl(), TimeStamped.class),
new TwoTuple(new SerialNumberedImpl(), SerialNumbered.class));
Basic b = (Basic) proxyObject;
SerialNumbered serialNumbered = (SerialNumbered) proxyObject;
TimeStamped timeStamped = (TimeStamped) proxyObject;
b.set("hello");
System.out.println(b.get());
System.out.println(serialNumbered.getSerialNumbered());
System.out.println(timeStamped.getStamped());
}
}
执行结果:
hello
1
1494841280897
通过动态代理得到的proxyObject实例就是一个混型类型,拥有多个接口功能.