Java动态代理

Posted Se7end

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java动态代理相关的知识,希望对你有一定的参考价值。

最近看了Feign的远程调用代理这部分的代码,尝试的自己写了一下。

 

调用模型图:

 

 

1.ProxyMethod注解,判断方法是否需要做代理。

/**
 * 代理方法注解
 */
@java.lang.annotation.Target(METHOD)
@Retention(RUNTIME)
public @interface ProxyMethod {

    public String value();
}

2.启动类,idService是生成的代理类。

public class StartApplication {

    public static void main(String[] args) {

        // 创建代理
        IdService idService = ProxyUtil.newInstance(new Target.HardCodedTarget<>(IdService.class));

        // 执行代理方法
        Integer id = idService.getId();

        System.out.println(id);
    }
}

3.IdService服务类

public interface IdService {

    @ProxyMethod("getId")
    public Integer getId();
}

4.类代理

/**
 * 代理
 * @param <T>
 */
public interface Target<T> {

    public Class<T> type();

    public static class HardCodedTarget<T> implements Target<T> {

        private Class<T> type;

        public HardCodedTarget(Class<T> type) {
            this.type = type;
        }

        @Override
        public Class<T> type() {
            return type;
        }
    }
}

5.代理工具类

/**
 * 代理工具类
 */
public class ProxyUtil {

    public static <T> T newInstance(Target<T> target) {

        Map<String, MethodHandler> nameToHandler = MethodHandler.FactoryMethodHandler.apply(target);
        Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();

        for (Method method : target.type().getMethods()) {
            if (method.getDeclaringClass() == Object.class) {
                continue;
            } else if (isDefault(method)) {
                MethodHandler.DefaultMethodHandler handler = new MethodHandler.DefaultMethodHandler(method);
                methodToHandler.put(method, handler);
            } else {
                System.out.println("ProxyUtil.newInstance.Method:" + method.getName());
                methodToHandler.put(method, nameToHandler.get(configKey(target.type(), method)));
            }
        }

        InvocationHandler handler = new DefaultInvocationHandler(target, methodToHandler);

        @SuppressWarnings("unchecked")
        T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[]{target.type()}, handler);

        return proxy;
    }

    public static String configKey(Class<?> targetType, Method method) {
        StringBuilder builder = new StringBuilder();
        builder.append(targetType.getSimpleName());
        builder.append(\'#\').append(method.getName()).append(\'(\');
        for (Type param : method.getGenericParameterTypes()) {
            builder.append(getRawType(param)).append(\',\');
        }
        if (method.getParameterTypes().length > 0) {
            builder.deleteCharAt(builder.length() - 1);
        }
        return builder.append(\')\').toString();
    }

    public static String getRawType(Type param) {
        return param.getTypeName();
    }

    /**
     * Identifies a method as a default instance method.
     */
    public static boolean isDefault(Method method) {
        // Default methods are public non-abstract, non-synthetic, and non-static instance methods
        // declared in an interface.
        // method.isDefault() is not sufficient for our usage as it does not check
        // for synthetic methods.  As a result, it picks up overridden methods as well as actual default methods.
        final int SYNTHETIC = 0x00001000;
        return ((method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC | SYNTHETIC)) ==
                Modifier.PUBLIC) && method.getDeclaringClass().isInterface();
    }

    /**
     * 自定义方法代理
     */
    public static class DefaultInvocationHandler implements InvocationHandler {

        private final Target<?> target;
        private final Map<Method, MethodHandler> dispatch;

        public DefaultInvocationHandler(Target<?> target, Map<Method, MethodHandler> dispatch) {
            this.target = target;
            this.dispatch = dispatch;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if ("equals".equals(method.getName())) {
                try {
                    Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
                    return equals(otherHandler);
                } catch (IllegalArgumentException e) {
                    return false;
                }
            } else if ("hashCode".equals(method.getName())) {
                return hashCode();
            } else if ("toString".equals(method.getName())) {
                return toString();
            }
            return dispatch.get(method).invoke(args);
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof DefaultInvocationHandler) {
                DefaultInvocationHandler other = (DefaultInvocationHandler) obj;
                return target.equals(other.target);
            }
            return false;
        }

        @Override
        public int hashCode() {
            return target.hashCode();
        }

        @Override
        public String toString() {
            return target.toString();
        }
    }
}

6.代理方法处理类

public interface MethodHandler {

    Object invoke(Object[] argv) throws Throwable;

    public static class DefaultMethodHandler implements MethodHandler {
        private final MethodHandle unboundHandle;
        private MethodHandle handle;

        public DefaultMethodHandler(Method defaultMethod) {
            try {
                Class<?> declaringClass = defaultMethod.getDeclaringClass();
                Field field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
                field.setAccessible(true);
                MethodHandles.Lookup lookup = (MethodHandles.Lookup) field.get(null);

                this.unboundHandle = lookup.unreflectSpecial(defaultMethod, declaringClass);
            } catch (NoSuchFieldException ex) {
                throw new IllegalStateException(ex);
            } catch (IllegalAccessException ex) {
                throw new IllegalStateException(ex);
            }
        }

        /**
         * Bind this handler to a proxy object.  After bound, DefaultMethodHandler#invoke will act as if it was called
         * on the proxy object.  Must be called once and only once for a given instance of DefaultMethodHandler
         */
        public void bindTo(Object proxy) {
            if (handle != null) {
                throw new IllegalStateException("Attempted to rebind a default method handler that was already bound");
            }
            handle = unboundHandle.bindTo(proxy);
        }

        /**
         * Invoke this method.  DefaultMethodHandler#bindTo must be called before the first
         * time invoke is called.
         */
        @Override
        public Object invoke(Object[] argv) throws Throwable {
            if (handle == null) {
                throw new IllegalStateException("Default method handler invoked before proxy has been bound.");
            }
            return handle.invokeWithArguments(argv);
        }
    }

    public static class FactoryMethodHandler {

        public static Map<String, MethodHandler> apply(Target<?> target) {
            System.out.println("初始化代理>>>");
            Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
            Class<?> targetType = target.type();
            for (Method method : targetType.getMethods()) {
                if (method.getDeclaringClass() == Object.class ||
                        (method.getModifiers() & Modifier.STATIC) != 0 ||
                        ProxyUtil.isDefault(method)) {
                    continue;
                }
                result.put(ProxyUtil.configKey(targetType, method), new ProxyMethodHandler(method));
            }
            return result;
        }
    }

    public static class ProxyMethodHandler implements MethodHandler {

        private Method method;

        public ProxyMethodHandler(Method method) {
            this.method = method;
        }

        @Override
        public Object invoke(Object[] argv) throws Throwable {
            System.out.println("执行代理方法>>>");
            ProxyMethod proxyMethod = method.getAnnotation(ProxyMethod.class);
            if (null != proxyMethod) {
                if ("getId".equals(proxyMethod.value())) {
                    return 1;
                }
            }
            return null;
        }
    }
}

 

在ProxyMethodHandler方法的invoke方法中,根据ProxyMethod注解来处理代理方法的业务逻辑。

 

以上是关于Java动态代理的主要内容,如果未能解决你的问题,请参考以下文章

Java设计模式-代理模式之动态代理(附源代码分析)

(java反射-JDK动态代理)+CGLIB动态代理

Java动态代理

Java动态代理

Java动态代理

动态代理