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设计模式的知识点说明: 1. 策略模式(Strategy Pattern)是一种行为设计模式,允许在运行时选择算法的行为。策略模式的意图是定义一系列算法,将每个算法封装起来,并使它们可以...
这个“JAVA设计模式-chm版”资源显然包含了关于Java设计模式的详细信息,便于理解和应用。设计模式是对常见问题的解决方案的标准化描述,它们在软件工程中起到了重要的作用,帮助开发者创建可维护、可扩展且易于理解...
Java设计模式是软件工程中的一种重要思想,它总结了在解决特定问题时,程序员们反复使用的一些最佳实践和解决方案。这个资源"Java设计模式----通俗易懂版"显然是一个专门针对初学者或需要深入理解设计模式的开发者...
JAVA-设计模式-结构型模式-代理模式
总结来说,Java设计模式中的代理模式提供了一种优雅的方式来控制对目标对象的访问,并扩展其功能。动态代理更是使得这一过程更加灵活,降低了代码的维护成本。通过学习和应用代理模式,开发者可以更好地设计和实现...
Java设计模式、程序设计、反射、注解和泛型是Java开发中的核心概念,它们各自在不同的场景下发挥着重要作用,构建出高效、可维护的软件系统。 首先,Java设计模式是面向对象编程中的一种最佳实践,是解决常见问题的...
### Java设计模式详解 #### 1. 设计模式概述 设计模式是在软件设计过程中针对常见问题的可重复使用的解决方案。这些模式有助于解决软件设计中出现的常见问题,并提供了一种标准化的方法来解决问题,使得代码更加...
### Java设计模式详解 #### 一、概述 Java设计模式是一种在特定场景下解决软件设计问题的方法论。设计模式能够帮助开发者以一种更加系统化、标准化的方式来构建软件系统,提高软件的可维护性和可扩展性。本文档...
### Java设计模式详解 #### 创建型模式 **1.1 工厂方法(Factory Method)** 工厂方法模式定义了一个创建对象的接口,但允许子类决定实例化哪一个类。这使得一个类的实例化可以被推迟到其子类。这种模式在以下...
### Java设计模式的应用 #### 一、引言 在当今快速发展的软件开发领域,Java作为一门功能强大且灵活的语言,不仅拥有丰富的API资源,还能与强大的数据库系统无缝对接。这使得许多开发人员能够以模块化的形式构建...
这篇名为"JAVA设计模式---100%推荐"的资源,可能是对Java设计模式的深入解析,旨在帮助开发者更好地理解和应用这些模式。 设计模式通常分为三类:创建型、结构型和行为型。创建型模式涉及对象的实例化过程,如单例...
Java 设计模式 - 代理模式 代理模式(Proxy Pattern)是一种常用的设计模式,提供了间接访问目标对象的一种方式,即通过代理对象访问目标对象。这样做的好处是,可以在不改变原有目标对象的基础上,对目标对象增加...
JAVA设计模式是编程领域中非常重要的概念,它为软件开发人员提供了在特定情境下解决常见问题的模板。设计模式公司出品的《JAVA设计模式》书籍,详细介绍了多种设计模式,适合不同水平的程序员学习和使用。 首先,...
本资源主要介绍了JAVA设计模式的原则和23种设计模式的总结。设计模式是软件设计中的一种解决方案,能够使软件系统更加灵活、可维护和可扩展。本资源首先介绍了设计模式的六大原则,包括单一责任原则、开闭原则、里氏...
通过阅读《设计模式-Java语言中的应用》,读者不仅可以掌握设计模式的基本概念和原理,还能学习到如何在实际项目中选择合适的设计模式,以及如何优雅地在Java代码中实现这些模式。这将有助于提升开发者的编程技巧,...
JAVA设计模式-day2,请的行业大能讲得课程,涉及:创建模式(5种: 1、 工厂方法模式(Factory Method); 2、 抽象工厂模式; 3、 单例模式(Singleton) • 4、 建造者模式(Builder); 5、 原型模式(Prototype...
《Java与模式》是阎宏博士的一本经典著作,它深入浅出地介绍了如何在Java编程中应用设计模式。这本书不仅讲解了设计模式的基本概念,还涵盖了23种经典的GOF设计模式,并结合Java语言特性进行了详细的解释和实例演示...
Java设计模式是软件工程中的一种重要思想,它代表了在解决特定问题时的最佳实践。这些模式都是经过时间和经验验证的设计解决方案,可以提高代码的可读性、可维护性和复用性。Java设计模式主要分为三类:创建型模式、...
在软件工程中,设计模式是一种被广泛接受的解决特定设计问题的...因此,深入学习和理解Java设计模式对于任何Java开发者来说都是至关重要的。通过文档中的图解和代码示例,读者可以更好地理解和掌握这些模式的实际应用。