1.代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问(在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用).
2.代理模式一般涉及到的角色有:(1)抽象角色:声明真实对象和代理对象的共同接口; (2)真实角色:代理角色所代表的真实对象,是我们最终要引用的对象; (3)代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装
例子1:实现一个静态代理
- package edu.hust.proxy;
- //抽象角色
- public interface RoleDAO {
- public void doSomething();
- }
- package edu.hust.proxy;
- //真实角色
- public class RoleDAOImpl implements RoleDAO {
- public void doSomething() {
- System.out.println("我可以做一些事情, 比如:数据的增删改查.....");
- }
- }
- package edu.hust.proxy;
- //代理角色
- public class RoleProxy implements RoleDAO {
- //将真实角色作为代理角色的属性。组合理论, 表示引用.
- private RoleDAOImpl roleDAOImpl;
- //该方法封装了真实角色的doSomething()方法
- public void doSomething() {
- if (roleDAOImpl == null) {
- roleDAOImpl = new RoleDAOImpl();
- }
- this.before();
- roleDAOImpl.doSomething();
- this.after();
- }
- public void before() {
- System.out.println("做事情之前, 我想我可以做点其他事情:such as --> 判断一下权限..");
- }
- public void after() {
- System.out.println("做事情之后, 我想我还可以做点其他事情:such as --> 写个日志..");
- }
- }
- package edu.hust.proxy;
- //客户端
- public class Client {
- public static void main(String[] args) {
- new RoleProxy().doSomething();
- }
- }
但是,如果要按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际使用时,一个真实角色必须对应一个 代理角色,如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决.
3.动态代理
所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:
(1)Interface InvocationHandler:该接口中仅定义了一个方法
public object invoke(Object obj, Method method, Object[] args):在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的doSomething(),args为该方法的参数数组。 这个抽象方法在代理类中动态实现。
(2)Proxy,该类即为动态代理类,作用类似于上例中的RoleProxy,其中主要包含以下内容
protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。
static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例。
例子2:先实现一个最基本的动态代理
- package edu.hust.dynaProxy;
- //抽象角色
- public interface RoleDAO {
- public void doSomething();
- }
- package edu.hust.dynaProxy;
- import edu.hust.dynaProxy.RoleDAO;
- public class RoleDAOImpl1 implements RoleDAO {
- public void doSomething() {
- System.out.println("吃牛肉。。。。。");
- }
- }
- package edu.hust.dynaProxy;
- import edu.hust.dynaProxy.RoleDAO;
- public class RoleDAOImpl2 implements RoleDAO {
- public void doSomething() {
- System.out.println("吃蔬菜。。。");
- }
- }
- package edu.hust.dynaProxy;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- /*
- * 代理角色
- *
- * 通过构造函数RoleProxy(Object obj)将 被代理类对象 传递进来.
- *
- * */
- public class RoleProxyBefore implements InvocationHandler {
- private Object obj;
- public RoleProxyBefore() {}
- public RoleProxyBefore(Object obj) {
- this.obj = obj;
- }
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- this.before();
- Object object = method.invoke(obj, args);
- return object;
- }
- public void before() {
- System.out.println("做事情之前, 我想我可以做点其他事情:such as --> 判断一下权限..");
- }
- }
- package edu.hust.dynaProxy;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- /*
- * 代理角色
- *
- * 通过构造函数RoleProxy(Object obj)将 被代理类对象 传递进来.
- *
- * */
- public class RoleProxyAfter implements InvocationHandler {
- private Object obj;
- public RoleProxyAfter() {}
- public RoleProxyAfter(Object obj) {
- this.obj = obj;
- }
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- Object object = method.invoke(obj, args);
- this.after();
- return object;
- }
- public void after() {
- System.out.println("做事情之后, 我想我还可以做点其他事情:such as --> 写个日志..");
- }
- }
客户端类有两个版本:Client1.java是最原始的,Client2.java是用工厂重构过的
- package edu.hust.dynaProxy;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Proxy;
- public class Client1 {
- public static void main(String[] args) {
- //获得 被代理类 的对象
- RoleDAO roleDAO1 = new RoleDAOImpl1();
- RoleDAO roleDAO2 = new RoleDAOImpl2();
- //获得 代理类 的对象
- //(1) 取得Class实例
- Class<?> cls_roleDAO1 = roleDAO1.getClass();
- Class<?> cls_roleDAO2 = roleDAO2.getClass();
- //(2) 针对每个 被代理类对象, 初始化其对应的动态代理类
- InvocationHandler h1_before = new RoleProxyBefore(roleDAO1);
- InvocationHandler h2_before = new RoleProxyBefore(roleDAO2);
- InvocationHandler h1_after = new RoleProxyAfter(roleDAO1);
- InvocationHandler h2_after = new RoleProxyAfter(roleDAO2);
- //(3) 获得 代理类 的对象
- RoleDAO roleDAO1_before = (RoleDAO) Proxy.newProxyInstance(cls_roleDAO1.getClassLoader(), cls_roleDAO1.getInterfaces(), h1_before);
- RoleDAO roleDAO2_before = (RoleDAO) Proxy.newProxyInstance(cls_roleDAO2.getClassLoader(), cls_roleDAO2.getInterfaces(), h2_before);
- RoleDAO roleDAO1_after = (RoleDAO) Proxy.newProxyInstance(cls_roleDAO1.getClassLoader(), cls_roleDAO1.getInterfaces(), h1_after);
- RoleDAO roleDAO2_after = (RoleDAO) Proxy.newProxyInstance(cls_roleDAO2.getClassLoader(), cls_roleDAO2.getInterfaces(), h2_after);
- //直接获得 代理类 的对象:相比上面的6行代码(只是获得代理类对象的分解动作), 我更喜欢用一下被注释的方式获得代理类对象。
- //RoleDAO roleDAO1_before = (RoleDAO) Proxy.newProxyInstance(roleDAO1.getClass().getClassLoader(), roleDAO1.getClass().getInterfaces(), new RoleProxyBefore(roleDAO1));
- //RoleDAO roleDAO2_before = (RoleDAO) Proxy.newProxyInstance(roleDAO2.getClass().getClassLoader(), roleDAO2.getClass().getInterfaces(), new RoleProxyBefore(roleDAO2));
- //RoleDAO roleDAO1_after = (RoleDAO) Proxy.newProxyInstance(roleDAO1.getClass().getClassLoader(), roleDAO1.getClass().getInterfaces(), new RoleProxyAfter(roleDAO1));
- //RoleDAO roleDAO2_after = (RoleDAO) Proxy.newProxyInstance(roleDAO2.getClass().getClassLoader(), roleDAO2.getClass().getInterfaces(), new RoleProxyAfter(roleDAO2));
- roleDAO1_before.doSomething();
- System.out.println("===========================================================");
- roleDAO2_before.doSomething();
- System.out.println("===========================================================");
- roleDAO1_after.doSomething();
- System.out.println("============================================================");
- roleDAO2_after.doSomething();
- }
- /*
- * 输出结果:
- *
- * 做事情之前, 我想我可以做点其他事情:such as --> 判断一下权限..
- * 吃牛肉。。。。。
- * ===========================================================
- * 做事情之前, 我想我可以做点其他事情:such as --> 判断一下权限..
- * 吃蔬菜。。。
- * ===========================================================
- * 吃牛肉。。。。。
- * 做事情之后, 我想我还可以做点其他事情:such as --> 写个日志..
- * ============================================================
- * 吃蔬菜。。。
- * 做事情之后, 我想我还可以做点其他事情:such as --> 写个日志..
- *
- * */
- }
- package edu.hust.dynaProxy;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Proxy;
- public class Client2 {
- /*
- * 改进:建立代理工厂, 进一步简化代码
- * param1:被代理类 的对象
- * param2:代理类 的名字
- *
- * 最后:这个重构方法常放与代理类(代理类也算是一种工具类)中, 这样的代码更加优雅..
- */
- public static Object proxyFactory(Object obj, String name_classOfProxy) {
- InvocationHandler h = null;
- if ("RoleProxyBefore".equals(name_classOfProxy)) h = new RoleProxyBefore(obj);
- else if ("RoleProxyAfter".equals(name_classOfProxy)) h = new RoleProxyAfter(obj);
- return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), h);
- }
- public static void main(String[] args) {
- //获得 被代理类 的对象
- RoleDAO roleDAO1 = new RoleDAOImpl1();
- RoleDAO roleDAO2 = new RoleDAOImpl2();
- //获得 代理类 的对象
- RoleDAO roleDAO1_before = (RoleDAO) Client2.proxyFactory(roleDAO1, "RoleProxyBefore");
- RoleDAO roleDAO2_before = (RoleDAO) Client2.proxyFactory(roleDAO2, "RoleProxyBefore");
- RoleDAO roleDAO1_after = (RoleDAO) Client2.proxyFactory(roleDAO1, "RoleProxyAfter");
- RoleDAO roleDAO2_after = (RoleDAO) Client2.proxyFactory(roleDAO2, "RoleProxyAfter");
- roleDAO1_before.doSomething();
- System.out.println("===========================================================");
- roleDAO2_before.doSomething();
- System.out.println("===========================================================");
- roleDAO1_after.doSomething();
- System.out.println("============================================================");
- roleDAO2_after.doSomething();
- }
- /*
- * 输出结果:
- *
- * 做事情之前, 我想我可以做点其他事情:such as --> 判断一下权限..
- * 吃牛肉。。。。。
- * ===========================================================
- * 做事情之前, 我想我可以做点其他事情:such as --> 判断一下权限..
- * 吃蔬菜。。。
- * ===========================================================
- * 吃牛肉。。。。。
- * 做事情之后, 我想我还可以做点其他事情:such as --> 写个日志..
- * ============================================================
- * 吃蔬菜。。。
- * 做事情之后, 我想我还可以做点其他事情:such as --> 写个日志..
- *
- * */
- }
例子3:对例子2进行重构,其中RoleDAO.java、RoleDAOImpl1.java、RoleDAOImpl2.java无需改动。只要将两个代理类和Client类重构就ok了。
- package edu.hust.dynaProxy2;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- /*
- * 代理角色
- *
- * 通过构造函数RoleProxy(Object obj)将 被代理类对象 传递进来.
- *
- * */
- public class RoleProxyBefore implements InvocationHandler {
- private Object obj;
- public Object bind(Object obj) {
- this.obj = obj;
- return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
- }
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- this.before();
- Object object = method.invoke(obj, args);
- return object;
- }
- public void before() {
- System.out.println("做事情之前, 我想我可以做点其他事情:such as --> 判断一下权限..");
- }
- }
- package edu.hust.dynaProxy2;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- /*
- * 代理角色
- *
- * 通过构造函数RoleProxy(Object obj)将 被代理类对象 传递进来.
- *
- * */
- public class RoleProxyAfter implements InvocationHandler {
- private Object obj;
- public Object bind(Object obj) {
- this.obj = obj;
- return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
- }
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- Object object = method.invoke(obj, args);
- this.after();
- return object;
- }
- public void after() {
- System.out.println("做事情之后, 我想我还可以做点其他事情:such as --> 写个日志..");
- }
- }
- package edu.hust.dynaProxy2;
- public class Client {
- public static void main(String[] args) {
- //获得 代理类 的对象
- RoleProxyBefore roleProxyBefore = new RoleProxyBefore();
- RoleProxyAfter roleProxyAfter = new RoleProxyAfter();
- //获得 代理
- RoleDAO roleDAO1_before = (RoleDAO) roleProxyBefore.bind(new RoleDAOImpl1());
- RoleDAO roleDAO2_before = (RoleDAO) roleProxyBefore.bind(new RoleDAOImpl2());
- RoleDAO roleDAO1_after = (RoleDAO) roleProxyAfter.bind(new RoleDAOImpl1());
- RoleDAO roleDAO2_after = (RoleDAO) roleProxyAfter.bind(new RoleDAOImpl2());
- roleDAO1_before.doSomething();
- System.out.println("===========================================================");
- roleDAO2_before.doSomething();
- System.out.println("===========================================================");
- roleDAO1_after.doSomething();
- System.out.println("============================================================");
- roleDAO2_after.doSomething();
- }
- /*
- * 输出结果:
- *
- * 做事情之前, 我想我可以做点其他事情:such as --> 判断一下权限..
- * 吃牛肉。。。。。
- * ===========================================================
- * 做事情之前, 我想我可以做点其他事情:such as --> 判断一下权限..
- * 吃蔬菜。。。
- * ===========================================================
- * 吃牛肉。。。。。
- * 做事情之后, 我想我还可以做点其他事情:such as --> 写个日志..
- * ============================================================
- * 吃蔬菜。。。
- * 做事情之后, 我想我还可以做点其他事情:such as --> 写个日志..
- *
- * */
- }
总结:通过这种方式,(1)被代理的对象(RoleDAOImpl1或RoleDAOImpl2)可以在运行时动态改变;(2)需要控制的接口(RoleDAO)可以在运行时改变;(3)控制的方式(RoleProxyBefore或RoleProxyAfter)也可以动态改变,从而实现了非常灵活的动态代理关系。