zoukankan      html  css  js  c++  java
  • 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注解来处理代理方法的业务逻辑。

  • 相关阅读:
    块数据加密模式
    "jobTracker is not yet running"(hadoop 配置)
    平衡搜索树
    Programming Assignment 3: Collinear Points
    Programming Assignment 2: Randomized Queues and Deques
    Programming Assignment 1: Percolation
    1007. Maximum Subsequence Sum (25)
    Link List
    1081. Rational Sum (20)
    strassen algorithm
  • 原文地址:https://www.cnblogs.com/se7end/p/10419793.html
Copyright © 2011-2022 走看看