设计模式 -- 代理模式(Proxy)

模式介绍:能够将系统中需要的一些横向的通用逻辑和核心业务逻辑分割开,即改变通用逻辑的时候不影响核心业务逻辑的代码。

首先介绍静态代理设计的思路,要实现对某个类进行代理,比如说汽车(Car),有run()stop()的方法,要对该类中所有方法进行代理(添加同一种事务),那么该对象产生的代理就必须具有Car中所有的方法。一旦调用Car的方法,如:run(),就先调用代理的run()方法,在方法中再调用Carrun()方法,可想而知,要在前后加上逻辑就很方便了,更重要的是不会影响核心业务逻辑(这里是指Carrun方法)

    由于要在代理中调用Car的具体的方法,所以可以使用聚合的方式,将Car当成成员变量加到代理类中,而这样还不够灵活,因为这样就只能代理Car类对象了,所以更好的做法是定义一个接口,将接口聚合到代理类中,从而从只能代理某个类扩展成代理实现了某个接口的所有类。下面以产生坦克类的代理,计算模拟坦克的运行时间为例:

Ø  可以运动的” -- Moveable接口 – Moveable.java

package com.yilong.designpattern.proxy;

public interface Moveable {

    void move();

    void stop();

}

Ø  坦克 – Tank.java,实现了Moveable接口

package com.yilong.designpattern.proxy;

import java.util.Random;

 

public class Tank implements Moveable {

    public void move() {

       System.out.println("Tank Moving...");

       try {

           Thread.sleep(new Random().nextInt(10000));

       } catch (InterruptedException e) {

           e.printStackTrace();

       }

    }

    public void stop() {

       System.out.println("Tank Stopping...");

       try {

           Thread.sleep(new Random().nextInt(10000));

       } catch (InterruptedException e) {

           e.printStackTrace();

       }

    }

}

Ø  坦克代理 – TimeProxy.java,综上所述,需要实现要代理的对象实现的接口,

Tank对应的Moveable接口,这样TimeProxy就必须实现Moveable的方法。同时,需要将Moveable接口聚合到TimeProxy中,使得在代理过程中可以调用代理对象的方法。

package com.yilong.designpattern.proxy;

public class TimeProxy implements Moveable {

    Moveable moveable;

    public TimeProxy (Moveable moveable) {

       this.moveable = moveable;

    }

    public void move() {

       long start = System.currentTimeMillis();

       moveable.move();

       long end = System.currentTimeMillis();

       System.out.println("Moved Time:" + (end - start));

    }

    public void stop() {

       long start = System.currentTimeMillis();

       moveable.stop();

       long end = System.currentTimeMillis();

       System.out.println("Stopped Time:" + (end - start));

   

    }

}

Ø  专门创建代理的类Proxy – Proxy.java

package com.yilong.designpattern.proxy;

 

public class Proxy {

    public static Object newProxyInstance(Moveable m) {

       return new TimeProxy(m);

    }

}

Ø  测试类 – Client.java

package com.yilong.designpattern.proxy;

public class Client {

    public static void main(String[] args) {

       Tank t = new Tank();

       Car c = new Car();

       //Moveable m = new TankTimeProxy(t);

       Moveable m = (Moveable)Proxy.newProxyInstance(c);

       m.move();

       m.stop();

    }

}

    说明:此处的TimeProxy能代理实现了Moveable接口的任何类,而不仅仅是Tank,也可是Car:

Ø  汽车 – Car.java

package com.yilong.designpattern.proxy;

import java.util.Random;

public class Car implements Moveable {

    public void move() {

       System.out.println("Car Moving...");

       try {

           Thread.sleep(new Random().nextInt(5000));

       } catch (InterruptedException e) {

           e.printStackTrace();

       }

    }

    public void stop() {

       System.out.println("Car Stopping...");

       try {

           Thread.sleep(new Random().nextInt(5000));

       } catch (InterruptedException e) {

           e.printStackTrace();

       }

    }

}

    上述的代理只能代理实现了某个接口的类,而且代理只是关于时间日志记录的代理,而理想的情况是:

²  能够动态代理所有实现了接口的类

²  能够动态指定要实现怎样的代理(日志记录、性能统计、安全控制、事务处理等)

因此考虑使用动态代理模式,根据上面所说,关键需要实现以下几点:

²  使用JAVA提供的Compiler在构造代理类时根据传递进来的接口,使得总代理类

实现该接口,并实现里面的所有方法;

²  创建代理类的共同接口,即所有代理类都必须实现该接口,并实现里面的invoke

方法,invoke方法其中一个参数是Method,而代理类已经把代理对象聚合进来了,故只需要对代理对象调用Method方法即可。具体实现如下:

Ø  接口Moveable – Moveable.java

package com.yilong.designpattern.proxy;

public interface Moveable {

    void move();

    void stop(int i, int j);

}

Ø  代理类接口 – InvocationHandler.java。该接口有个抽象的方法invoke

参数包括生成的代理的对象Object o,要调用的方法Method m,方法的参数Object[] parameters

package com.yilong.designpattern.proxy;

import java.lang.reflect.Method;

public interface InvocationHandler {

    public void invoke(Object o, Method m, Object[] parameters);

}

Ø  时间记录的代理 – TimeHandler.java。实现InvocationHandler接口,将

代理的对象聚合到类中:private Object targer;

package com.yilong.designpattern.proxy;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

public class TimeHandler implements InvocationHandler {

    private Object target;

   

    public TimeHandler(Object target) {

       super();

       this.target = target;

    }

    public void invoke(Object o, Method m, Object[] parameters) {

       long startTime = System.currentTimeMillis();

       System.out.println("Start Time:" + startTime);

       try {

           m.invoke(target, parameters);

       } catch (Exception e) {

           e.printStackTrace();

       }

       long endTime = System.currentTimeMillis();

       System.out.println("End Time:" + endTime);

       System.out.println("Cost Time:" + (endTime - startTime));

    }

    public Object getO() {

       return target;

    }

    public void setO(Object o) {

       this.target = o;

    }

}

Ø  坦克 – Tank.java。实现了Moveable接口

package com.yilong.designpattern.proxy;

import java.util.Random;

public class Tank implements Moveable {

    public void move() {

       System.out.println("Tank Moving...");

       try {

           Thread.sleep(new Random().nextInt(10000));

       } catch (InterruptedException e) {

           e.printStackTrace();

       }

    }

    public void stop(int i, int j) {

       System.out.println("Tank Stopping...");

       try {

           Thread.sleep(new Random().nextInt(10000));

       } catch (InterruptedException e) {

           e.printStackTrace();

       }

    }

}

Ø  实现动态代理的核心类Proxy – Proxy.java。根据传递进来的接口和代理类产

生新的代理实例。

package com.yilong.designpattern.proxy;

import java.io.File;

import java.io.FileWriter;

import java.lang.reflect.Constructor;

import java.lang.reflect.Method;

import java.net.URL;

import java.net.URLClassLoader;

import javax.tools.JavaCompiler;

import javax.tools.StandardJavaFileManager;

import javax.tools.ToolProvider;

import javax.tools.JavaCompiler.CompilationTask;

public class Proxy {

    public static Object newProxyInstance(Class infc,

InvocationHandler h) throws Exception {

       String methodStr = "";//接收代理实例要实现的全部方法

       String parameterStr = "";//代理对象的方法中的参数字符串

       String parameterValue = "";//构造Method需要的参数类型字符串

       String objStr = "";//调用代理对象的方法时需要的参数列表

       String rt = "/r/n";//换行符

       //存放传递进来的接口的全部方法;

       Method[] methods = infc.getMethods();

       for(Method m : methods) {

           parameterStr = "";

           parameterValue = ", ";

           objStr = "";

           char identify = 'a';

           int index = 0;

           for(Class c : m.getParameterTypes()) {

              parameterValue += c.getCanonicalName() + ".class, ";

              parameterStr += c.getCanonicalName() + " " + identify

+ ", ";

              objStr += "        objs[" + index + "] = " + identify

+ ";" + rt;

              identify ++;

              index ++;

           }

           parameterValue = parameterValue.substring(0,

parameterValue.length() - 2);

           if(parameterStr.length() >= 2) {

              parameterStr = parameterStr.substring(0,

parameterStr.length() - 2);

           }

           methodStr += "    public void " + m.getName() + "(" + parameterStr + ") {" + rt +

                      "        Object[] objs = new Object[" + index-- + "];" + rt + objStr + rt +

                      "        try {" + rt +

                      "            Method md = " + infc.getName() + ".class.getMethod(/"" + m.getName() + "/"" + parameterValue + ");" + rt +

                      "            h.invoke(this, md, objs);" + rt +

                      "        } catch(Exception e) {" + rt +

                      "            e.printStackTrace();" + rt +

                      "        }" + rt +

                      "    }" + rt;

       }

      

       String src =

           "package com.yilong.designpattern.proxy;" + rt +

           "import java.lang.reflect.Method;" + rt +

           "public class NewProxy implements " + infc.getName() + "{" + rt +

          

           "    com.yilong.designpattern.proxy.InvocationHandler h;" + rt +

           "    public NewProxy(InvocationHandler h) {" + rt +

           "        this.h = h;" + rt +

           "    }" + rt + methodStr +

           "}";

       //System.out.println(System.getProperty("user.dir"));//D:/MyEclipse/Proxy1

       String fileName = "D:/MyEclipse/src/com/yilong/designpattern/proxy/NewProxy.java";

       File f = new File(fileName);

        FileWriter fw = new FileWriter(f);

       fw.write(src);

       fw.close();

      

       //compile

       JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

       StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);

       Iterable units = fileMgr.getJavaFileObjects(fileName);

       CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);

       t.call();

       fileMgr.close();

      

       //load into memery and create an instance

       URL[] urls = new URL[] {new URL("file:/D:/MyEclipse/src/")};

        URLClassLoader ul = new URLClassLoader(urls);

       Class c = ul.loadClass("com.yilong.designpattern.proxy.NewProxy");

       //System.out.println(c);

       Constructor ctr = c.getConstructor(InvocationHandler.class);

       Object moveObject = ctr.newInstance(h);

       return moveObject;

    }

}

Ø  测试类 – Client.java

package com.yilong.designpattern.proxy;

public class Client {

    public static void main(String[] args) throws Exception {

       Tank t = new Tank();

       InvocationHandler timeHandler = new TimeHandler(t);

       Moveable m = (Moveable)Proxy.newProxyInstance

(Moveable.class, timeHandler);

       m.move();

       m.stop(1, 2);

    }

}

Ø  动态编译生成的文件 – NewProxy.java

package com.yilong.designpattern.proxy;

import java.lang.reflect.Method;

public class NewProxy implements com.yilong.designpattern.proxy.Moveable{

    com.yilong.designpattern.proxy.InvocationHandler h;

    public NewProxy(InvocationHandler h) {

        this.h = h;

    }

    public void stop(int a, int b) {

        Object[] objs = new Object[2];

        objs[0] = a;

        objs[1] = b;

        try {

            Method md = com.yilong.designpattern.proxy.Moveable.class.getMethod("stop", int.class, int.class);

            h.invoke(this, md, objs);

        } catch(Exception e) {

            e.printStackTrace();

        }

    }

    public void move() {

        Object[] objs = new Object[0];

        try {

            Method md = com.yilong.designpattern.proxy.Moveable.class.getMethod("move");

            h.invoke(this, md, objs);

        } catch(Exception e) {

            e.printStackTrace();

        }

    }

}

    下面是JDK的代理,主要涉及JDK中的两个对象:

(1)     Proxy : 跟上面模拟的相似,是用来产生总代理的一个实例,需要传递代理类的类

型、代理的接口对象和代理对象(已经接受了要代理的那个类的一个实例)

(2)     InvocationHandler接口 : 所有要实现代理的类(事务处理、异常处理等)都需要实

现该接口,并实现接口的invoke方法;

Ø  文件User.java

package com.yilong.jdk.proxy;

public class User {

    private int id;

    private String name;

   

    public User(int id, String name) {

       this.id = id;

       this.name = name;

    }

   

    public int getId() {

       return id;

    }

    public void setId(int id) {

       this.id = id;

    }

    public String getName() {

       return name;

    }

    public void setName(String name) {

       this.name = name;

    }

}

Ø  文件UserService.java

package com.yilong.jdk.proxy;

public interface UserService {

    public void addUser(User u);

}

Ø  文件UserServiceImpl.java

package com.yilong.jdk.proxy;

import java.util.Random;

public class UserServiceImpl implements UserService {

    public void addUser(User u) {

       System.out.println(u.getId());

       System.out.println("1. Add User To Database!");

       System.out.println("2. Add Logger To LogFile!");

       try {

           Thread.sleep(new Random().nextInt(5000));

       } catch (InterruptedException e) {

           e.printStackTrace();

       }

    }

}

Ø  文件TimeHandler.java – 日志记录的代理

package com.yilong.jdk.proxy;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

public class TimeHandler implements InvocationHandler {

    private Object target;

    public TimeHandler(Object target) {

       super();

       this.target = target;

    }

    public Object invoke(Object proxy, Method method, Object[] args)

           throws Throwable {

       long startTime = System.currentTimeMillis();

       System.out.println("Start Time:" + startTime);

       Object obj = method.invoke(target, args);

       long endTime = System.currentTimeMillis();

       System.out.println("End Time:" + endTime);

       return obj;//将调用method后的返回值作为参数传递回去

    }

}

Ø  文件TransactionHandler.java – 事务处理的代理

package com.yilong.jdk.proxy;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

public class TransactionHandler implements InvocationHandler {

    private Object target;

    public TransactionHandler(Object target) {

       this.target = target;

    }

    public Object invoke(Object proxy, Method method, Object[] args)

           throws Throwable {

       System.out.println("Transaction Strat!");

       Object obj = method.invoke(target, args);

       System.out.println("Transaction Commit!");

       return obj;

    }

}

Ø  测试类Client.java

package com.yilong.jdk.proxy;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Proxy;

public class Client {

    public static void main(String[] args) {

       User u = new User(1, "yilong");

       UserService userServiceImpl = new UserServiceImpl();

       //产生事务代理对象,传递需要被代理的对象实例

       InvocationHandler transactionHandler = new

TransactionHandler(userServiceImpl);

       //产生时间日志的代理对象,传递需要被代理的对象实例

       InvocationHandler timeHandler = new

TimeHandler(transactionHandler);

       InvocationHandler TimeTransaction =

(InvocationHandler)Proxy.newProxyInstance(

              transactionHandler.getClass().getClassLoader(),

              transactionHandler.getClass().getInterfaces(),

              timeHandler);

      

       UserService userServiceProxy =

(UserService)Proxy.newProxyInstance(

userServiceImpl.getClass().getClassLoader(),

userServiceImpl.getClass().getInterfaces(), TimeTransaction);

              userServiceProxy.addUser(u);

    }

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值