设计模式之动态代理

用动态代理要解决的问题:

当我们想测试别人给出的jar包中的一个方法的运行时间,而我们没有源码,无法修改代码(如果有源码可以在方法前得到系统时间,

在方法后得到系统时间,两个值相减就能实际),怎么可以得到运行时间?

 

聚合的概念:

在一个类中调用另一个类

①写一个静态代理

(静态代理是针对一个或几个方法时是比较方便的,对于几百个或上千个的话,就不方便了,因为要写几百个或上千个静态代理类)

实现的接口:Moveable.java

package com.bjsxt.service;

 

public interface Moveable {

    void move();

}

 

目标类:Tank.java

package com.bjsxt.service;

 

public class Tank implements Moveable{

 

    @Override

    public void move() {

        System.out.println("坦克正在移动……");

    }

 

}

 

静态代理类:StaticProxy.java

package com.bjsxt.service;

 

public class StaticProxy implements Moveable{

 

    Moveable t = new Tank();

    @Override

    public void move() {

       System.out.println("坦克移动开始时间:        "+System.currentTimeMillis());//前面加的信息

        t.move();

       System.out.println("坦克移动结束时间:        "+System.currentTimeMillis());//后面加的信息

    }

 

}

 

测试静态代理:TestStaticProxy.java

package com.bjsxt.service;

 

public class TestStaticProxy {

    public static void main(String []arg){

        StaticProxy staticProxy = new StaticProxy(); 

        staticProxy.move();

    }

}

 

②.动态代理

总结概括:大概思路是,把目标类(Tank.java)的方法move()通过(TimeInvocationHandler.java)中的invoke(Object o,Method method)方法,通过反射机制invoke(目标类Tank)类中的方法,在方法前后加入一些需要执行的代码,然后把接口和相应的TimeInvocationHandler传入到能够获得代理类的类Proxy的newProxyInstance(Class infce, InvocationHandler invocationHandler) 方法中,在这个方法中,它把重新封装的方法(在前后加入了代码的方法)写入实现了对应接口的类中,并连接成字符串,然后用java的编译工具把生成类文件编译成.class文件并装入内存,通过.class文件生成对象,返回这个对象(代理对象)

实现的接口:Moveable.java

package com.bjsxt.service;

 

public interface Moveable {

    void move();

}

 

实现的接口:InvocationHandler

package com.bjsxt.proxy;

 

import java.lang.reflect.Method;

 

public interface InvocationHandler {

    public void invoke(Object o, Method m);

}

 

 

目标类:Tank.java

package com.bjsxt.service;

 

public class Tank implements Moveable{

 

    @Override

    public void move() {

        System.out.println("坦克正在移动……");

    }

 

}

 

具体handler的类:TimeInvocationHandler.java 

package com.bjsxt.proxy;

 

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 method) {

        long start = System.currentTimeMillis();

        try {

            method.invoke(target);

        } catch (Exception e) {

            e.printStackTrace();

        }

        long end = System.currentTimeMillis();

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

    }

 

}

 

用来产生代理类的静态类:Proxy 

package com.bjsxt.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 infce, InvocationHandler invocationHandler) throws Exception { //JDK6 Complier API, CGLib, ASM

String methodStr = "";

String rt = "\r\n";

Method[] methods = infce.getMethods();

for(Method method : methods) {

methodStr += " @Override" + rt + 

" public void " + method.getName() + "() {" + rt +

"     try {" + rt +

"     Method method = " + infce.getName() + ".class.getMethod(\"" +                                                                                        method.getName() + "\");" + rt +

"     invocationHandler.invoke(this, method);" + rt +

"     }catch(Exception e) {"+ rt 

+ " e.printStackTrace();" + rt

+ " }" + rt +

"}";

}

String src = 

"package com.bjsxt.proxy;" +  rt +

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

"public class $Proxy1 implements " + infce.getName() + "{" + rt +

"    com.bjsxt.proxy.InvocationHandler invocationHandler;" + rt +

"    public $Proxy1(InvocationHandler invocationHandler) {" + rt +

"        this.invocationHandler = invocationHandler;" + rt +

"    }" + rt + methodStr +

"}";

String fileName = 

"d:/src/com/bjsxt/proxy/$Proxy1.java";//java的源码

File f = new File(fileName);

FileWriter fw = new FileWriter(f);

fw.write(src);

fw.flush();

fw.close();

//compile

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();//获得java的编译器

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 memory and create an instance

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

URLClassLoader ul = new URLClassLoader(urls);

Class c = ul.loadClass("com.bjsxt.proxy.$Proxy1");

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

Object proxyObject = ctr.newInstance(invocationHandler);

return proxyObject;

}

}

 

测试类:Client.java 

package com.bjsxt.proxy;

 

public class Client {

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

        Tank target = new Tank();//被代理对象

        InvocationHandler timeInvocationHandler = new TimeInvocationHandler(target);//代理对象

        Moveable proxyMoveable = (Moveable)Proxy.newProxyInstance(Moveable.class, timeInvocationHandler);//通过静态方法实现代理,得到代理对象,

        proxyMoveable.move();

    }

}

//可以对任意的对象、任意的接口方法,实现任意的代理Test

 

③jdk的动态代理实现

注意:用jdk实现动态代理,目标类要实现接口,如果用hibernate的话,就不用实现接口

            实际底层用的就是jdk的动态代理,如果不实现接口的话,用的就是继承            

 

实现的接口:Moveable.java

package com.bjsxt.service;

 

public interface Moveable {

    void move();

}

 

目标类:Tank.java

package com.bjsxt.service;

 

public class Tank implements Moveable{

 

    @Override

    public void move() {

        System.out.println("坦克正在移动……");

    }

 

}

处理

处理类,加入自己的逻辑:TankInvocationHandler.java

package com.zhk.test.Jdkproxy;

 

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

 

public class TankInvocationHandler implements InvocationHandler{

Object target;

public TankInvocationHandler(Object target) {

super();

this.target = target;

}

 

@Override

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

// TODO Auto-generated method stub

System.out.println("开始执行移动……");

Object result = method.invoke(target, args);//第一个参数时指调用method方法的对象,第二个参数时指传入调用方法中的参数

System.out.println("移动结束……");

return result;

}

}

 

测试jdk动态代理:TestJdkProxy.java

 

package com.zhk.test.Jdkproxy;

 

import java.lang.reflect.Proxy;

 

public class TestJdkProxy {

    public static void main(String []args){

    Moveable tankTarget = new Tank();

    TankInvocationHandler tankInvocationHandler = new TankInvocationHandler(tankTarget);

    Moveable tankProxyClass = (Moveable)Proxy.newProxyInstance(

            tankTarget.getClass().getClassLoader(), 

            tankTarget.getClass().getInterfaces(), 

            tankInvocationHandler);//第一个参数时被代理类的classloader,第二个参数时被代理类的接口,

                                    //第三个是handler(也就是加处理逻辑的代码类)

    tankProxyClass.move();

    }

    

    

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿的十万个为什么

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值