深度模拟java动态代理实现机制系类之三

这里的内容就比较复杂了,要实现的是对任意的接口,对任意指定的方法,以及对任意指定的代理类型进行代理,就更真实的模拟出java虚拟机的动态代理机制

罗列一下这里涉及的类、接口之间的关系,方便大家学习。
1、InvocationHandler接口,用来处理指定的方法,即对特定方法的代理,处理的具体实现交由子类实现
2、TimeHandler类,实现了InvocationHandler接口的子类,具体的代理实现是进行时间代理
3、Proxy类,用于产生代理类的类
4、Moveable接口,举例过程中各类要实现的统一接口
5、Tank类,实现了Moveable接口,即被代理的类
6、Cilent,操作客户端

先把整个的思路理一下:
首先在Client端,new一个被代理的对象Tank,Tank对象作为构造参数传入代理处理类TimeHandler,new出一个TimeHandler对象
Tank的接口Moveable和TimeHandler对象作为参数传入Proxy,Proxy调用newProxyInstance方法,该方法中对接口的所有的方法,利用
TimeHandler对象进行代理,(可以简单理解为将接口方法与TimeHandler代理方法结合),生成新的代理对象的java文件、class文件、
然后加载进入内存,利用反射获得一个代理对象,返回该代理对象,在Client端调用则调用了代理对象方法;

1、InvocationHandler接口

package com.csu.proxy;

import java.lang.reflect.Method;
//对任意方法自定义处理
//方法调用的处理器
public interface InvocationHandler {   //定义一个接口,用来处理方法,处理的具体实现交由子类实现

public void invoke(Object o, Method m);  //对某个指定方法的处理
}

2、TimeHandler类

package com.csu.proxy;

import java.lang.reflect.Method;
public class TimeHandler implements InvocationHandler {
   private Object target;//被代理的对象

public Object getT() {
        return target;
    }

public void setT(Object t) {
        this.target = t;
    }

public TimeHandler(Object target) {
        this.target = target;
    }

@Override
    public void invoke(Object o,Method m){  //必须指定具体对象对具体的方法的调用
        long start = System.currentTimeMillis();
        System.out.println("start time is " + start);
        System.out.println(o.getClass().getName());
        //m 调用方法
        try {
            m.invoke(target); 
        } catch (Exception e) {e.printStackTrace();}

long end = System.currentTimeMillis();
        System.out.println("end time is "+end);
        System.out.println("time is "+(end - start));
    }
}

3、Moveable接口

package com.csu.proxy;

public interface Moveable {
    void move();
}

4、Tank类

package com.csu.proxy;

import java.util.Random;

public class Tank implements Moveable {

@Override
    public void move() {
        
        System.out.println("Tank Moving...");
        try {
            Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
    }    
    
}

5、Proxy类

package com.csu.proxy;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
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;

/**
方便大家阅读,关注主要的逻辑思路,将在前面博客的已经写过的注释代码清除,因为这是一系列,有很多代码引用
有想要看的,去上几篇文章看吧
**/

//该类要实现对任意接口,任意方法,以及任意的代理 的实现
public class ProxyG3 {
    public static Object newProxyInstance(Class intf, InvocationHandler h) throws Exception{
    //invocationHandler当成参数,指定代理的类型,即指定对方法要进行什么处理

//*****************1、获得java文件**********************************
    String methodsString = "";  
        String rt = "\r\n";

Method[] methods = intf.getMethods();
        for(Method m : methods) {
            methodsString += "@Override" + rt +
                    "public void " + m.getName() + "() {" + rt +
                    "    try {" + rt +
                    "    Method md = " + intf.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
                    "    h.invoke(this, md);" + rt +
                    "    }catch(Exception e) {e.printStackTrace();}" + rt +

"}";
        }

String src =
                        "package com.csu.proxy;" +  rt +
                        "import java.lang.reflect.Method;" + rt +
                        "public class TankTimeProxy implements " + intf.getName() + "{" + rt +
                        "    public TankTimeProxy(InvocationHandler h) {" + rt +
                        "        this.h = h;" + rt +
                        "    }" + rt +

"    com.csu.proxy.InvocationHandler h;" + rt +

methodsString +
                        "}";
        String fileName = "g:/src/com/csu/proxy/TankTimeProxy.java";//放在指定的地方
        File f = new File(fileName);
        FileWriter fw = new FileWriter(f);
        fw.write(src);
        fw.flush();
        fw.close();
    /**
    这里重点说一下:用于存放代理对象TankTimeProxy的java和class文件的包名要工程中的其他java文件的包名一致,查看代码你会发现
    工程的java文件和生成的代理对象的java文件的包名都是 com.csu.proxy;
    **/

//****************2、获得class文件****************************************

 //获得编译器对象
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        
        //管理动态生成的文件
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
        Iterable units = fileManager.getJavaFileObjects(fileName);

//“编译任务”对象
        JavaCompiler.CompilationTask task = compiler.getTask(null,fileManager,null,null,null,units);
        task.call();
        fileManager.close();

//*****************3、加载至内存******************************************

//通过Url引入本地文件
        URL[] urls = new URL[]{new URL("file:/"+"g:/src/")}; //访问本地文件   指定class文件存放的位置
        URLClassLoader urlClassLoader = new URLClassLoader(urls);
        Class c = urlClassLoader.loadClass("com.csu.proxy.TankTimeProxy");

//******************4、执行class文件,返回代理对象***************************************

//获得构造方法
        Constructor constructor = c.getConstructor(InvocationHandler.class);  //getConstructor的参数为Class类型,是原构造方法的参数的Class类型

//产生新对象
        Object m =  constructor.newInstance(h);

return m;
    }
}

6、Cilent客户端

package com.csu.proxy;

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

Tank t = new Tank();
        InvocationHandler h = new TimeHandler(t);

Moveable m =(Moveable) ProxyG3.newProxyInstance(Moveable.class, h);

m.move();

}
}

7、执行结果

(1)生成的java和class文件

(2)查看生成的java文件代码

(3)运行结果

时间: 2024-08-07 12:05:28

深度模拟java动态代理实现机制系类之三的相关文章

深度模拟java动态代理实现机制系类之一

上一篇博客是最基本的动态代理原理的实现,因为其固定了接口,固定了代理方法,以及固定了代理的类型,接下来的博客系类将一步步渐入深度介绍java的动态代理的实现原理 ****************************************************************************首先补充一下“java代理”的相关知识,静态代理的实现包括两种方式,一是聚合,另一种是继承.聚合是指通过接口,调用其实现类的具体方法:比如接口i,含有方法run(); 类A 实现了接口i

深度模拟java动态代理实现机制系类之二

这次我们要实现的是对任意接口,任意的方法进行特定的代理 这里不一样的只有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 jav

Java 动态代理机制分析及扩展,第 1 部分

引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还可以按需调整委托类对象及其功能,这是一套非常灵活有弹性的代理框架.通过阅读本文,读者将会对 Java 动态代理机制有更加深入的理解.本文首先从 Java 动态代理的运行机制和特点出发,对其代码进行了分析,推演了动态生成类的内部实现. 回页首 代理:设计模式 代理是一种常用的设计

Java 动态代理机制分析及扩展

引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还可以按需调整委托类对象及其功能,这是一套非常灵活有弹性的代理框架.通过阅读本文,读者将会对 Java 动态代理机制有更加深入的理解.本文首先从 Java 动态代理的运行机制和特点出发,对其代码进行了分析,推演了动态生成类的内部实现. 代理:设计模式 代理是一种常用的设计模式,其

[转]Java 动态代理机制分析及扩展

引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还可以按需调整委托类对象及其功能,这是一套非常灵活有弹性的代理框架.通过阅读本文,读者将会对 Java 动态代理机制有更加深入的理解.本文首先从 Java 动态代理的运行机制和特点出发,对其代码进行了分析,推演了动态生成类的内部实现. 代理:设计模式 代理是一种常用的设计模式,其

Java动态代理简单应用

概念 代理模式是基本的设计模式之一,它是开发者为了提供额外的或不同的操作,而插入的用来代替“实际”对象的对象.这些操作通常涉及与“实际”对象的通信,因此代理通常充当着中间人的角色. Java动态代理比代理的思想更进一步,因为它可以动态地创建代理并动态地处理对代理方法的调用.在动态代理上所做的所有调用都会被重定向到单一的调用处理器(InvocationHandler)上,调用处理器的工作是揭示调用的类型并确定相应的策略. Java动态代理实现机制采用了反射的思想,有关于反射的基础知识,可以参见博客

模拟JDK动态代理类的实现

问题: 要理解动态代理及其优点,我们先从这样一个问题入手,比如现在我们有UserDao这样一个接口,里面有addUser()方法,同时有一个UserDaoImpl类实现了该接口,具体实现了addUser()方法,现在我要实现在该方法前后记录日志的功能,有什么解决办法呢? 在源代码上直接修改.第一反应肯定是直接在源码上添加该功能,但是如果我的需求变成在所有的DaoImpl包里的类的所有的方法都添加记录日志的功能,那再去每一个都添加,工作量大,代码的重用率也不高,而且有的时候你可能没有源代码,所以该

java 动态代理深度学习(Proxy,InvocationHandler),含$Proxy0源码

java 动态代理深度学习, 一.相关类及其方法: java.lang.reflect.Proxy,Proxy 提供用于创建动态代理类和实例的静态方法.newProxyInstance()返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序(详见api文档) java.lang.reflect.InvocationHandler,InvocationHandler 是代理实例的调用处理程序 实现的接口. invoke()在代理实例上处理方法调用并返回结果.在与方法关联的代理

java动态代理机制

首先了解代理设计模式,其思想是为其他对象提供一种代理以控制对这个对象的访问. java动态代理就是遵循这种思想,spring中的AOP实现原理就是java的动态代理. 在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface).另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的. 每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通