Java实现代理的两种方法

写在前面

参考连接:http://modouxiansheng.top/2018/09/14/不学无数-Java代理模式-2018/

代理的名词

代理对象:增强后的对象。
目标对象:被增强后的对象。

Java实现代理的两种方法

1、静态代理
(1)继承:
目标对象:

package dao;

public class UserDaoImpl  {

    public void query(String name) {
        System.out.println("query name = " + name);
    }
}

代理对象:

package Proxy;
import dao.UserDaoImpl;
public class LogUserProxy extends UserDaoImpl {

    public void query(String name) {
        System.out.println("log name = " + name);
        System.out.println("query name = " + name);
    }
}

Java实现代理的两种方法_第1张图片
(2)聚合:
抽象对象:

package dao;

public interface UserDao {

    public void query(String name);
}

目标对象:

package dao;

public class UserDaoImpl implements UserDao {

    public void query(String name) {
        System.out.println("query name = " + name);
    }
}

代理对象:

package Proxy2;

import dao.UserDao;

public class LogUserProxy implements UserDao {

    private UserDao userDao;

    public LogUserProxy(UserDao userDao) {
        this.userDao = userDao;
    }

    public void query(String name) {
        System.out.println("....log.....");
        userDao.query(name);
    }
}

代理对象:

package Proxy;

import dao.UserDaoImpl;

public class TimerUserProxy extends UserDaoImpl {

    public void query(String name) {
        System.out.println("Timer name = " + name);
        System.out.println("query name = " + name);
    }
}

package test;

import Proxy2.LogUserProxy;
import Proxy2.TimerUserProxy;
import dao.UserDao;
import dao.UserDaoImpl;

public class Test {

    public static void main(String[] args) {
        UserDao userDao = new UserDaoImpl();
        UserDao proxy1 = new LogUserProxy(userDao);
        UserDao proxy2 = new TimerUserProxy(proxy1);
        proxy2.query("张三");
    }
}

Java实现代理的两种方法_第2张图片
目标对象和代理对象实现同一个接口,并且代理对象当中包含抽象对象。

2、动态代理
代理:本来应该自己做的事情,却请了别人来做,别请的人就是代理对象。

  • 举例:春季回家买票让人代买。

动态代理:再程序运行过程中产生的这个对象

  • 而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理。
  • 在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib。
  • Proxy类中的方法创建动态代理类对象:
public static Object new ProxyInstance (ClassLoader load,Class interfaces,
InvocationHandler h)
最终会调用InvocationHandler的方法
  • InvocationHandler
    • Object invoke(Object proxy, Method method, Object[] args)

Java实现代理的两种方法_第3张图片

package utils;

import com.sun.xml.internal.bind.v2.runtime.reflect.opt.Const;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

public class ProxyUtil {

    /**
     * 得到一个java文件
     * 编译成为一个class
     * 通过反射得到一个对象
     * return
     * @param target
     * @return
     */

    public static Object newProxyInstance(Object target) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        String content = "";
        String packageContent = "package Proxy2;";
        Class targetInfo = target.getClass().getInterfaces()[0];
        String targetInfoName = targetInfo.getSimpleName();
        String importContent = "import " + targetInfo.getName() + ";";
        String classContent = "public class $Proxy implements " + targetInfoName + "{";
        String fieldContent = "private " + targetInfoName + " target;";
        String construterContent = "public $Proxy(" + targetInfoName + " target){" +
                "this.target = target;}";

        String methodsContent = "";
        Method[] methods = targetInfo.getDeclaredMethods();
        /**
         * public void query(String name) {
         *         System.out.println("....log.....");
         *         userDao.query(name);
         *     }
         */
        for (Method method : methods) {
            String methodName = method.getName();
            Class returnType = method.getReturnType();
            Class[] parameterTypes = method.getParameterTypes();
            String argsContent = "";
            String argsNames = "";
            int i = 0;
            for (Class parameterType : parameterTypes) {
                String simpleName = parameterType.getSimpleName();
                argsContent += simpleName + " p" +  i + ",";
                argsNames += "p" + i +  ",";
                i ++;
            }

            if (argsContent.length() > 0) {
                argsContent = argsContent.substring(0,argsContent.lastIndexOf(",") - 1);
                argsNames = argsNames.substring(0,argsNames.lastIndexOf(",") - 1);
            }


            methodsContent = "public " + returnType + " " + methodName + "(" +
            argsContent + "){" + "System.out.println(\"....log.....\");"
            + "target." + methodName + "(" + argsNames + ");}";

        }

        content += packageContent + importContent + classContent + fieldContent +
                construterContent + methodsContent + "}";
        File file = new File("g:\\Proxy2\\$Proxy.java");
        if (!file.exists()) {
            file.createNewFile();
        }

        FileWriter fileWriter = new FileWriter(file);
        fileWriter.flush();
        fileWriter.write(content);
        fileWriter.close();

        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
        Iterable units = fileManager.getJavaFileObjects(file);
        JavaCompiler.CompilationTask task = compiler.getTask(null,fileManager,null,null,null,units);
        task.call();
        fileManager.close();

        URL[] urls = new URL[]{new URL("file:g:\\\\")};
        URLClassLoader urlClassLoader = new URLClassLoader(urls);
        Class clzz = urlClassLoader.loadClass("Proxy2.$Proxy");
        Constructor constructor = clzz.getConstructor(targetInfo);
        Object proxy = constructor.newInstance(target);
        return proxy;
    }
}

你可能感兴趣的:(Java实现代理的两种方法)