自己动手模拟实现Java动态代理

1.0 被代理类接口
package com.sheting.reflect.proxy.demo1;

/**
 * created by zheTing on 2018-03-06 14:07
 */
public interface HelloWorld {
    void sayHello(String name);
}
2.0 被代理类,接口的实现
package com.sheting.reflect.proxy.demo1;

/**
 * created by zheTing on 2018-03-06 14:08
 */
public class HelloWorldImpl implements HelloWorld{

    @Override
    public void sayHello(String name) {
        System.out.println("我是被代理类。 Hello " + name);
    }

}

第3.0、4.0是把动态代理要处理的业务抽象出一个接口和接口的实现。

3.0 增强被代理类方法的接口
package com.sheting.reflect.proxy.demo1;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * created by zheTing on 2018-03-06 14:02
 */
public interface InvocationHandler {
     Object invoke(Method method, Object o, Object... params) throws InvocationTargetException, IllegalAccessException;
}
4.0 增强被代理类方法接口的实现
package com.sheting.reflect.proxy.demo1;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Create Time: 2018-03-06 15:34
 * @author sheting
 */
public class LogHandler implements InvocationHandler {

    @Override
    public Object invoke(Method method, Object o, Object... params) throws InvocationTargetException, IllegalAccessException {
        System.out.println("start...");
        Object invoke = method.invoke(o, params);
        System.out.println("eng...");
        return invoke;
    }
}
5.0 模拟JDK 的动态代理生成类
package com.sheting.reflect.proxy.demo1;

import org.apache.commons.io.FileUtils;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.concurrent.atomic.AtomicLong;

/**
 * created by zheTing on 2018-03-06 14:03
 */
public class Proxy {

    private static final String RT = "\r\n";

    public static final AtomicLong proxyNum = new AtomicLong(0);

    /**
     * 第一个参数是 被代理接口
     * 第二个参数是 被代理接口的实现 的对象
     * 第三个参数是 代理对象
     */
    public static Object newProxyInstance(Class interfaceObj, Object obj, InvocationHandler handler) throws Exception {

        Method[] methods = interfaceObj.getMethods();
        StringBuilder b = new StringBuilder();
        for (Method method : methods) {
            int parameterCount = method.getParameterCount();
            Class<?>[] parameterTypes = method.getParameterTypes();
            StringBuilder paramStr = new StringBuilder();
            StringBuilder paramClasses = new StringBuilder();
            for (int i = 0; i < parameterCount; i++) {
                paramStr.append(parameterTypes[i].getName()).append(" ").append("arg").append(i).append(",");
                paramClasses.append(parameterTypes[i].getName()).append(".class,");
            }

            //截掉最后一个逗号
            String subParamStr = paramStr.substring(0, paramStr.length() - 1);
            String subParamClasses = paramClasses.substring(0, paramClasses.length() - 1);
            b.append("    @Override" + RT)
                    .append("    public void " + method.getName() + "(" + subParamStr + ") {" + RT)
                    .append("      try {" + RT)
                    .append("           Method method = " + interfaceObj.getName() + ".class.getMethod(\"" + method.getName() + "\", " + subParamClasses + ");" + RT)
                    .append("           handler.invoke(method, obj, arg0);" + RT)
                    .append("      } catch (Exception e) {" + RT)
                    .append("        e.printStackTrace();}" + RT)
                    .append("      }" + RT)
            ;
        }

        long num = proxyNum.getAndIncrement();


        //声明一段源码
        String sourceCode =
                "package com.sheting.reflect.proxy.demo1;" + RT +
                        "import java.lang.reflect.Method;" + RT +
                        "/**" + RT +
                        " * Created by sheting on 2018/3/6." + RT +
                        "* 聚合模式实现静态代理" + RT +
                        "*/" + RT +
                        "public class $Proxy" + num + " implements " + interfaceObj.getName() + " {" + RT +
                        "   private " + interfaceObj.getName() + " obj;" + RT +
                        "   private InvocationHandler handler;" + RT + RT +
                        "   public $Proxy" + num + "(" + interfaceObj.getName() + " obj, InvocationHandler handler){" + RT +
                        "       this.obj = obj;" + RT +
                        "       this.handler = handler;" + RT +
                        "   }" + RT +
                        b.toString() +
                        "}";


        String filename = System.getProperty("user.dir") + "/src/main/java/com/sheting/reflect/proxy/demo1/$Proxy" + num + ".java";
        File file = new File(filename);
        //使用org.apache.commons.io.FileUtils.writeStringToFile()将源码写入磁盘
        //并不是一定要生成文件,如果可以直接生成二进制代码load到JVM中,则不必要那么麻烦生成文件了
        FileUtils.writeStringToFile(file, sourceCode);

        //获得当前系统中的编译器
        JavaCompiler complier = ToolProvider.getSystemJavaCompiler();
        //获得文件管理者
        StandardJavaFileManager fileMgr = complier.getStandardFileManager(null, null, null);
        Iterable its = fileMgr.getJavaFileObjects(filename);
        //编译任务
        JavaCompiler.CompilationTask task = complier.getTask(null, fileMgr, null, null, null, its);
        //开始编译
        task.call();
        fileMgr.close();

        //类加载
        URL[] urls = new URL[]{new URL("file:/" + System.getProperty("user.dir") + "/src")};
        URLClassLoader urlClassLoader = new URLClassLoader(urls);
        Class cls = urlClassLoader.loadClass("com.sheting.reflect.proxy.demo1.$Proxy" + num);

        //生成代理类对象
        Constructor ct = cls.getConstructor(interfaceObj, InvocationHandler.class);
        return ct.newInstance(obj, handler);
    }

}

动态生成的类:

package com.sheting.reflect.proxy.demo1;
import java.lang.reflect.Method;
/**
 * Created by sheting on 2018/3/6.
* 聚合模式实现静态代理
*/
public class $Proxy0 implements com.sheting.reflect.proxy.demo1.HelloWorld {
   private com.sheting.reflect.proxy.demo1.HelloWorld obj;
   private InvocationHandler handler;

   public $Proxy0(com.sheting.reflect.proxy.demo1.HelloWorld obj, InvocationHandler handler){
       this.obj = obj;
       this.handler = handler;
   }
    @Override
    public void sayHello(java.lang.String arg0) {
      try {
           Method method = com.sheting.reflect.proxy.demo1.HelloWorld.class.getMethod("sayHello", java.lang.String.class);
           handler.invoke(method, obj, arg0);
      } catch (Exception e) {
        e.printStackTrace();}
      }
}
6.0 测试类
package com.sheting.reflect.proxy.demo1;

/**
 * created by zheTing on 2018-03-06 14:04
 */
public class Test {

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

        HelloWorld proxyObj = (HelloWorld) Proxy.newProxyInstance(HelloWorld.class, new HelloWorldImpl(), new LogHandler());
        proxyObj.sayHello("sheting");

    }
}

运行结果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值