java

Proxy.newProxyInstance

2020-04-03  本文已影响0人  知然

简单实现

Q:通过代理接口的方式进行声明, 然而不通过类实现的方式进行使用,而是使用其他方式实现.
比如MyBatis 如何做到只定义接口, 逻辑写到xml中,就可以调用接口?
FeignClient 为什么只做了声明,却可以直接使用接口进行注入?

A: 其实这些底层都是用于了一个叫做代理的方式来实现的

比如 现在有一个接口是这样的


    interface TestInterface {

        String test01();

        String test02(String st, String st2);

    }

借助 代理的方式给他提供方法的实现,需要用到 Proxy.newProxyInstance这个方法

newProxyInstance,方法有三个参数:

  1. loader : 用哪个类加载器去加载代理对象
  2. interfaces: 动态代理类需要实现的接口
  3. h: InvocationHandler 类型 动态代理方法在执行时,会调用h里面的invoke方法去执行

loader实例很好获得, 使用getClass().getClassLoader()即可.

现在来构造一个 interfaces的实例

 new Class[]{TestInterface.class}

构造一个 h的对象

    static class TestProxy implements InvocationHandler {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

          return null;
        }

动态创建一个接口的实例


        InvocationHandler h = new TestProxy();

        TestInterface obj = (TestInterface) Proxy.newProxyInstance(getClass().getClassLoader(), 
                                  new Class[]{TestInterface.class}, h);

以上,就完成了大概调用的编写. 接着来完成接口实现.

完善TestProxy.invoke方法


        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 假设这里按照不同的需求进行了实现. 
            switch (method.getName()) {
                case "tet01": {
                    return "invoke==>" + UUID.randomUUID().toString();
                }
                case "test02": {
                    return "invoke==>" + Arrays.asList(args);
                }
            }
            return null;

        }
    }

完成 方法的调用


     InvocationHandler h = new TestProxy();

        TestInterface obj = (TestInterface) Proxy.newProxyInstance(getClass().getClassLoader(),
                   new Class[]{TestInterface.class}, h);

      //调用接口中的方法.
        String res = obj.test01();

        System.out.println(res);

简单的封装

创建一个工厂

    static class TestFactory {

        public static <T> T newInstance(Class<T> clazz) {

            InvocationHandler h = new TestProxy();

            return (T) Proxy.newProxyInstance(TestFactory.class.getClassLoader(), new Class[]{clazz}, h);
        }

    }

通过工厂来调用

        TestInterface t = TestFactory.newInstance(TestInterface.class);

        String res = t.test02("111", "222");

        System.out.println(res);

完整的测试类

package cn.com.dunlop.util;

import org.junit.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.UUID;

public class TestProxyClazz {

    interface TestInterface {

        String test01();

        String test02(String st, String st2);

    }


    static class TestProxy implements InvocationHandler {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

            switch (method.getName()) {
                case "tet01": {
                    return "invoke==>" + UUID.randomUUID().toString();
                }
                case "test02": {
                    return "invoke==>" + Arrays.asList(args);
                }
            }
            return null;

        }
    }

    static class TestFactory {

        public static <T> T newInstance(Class<T> clazz) {

            InvocationHandler h = new TestProxy();


            return (T) Proxy.newProxyInstance(TestFactory.class.getClassLoader(), new Class[]{clazz}, h);
        }

    }

    @Test
    public void tet01() {

        InvocationHandler h = new TestProxy();

        TestInterface obj = (TestInterface) Proxy.newProxyInstance(getClass().getClassLoader(),
 new Class[]{TestInterface.class}, h);

        String res = obj.test01();

        System.out.println(res);

    }

    @Test
    public void tet02() {

        TestInterface t = TestFactory.newInstance(TestInterface.class);

        String res = t.test02("111", "222");

        System.out.println(res);

    }
}

总结

通过这种代理方式,可以很轻松做到动态创建接口实现类.

上一篇下一篇

猜你喜欢

热点阅读