Java动态代理模式
1. 代理:一个角色代表别一个角色来完成某些特定的功能。
比如:生产商,中间商,客户这三者这间的关系
客户买产品并不直接与生产商打交道,也不用知道产品是如何产生的,客户只与中间商打交道,而中间商就可以对产品进行一些包装,提供一些售后的服务。
代理模式有三个角色: 1. 抽象主题角色 2. 代理主题角色 3. 实际被代理角色
其它类通过访问代理主题角色来访问实际被代理角色。
2. 下面我们来个一个静态代理的实现。
我以一个坦克为例。
抽象主题角色:Moveable
- package com.gjy.proxy;
- blic interface Moveable {
- void move();
代理主题角色:TanktimeProxy
- package com.gjy.proxy;
- public class TanktimeProxy implements Moveable{
- private Moveable t;
- public TanktimeProxy(Moveable t) {
- super();
- this.t = t;
- }
- @Override
- public void move() {
- long time1 = System.currentTimeMillis();
- System.out.println("time1="+time1);
- t.move();
- long time2 = System.currentTimeMillis();
- System.out.println("time2="+time2);
- System.out.println("运行时间为:"+(time2-time1));
- }
- }
实际被代理对象:Tank
- package com.gjy.proxy;
- public class Tank implements Moveable{
- @Override
- public void move() {
- System.out.println("TanK moving........");
- }
- }
测试:
- package com.gjy.proxy;
- public class TestTank {
- public static void main(String[] args) {
- Tank t = new Tank();
- Moveable move = new TanktimeProxy(t);
- move.move();
- }
- }
从上例可以看到代理主题角色:TanktimeProxy实现了对Tank的move()方法运行时间的计算,而TanktimeProxy,Tank都实现了Moveable接口,通过调用TanktimeProxy的move()方法我们可以实现对Tank的move()方法的运行时间的计算,而不用在Tank的move()方法中作任何实现,这就是代理的作用。代理实现时TanktimeProxy,Tank必需实现Moveable接口。
下面我想在TanK的move()方法前后加上日志:
我必需再写一个类来实现这一功能:
- package com.gjy.proxy;
- public class TanklogProxy implements Moveable{
- private Moveable t;
- public TanklogProxy(Moveable t) {
- super();
- this.t = t;
- }
- @Override
- public void move() {
- System.out.println("start move........");
- t.move();
- System.out.println("end move......");
- }
- }
测试:
- package com.gjy.proxy;
- public class TestTank {
- public static void main(String[] args) {
- Tank t = new Tank();
- Moveable move = new TanktimeProxy(t);
- Moveable movet = new TanklogProxy(move);
- movet.move();
- }
- }
这样我通过代理在Tank的move()方法前后加入了日志和时间统计的功能,由于TanktimeProxy,TanklogProxy都实现了Moveable接口,所以TanklogProxy可以代理TanktimeProxy,反过来也可以,它们对Tank的代理顺序是可以交换的。
如果我想在Tank的move()方法调用的前后加入更多的功能,是不是要写更多的代理主题角色,这样子会使得代码过于臃肿,不易于维护,那有没有什么办法可以解决呢,答案是可以的,我们可以动态的来生成代理主题角色,来代理所有的被代理对象,这就是动态代理。
下面是一个简单的动态代理的实现:
类图如下:
首先编写一个生成代理主题角色的类:Proxy
- package com.gjy.DynamicProxy;
- 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 newProxyIntenct(Class infac,InvocationHandler h) throws Exception{
- String br ="\r\n";
- String methString ="";
- Method[] method = infac.getMethods();
- for(Method m: method){
- methString = " @Override"+ br +
- " public void "+m.getName()+"() {"+ br +
- " try {" + br +
- " Method md ="+ infac.getName()+".class.getMethod(\""+m.getName()+"\");"+ br +
- " h.invoke(this,md);" + br +
- " }catch (Exception e){ "+ br+
- " e.printStackTrace();" + br +
- " }" + br +
- " }";
- }
- String src =
- "package com.gjy.DynamicProxy;" + br +
- "import java.lang.reflect.Method;" + br +
- "public class $Proxy implements "+infac.getName()+"{" + br +
- " private com.gjy.DynamicProxy.InvocationHandler h;" + br +
- " public $Proxy(InvocationHandler h) {" + br +
- " super();" + br +
- " this.h = h;" + br +
- " }" + br + br +
- methString +br +
- "}";
- MakFileUtil.createFile("D:/src/com/gjy/DynamicProxy");
- //生成java文件
- String fileName ="D:\\src\\com\\gjy\\DynamicProxy\\$Proxy.java";
- System.out.println(fileName);
- File file = new File(fileName);
- FileWriter fWriter = new FileWriter(file);
- fWriter.write(src);
- fWriter.flush();
- fWriter.close();
- //生成class文件,jdk6提供的工具类
- JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
- //System.out.println(compiler.getClass().getName());
- StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
- Iterable units = fileManager.getJavaFileObjects(fileName);
- CompilationTask task = compiler.getTask(null, fileManager, null, null, null, units);
- task.call();
- fileManager.close();
- //装载到内存,生成新对象
- URL[] urls = new URL[]{new URL("file:/"+"D:\\src\\")};
- URLClassLoader loader = new URLClassLoader(urls);
- Class c = loader.loadClass("com.gjy.DynamicProxy.$Proxy");
- //通过有参的构造器反射生成代理类的实例
- Constructor ctr = c.getConstructor(InvocationHandler.class);
- Object obj = (Object) ctr.newInstance(h);
- return obj;
- }
- }
代理对象的操作接口:
- package com.gjy.DynamicProxy;
- import java.lang.reflect.Method;
- public interface InvocationHandler {
- void invoke(Object o,Method m);
- }
通过实现代理对象的操作接口实现对被代理对象的方法调用前后的逻辑操作。
TimeInvocationHandler实现InvocationHandler接口:
- package com.gjy.DynamicProxy;
- import java.lang.reflect.Method;
- public class TimeInvocationHandler implements InvocationHandler {
- private Object target;
- public TimeInvocationHandler(Object target) {
- super();
- this.target = target;
- }
- @Override
- public void invoke(Object o, Method m) {
- long time1 = System.currentTimeMillis();
- System.out.println("time1="+time1);
- try {
- m.invoke(target);
- } catch (Exception e) {
- e.printStackTrace();
- }
- long time2 = System.currentTimeMillis();
- System.out.println("time2="+time2);
- System.out.println("Tank 的启动时间:"+(time2-time1));
- }
- }
实际被代理对象:Tank
- package com.gjy.DynamicProxy;
- ublic class Tank implements Moveable{
- @Override
- public void move() {
- int a = 5;
- int b = 6;
- int c = 0;
- int d = 0;
- for (int i = 0; i < 1000; i++) {
- d = i;
- }
- c = ((a+b)/2)*12;
- System.out.println("TanK moving..Tank 的速度是"+c);
- }
抽象代理主题:Moveable
- package com.gjy.DynamicProxy;
- public interface Moveable {
- void move();
- }
- }
测试:
- package com.gjy.DynamicProxy;
- public class TestTank {
- public static void main(String[] args) throws Exception{
- Tank t = new Tank();
- Moveable moveable = (Moveable) Proxy.newProxyIntenct(Moveable.class,new TimeInvocationHandler(t));
- moveable.move();
- }
- }
创建文件夹工具类:MakFileUtil
- package com.gjy.DynamicProxy;
- import java.io.File;
- import java.io.IOException;
- import java.util.StringTokenizer;
- public class MakFileUtil {
- public static void createFile(String pathstr) throws IOException{
- // File dirFile;
- // boolean bFile;
- // bFile = false;
- //
- // dirFile = new File("E:\\test");
- // bFile = dirFile.exists();
- //
- // if( bFile == true ){
- // System.out.println("The folder exists.");
- // }else{
- // System.out.println("The folder do not exist,now trying to create a one...");
- // bFile = dirFile.mkdir();
- // if( bFile == true ){
- // System.out.println("Create successfully!");
- // }else{
- // System.out.println("Disable to make the folder,please check the disk is full or not.");
- // System.exit(1);
- // }
- //创建多级目录
- String path = pathstr;
- //为指定字符串构造一个 string tokenizer。 "/"字符是分隔标记的分隔符。分隔符字符本身不作为标记。
- StringTokenizer st = new StringTokenizer(path,"/");
- String path1 = st.nextToken()+"/";
- String path2 = path1;
- while(st.hasMoreTokens())
- {
- path1 = st.nextToken()+"/";
- path2 += path1;
- File inbox = new File(path2);
- if(!inbox.exists())
- inbox.mkdir();
- }
- }
- }
以上就是动态代理的一个模拟实现,测试时我们不管Proxy和InvocationHandler是怎么实现的,我们只要实现InvocationHandler接口完成相应的逻辑,然后调用Proxy
的newProxyIntenct(Class infac, InvocationHandler h) 传入相应的接口,和InvocationHandler的实现类就可以实现对被代理对象的代理。也就是说Proxy和InvocationHandler写好之后永远不变。
在运行过程中Proxy会动态生成代理主题角色,示例中生成的代理主题角色的代码如下:
- import java.lang.reflect.Method;
- public class $Proxy implements com.gjy.DynamicProxy.Moveable{
- private com.gjy.DynamicProxy.InvocationHandler h;
- public $Proxy(MakFileUtil h) {
- super();
- this.h = h;
- }
- @Override
- public void move() {
- try {
- Method md =com.gjy.DynamicProxy.Moveable.class.getMethod("move");
- h.invoke(this,md);
- }catch (Exception e){
- e.printStackTrace();
- }
- }
- }
如果我们想在Tank的move()方法被调用的前后加入其它的逻辑处理,我们只需实现InvocationHandler接口,下面是给move()加日志:
- package com.gjy.DynamicProxy;
- import java.lang.reflect.Method;
- public class LogInvocationHandler implements InvocationHandler {
- private Object target;
- public LogInvocationHandler(Object target) {
- super();
- this.target = target;
- }
- @Override
- public void invoke(Object o, Method m) {
- System.out.println("Tank start...........");
- try {
- m.invoke(target);
- } catch (Exception e) {
- e.printStackTrace();
- }
- System.out.println("Tank stop..............");
- }
- }
测试:
- package com.gjy.DynamicProxy;
- public class TestTank {
- public static void main(String[] args) throws Exception{
- Tank t = new Tank();
- Moveable moveable = (Moveable) Proxy.newProxyIntenct(Moveable.class,new TimeInvocationHandler(t));
- Moveable moveable2 = (Moveable) Proxy.newProxyIntenct(Moveable.class, new LogInvocationHandler(moveable));
- moveable2.move();
- }
- }
相关推荐
Java 设计模式 代理模式介绍,含源码
JAVA-设计模式-结构型模式-代理模式
Java设计模式,代理模式,包含动态代理的Demo,具体的思想与实现有很多讲得很好的老师,我是看厉风行老师的视频学的,讲得不错,简单易懂
java常用设计模式-代理模式
JAVA设计模式-day2,请的行业大能讲得课程,涉及:创建模式(5种: 1、 工厂方法模式(Factory Method); 2、 抽象工厂模式; 3、 单例模式(Singleton) • 4、 建造者模式(Builder); 5、 原型模式(Prototype...
java设计模式,设计模式公司出品。策略模式,代理模式,单例模式,多例模式,工厂模式,门面模式等。
java模式设计-代理模式之动态代理.ppt
java设计模式视频教程-代理模式, 深层了解java的设计模式
java 模式 设计 代理模式 ,动态代理跟反射机制的内容相关
设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段...
Java设计模式——代理设计模式(静态代理和动态代理) 各种情况例子源码
基于Java的设计模式——代理模式demo的实现(高分课设)个人经导师指导并认可通过的98分大作业设计项目,适用人群:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业或毕业设计,作为“参考资料”使用...
本课程适合所有需要弥补JAVA设计模式的同学,课件内容制作精细,由浅入深,适合入门或进行知识回顾。 【完整课程列表】 基于java程序语言的设计java模式课程 01-设计模式概述(共36页).pptx 基于java程序语言的...
Java设计模式之代理模式(结构)Java设计模式之代理模式(结构)Java设计模式之代理模式(结构)Java设计模式之代理模式(结构)Java设计模式之代理模式(结构)
JAVA设计模式之代理模式实例
1.2.7 代理模式 34 1.3 行为型模式 37 1.3.1 责任链模式 37 1.3.2 命令模式 40 1.3.3 解释器模式 43 1.3.4 迭代器模式 45 1.3.5 中介者模式 49 1.3.6 备忘录模式 52 1.3.7 观察者模式 54 1.3.8 状态模式 58 1.3.9 ...
自己写的Java的代理模式的实现,有兴趣的可以下载看看
Java 经典设计模式讲解以及项目实战 设计模式简介:主要介绍各种设计模式的概念和运用场景等 设计模式综合运用:主要是笔者在实际工作中运用到的一些设计模式综合运用事例的提炼 Spring设计模式简介:主要是讲述...
本系统使用Java代码实现,是设计模式的期末课程设计,共使用了5种设计模式,分别是**原型模式、单例模式、抽象工厂模式、代理模式、建造者模式。*,希望对各位有帮助
代理模式JAVA源程,正在学设计模式的朋友可以看下。比较容易理解。