@Override
    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<T> interfaceClass, Invoker proxyInvoker) {
        StringBuilder debug = null;
        if (LOGGER.isDebugEnabled()) {
            debug = new StringBuilder();
        }
        try {
            Class clazz = null;
            if (!disableCache) {
                clazz = PROXY_CLASS_MAP.get(interfaceClass);
            }
            if (clazz == null) {
                //生成代理类
                String interfaceName = ClassTypeUtils.getTypeStr(interfaceClass);
                ClassPool mPool = ClassPool.getDefault();
                mPool.appendClassPath(new LoaderClassPath(ClassLoaderUtils.getClassLoader(JavassistProxy.class)));
                CtClass mCtc = mPool.makeClass(interfaceName + "_proxy_" + counter.getAndIncrement());
                if (interfaceClass.isInterface()) {
                    mCtc.addInterface(mPool.get(interfaceName));
                } else {
                    throw new IllegalArgumentException(interfaceClass.getName() + " is not an interface");
                }

                // 继承 java.lang.reflect.Proxy
                mCtc.setSuperclass(mPool.get(java.lang.reflect.Proxy.class.getName()));
                CtConstructor constructor = new CtConstructor(null, mCtc);
                constructor.setModifiers(Modifier.PUBLIC);
                constructor.setBody("{super(new " + UselessInvocationHandler.class.getName() + "());}");
                mCtc.addConstructor(constructor);

                List<String> fieldList = new ArrayList<String>();
                List<String> methodList = new ArrayList<String>();

                fieldList.add("public " + Invoker.class.getCanonicalName() + " proxyInvoker = null;");
                createMethod(interfaceClass, fieldList, methodList);

                for (String fieldStr : fieldList) {
                    if (LOGGER.isDebugEnabled()) {
                        debug.append(fieldStr).append("\n");
                    }
                    mCtc.addField(CtField.make(fieldStr, mCtc));
                }
                for (String methodStr : methodList) {
                    if (LOGGER.isDebugEnabled()) {
                        debug.append(methodStr).append("\n");
                    }
                    mCtc.addMethod(CtMethod.make(methodStr, mCtc));
                }
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("javassist proxy of interface: {} \r\n{}", interfaceClass,
                        debug != null ? debug.toString() : "");
                }
                // Under jdk 11+, `neighbour` param is required to apply LookUp.defineClass
                // and avoid reflect calling to Classloader.defineClass(), as calling
                // Classloader.defineClass() from unnamed module is prohibited, which may
                // provoke InaccessibleObjectException.
                clazz = mPool.toClass(mCtc, interfaceClass,
                    // use tccl as former
                    Thread.currentThread().getContextClassLoader(),
                    interfaceClass.getProtectionDomain());
                PROXY_CLASS_MAP.put(interfaceClass, clazz);
            }
            Object instance = clazz.newInstance();
            clazz.getField("proxyInvoker").set(instance, proxyInvoker);
            return (T) instance;
        } catch (Exception e) {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("javassist proxy of interface: {} \r\n{}", interfaceClass,
                    debug != null ? debug.toString() : "");
            }
            throw new SofaRpcRuntimeException(LogCodes.getLog(LogCodes.ERROR_PROXY_CONSTRUCT, "javassist"), e);
        }
    }
@Test
    public void getProxy() throws Exception {
        JavassistProxy proxy = new JavassistProxy();
        AbstractTestClass testClass = null;
        try {
            testClass = proxy.getProxy(AbstractTestClass.class, new TestInvoker());
        } catch (Exception e) {
            LOGGER.info(e.getMessage());
        }
        Assert.assertNull(testClass);

        TestInvoker invoker = new TestInvoker();
        TestInterface testInterface = proxy.getProxy(TestInterface.class, invoker);
        Assert.assertNotNull(testInterface);

        Class clazz = testInterface.getClass().getInterfaces()[0];
        Assert.assertEquals(TestInterface.class, clazz);

        Assert.assertTrue(Proxy.class.isAssignableFrom(testInterface.getClass()));
        Assert.assertFalse(Proxy.isProxyClass(testInterface.getClass()));

        Assert.assertEquals(proxy.getInvoker(testInterface).getClass(), TestInvoker.class);
        Assert.assertEquals(testInterface.toString(), invoker.toString());
        Assert.assertEquals(testInterface.hashCode(), invoker.hashCode());

        TestInterface another1 = proxy.getProxy(TestInterface.class, invoker);
        TestInterface another2 = proxy.getProxy(TestInterface.class, new TestInvoker());
        Assert.assertFalse(testInterface.equals(invoker));
        Assert.assertFalse(testInterface.equals(another2));
        Assert.assertEquals(testInterface, another1);

        Assert.assertEquals(678, another1.sayNum(true));
        SofaRequest request = invoker.getRequest();
        Assert.assertEquals(TestInterface.class.getCanonicalName(), request.getInterfaceName());
        Assert.assertEquals("sayNum", request.getMethodName());
        Assert.assertEquals("boolean", request.getMethodArgSigs()[0]);
        Assert.assertEquals(true, request.getMethodArgs()[0]);
        Assert.assertNotNull(request.getMethod());

        Assert.assertEquals("sayHello", another1.sayHello("xxxx"));
        another1.sayNoting();
        Assert.assertArrayEquals(new int[] { 6, 7, 8 }, another1.sayNums(null, new HashMap()));
        Assert.assertNull(another1.sayNum2(1.2D));

        boolean error = false;
        try {
            another1.throwbiz1();
        } catch (Throwable e) {
            error = true;
        }
        Assert.assertFalse(error);

        error = false;
        try {
            another1.throwbiz2();
        } catch (Throwable e) {
            error = true;
        }
        Assert.assertFalse(error);

        try {
            another1.throwRPC();
        } catch (Throwable e) {
            error = true;
        }
        Assert.assertTrue(error);
    }