首页 > 其他分享 >简单实现动态代理

简单实现动态代理

时间:2022-10-29 23:22:45浏览次数:56  
标签:int Calculator 代理 目标 result 简单 动态 方法 public

1.目标接口

package org.example.proxy;

public interface Calculator {

    int add(int i, int j);

    int sub(int i, int j);

    int mul(int i, int j);

    int div(int i, int j);

}

2.目标实现

package org.example.proxy;


public class CalculatorPureImpl implements Calculator {

    @Override
    public int add(int i, int j) {

        int result = i + j;

        System.out.println("方法内部 result = " + result);

        return result;
    }

    @Override
    public int sub(int i, int j) {
        int result = i - j;

        System.out.println("方法内部 result = " + result);

        return result;
    }

    @Override
    public int mul(int i, int j) {

        int result = i * j;

        System.out.println("方法内部 result = " + result);

        return result;
    }

    @Override
    public int div(int i, int j) {

        int result = i / j;

        System.out.println("方法内部 result = " + result);

        return result;
    }
}

3.代理工厂

public class LogDynamicProxyFactory {

    // 将被代理的目标对象声明为成员变量
    private Calculator target;
    public LogDynamicProxyFactory() {

    }

    public LogDynamicProxyFactory(Calculator target) {
        this.target = target;
    }

    public Calculator getProxy() throws Throwable {

        // 创建代理对象所需参数一:加载目标对象的类的类加载器
        ClassLoader classLoader = target.getClass().getClassLoader();

        // 创建代理对象所需参数二:目标对象的类所实现的所有接口组成的数组
        Class<?>[] interfaces = target.getClass().getInterfaces();


        InvocationTest handler = new InvocationTest() {
            @Override
            public Object Objectinvoke(Method method, Object[] args){
                // 代理对象,当前方法用不上这个对象


                // method就是代表目标方法的Method对象


                // 外部调用目标方法时传入的实际参数


                // 我们对InvocationHandler接口中invoke()方法的实现就是在调用目标方法
                // 围绕目标方法的调用,就可以添加我们的附加功能

                // 声明一个局部变量,用来存储目标方法的返回值
                Object targetMethodReturnValue = null;

                // 通过method对象获取方法名
                String methodName = method.getName();

                // 为了便于在打印时看到数组中的数据,把参数数组转换为List
                List<Object> argumentList = Arrays.asList(args);

                try {

                    // 在目标方法执行前:打印方法开始的日志
                    log.debug("[动态代理][日志] " + methodName + " 方法开始了,参数是:-----" + argumentList);

                    // 调用目标方法:需要传入两个参数
                    // 参数1:调用目标方法的目标对象
                    // 参数2:外部调用目标方法时传入的实际参数
                    // 调用后会返回目标方法的返回值

                    targetMethodReturnValue = method.invoke(target, args);

                    // 在目标方法成功后:打印方法成功结束的日志【寿终正寝】
                    log.debug("[动态代理][日志] " + methodName + " 方法成功结束了,返回值是:-----" + targetMethodReturnValue);

                }catch (Exception e){

                    // 通过e对象获取异常类型的全类名
                    String exceptionName = e.getClass().getName();

                    // 通过e对象获取异常消息
                    String message = e.getMessage();

                    // 在目标方法失败后:打印方法抛出异常的日志【死于非命】
                    log.debug("[动态代理][日志] " + methodName + " 方法抛异常了,异常信息是:-----" + exceptionName + "," + message);

                }finally {

                    // 在目标方法最终结束后:打印方法最终结束的日志【盖棺定论】
                    log.debug("[动态代理][日志] " + methodName + " 方法最终结束了-----");

                }

                // 这里必须将目标方法的返回值返回给外界,如果没有返回,外界将无法拿到目标方法的返回值
                return targetMethodReturnValue;
            }

        };


//        org.example.dss.Calculator proxy = (Calculator) Proxy.newProxyInstance(classLoader, interfaces, handler);
        Calculator calculator = (Calculator) MyProxyTest.myGetPorxyInstance(classLoader, interfaces, handler);

        // 返回代理对象
       return calculator;
    }
}

4.代理

public class MyProxyTest {
    public static Object myGetProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationTest h) throws Throwable {

        Class<?>[] clone = interfaces.clone();

        Class<?> aClass = loader.loadClass(interfaces.clone()[0].getName());

        Method[] methods = aClass.getMethods();

        HashMap<String, Method> map = new HashMap<>();
        String mm = "";


        for (Method method : methods){
            String name = method.getName();
            Class<?>[] parameterTypes = method.getParameterTypes();
            map.put(name,method);

            String m =
            "    public int "+ name+ "("+parameterTypes[0].getName()+" i, "+parameterTypes[1].getName()+" j)" +
                    "    {" +
                    "        Object objectinvoke = h.Objectinvoke(this.methods.get(\""+name+"\"), new Object[]{i,j});" +
                    "        return (int)objectinvoke;" +
                    "    }";

            mm = mm + m;
        }

        //------------------------------------------------------------------"package org.example.proxy;" +
        // 传入String类型的代码
        String source = "import java.util.HashMap;import java.lang.reflect.Method;\n" +
                "\n" +
                "\n" +
                "public class ProxyCal implements Calculator\n" +
                "{\n" +
                "    private InvocationTest h;\n" +
                "    private HashMap<String, Method> methods;\n" +
                "\n" +
                "    public ProxyCal() {\n" +
                "    }\n" +
                "    public ProxyCal(InvocationTest h) {\n" +
                "        this.h = h;\n" +
                "    }\n" +
                "    public InvocationTest getH() {\n" +
                "        return this.h;\n" +
                "    }\n" +
                "\n" +
                "    public void setH(InvocationTest h) {\n" +
                "        this.h = h;\n" +
                "    }\n" +
                "    @Override\n"+ mm +
                "}";
        Class<?> clazz = (Class<?>)StringCompiler.run(source, "1", "2");

        Constructor<?>[] constructors = clazz.getConstructors();

        Object instance = constructors[1].newInstance(h);
        Field fieldMethod = clazz.getDeclaredField("methods");
        fieldMethod.setAccessible(true);
        fieldMethod.set(instance,map);

        return instance;
    }
}

5.测试

public class test1 {
    @Test
    public void test1() throws Throwable {
        // 1.创建被代理的目标对象
        Calculator target = new CalculatorPureImpl();
        LogDynamicProxyFactory proxyFactory = new LogDynamicProxyFactory(target);

        Calculator proxy =  proxyFactory.getProxy();

        System.out.println(proxy.add(3, 3));
        System.out.println(proxy.sub(3, 3));
        System.out.println(proxy.mul(3, 3));
        System.out.println(proxy.div(3, 3));
    }

}

 参数的数量,类型,肯定是不一样的,但是都是可以拿到的,无非拼接是麻烦一些,我就懒得搞了

标签:int,Calculator,代理,目标,result,简单,动态,方法,public
From: https://www.cnblogs.com/dzs894330350/p/16840196.html

相关文章