代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用.在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: 指代的是调用真实对象某个方法时接受的参数
动态创建一个代理对象的类,用的最多的就是 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动态代理机制