代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用.在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class)
动态代理的通俗化解释:A接口有c方法,类B实现A接口,原本应该是执行B类中的c方法,可现在不这样做;我声明产生B类的代理类B',由它来冒充B类的“兄弟”并“实现”A接口,对外界来说B'应该也有c方法,可当真正调用它的时候,
它会去执行与它关联InvocationHandler的invoke()方法,在这个方法里面你可以做很多事情。这样,这个请求就被“代理”到其它地方去了。
InvocationHandler:
每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个类,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy: 指代我们所代理的那个真实对象
method: 指代的是我们所要调用真实对象的某个方法的Method对象
args: 指代的是调用真实对象某个方法时接受的参数
Proxy
动态创建一个代理对象的类,用的最多的就是 newProxyInstance 这个方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[]interfaces,InvocationHandler h) throws IllegalArgumentException {
// 检查 h 不为空,否则抛异常
if (h == null) {
throw new NullPointerException();
}
// 获得与指定类装载器和一组接口相关的代理类类型对象
Class cl = getProxyClass(loader, interfaces);
// 通过反射获取构造函数对象并生成代理类实例
try {
Constructor cons = cl.getConstructor(constructorParams);
return (Object) cons.newInstance(new Object[] { h });
} catch (NoSuchMethodException e) { throw new InternalError(e.toString());
} catch (IllegalAccessException e) { throw new InternalError(e.toString());
} catch (InstantiationException e) { throw new InternalError(e.toString());
} catch (InvocationTargetException e) { throw new InternalError(e.toString());
}
}
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.
loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
实例:
定义接口
public interface UserDao {
public void save(User user);
}
定义接口实现
public class UserDaoImpl implements UserDao {
//@Override
public void save(User user) {
System.out.println("usersaved!!!");
}
}
定义代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DebugInterceptor implements InvocationHandler {
private Object target;
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
private void operate(Method m){
System.out.println(m.getName()+" start!!!");
}
/*
* proxy: 指代我们所代理的那个真实对象
* method: 指代的是我们所要调用真实对象的某个方法的Method对象
* args: 指代的是调用真实对象某个方法时接受的参数
*
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
* java.lang.reflect.Method, java.lang.Object[])
*/
//@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
operate(method);
method.invoke(target, args);
return null;
}
}
测试程序
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
UserDao userDao = new UserDaoImpl();
DebugInterceptor di = new DebugInterceptor();
di.setTarget(userDao);
//Proxy.newProxyInstance(loader, interfaces, h)参数分别表示调用函数的类加载器,调用函数的全部接口,实现此代理的类
UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao
.getClass().getClassLoader(), userDao.getClass()
.getInterfaces(), di);
System.out.println(userDaoProxy.getClass().getName());
System.out.println(userDaoProxy.getClass().getMethods());
userDaoProxy.save(new User());
}
}
output:
com.sun.proxy.$Proxy0
[Ljava.lang.reflect.Method;@feb48
save start!!!
usersaved!!!
com.sun.proxy.$Proxy0是由以下代码生成的对象的名称
UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao
.getClass().getClassLoader(), userDao.getClass()
.getInterfaces(), di);
由此可以看到通过 Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口(userDao)的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号
在真正通过代理对象来调用真实对象的方法的时候,我们可以在该方法前后添加自己的一些操作,这就是我们的java动态代理机制