JavaReflectionInAction
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
在Java 1.3推出的时候,最为闪耀的一一个特性就是动态代理。
动态代理使用用了字节码生生成的方方式,生生成了⺫目目标接口口的代理,并且将代理所做的工工作委 派给了代理的InvocationHandler,从实现层面面分开了做什么和怎么做,就算不从技术角角度上 审视动态代理,从设计角角度上看,动态代理的隔离关注的设计思想就值得我们学习。
if (join != null) { List<Response> results = new ArrayList<Response>(); for (; invokerIndex < invokers.size(); invokerIndex ++) { invoker = invokers.get(invokerIndex); try { Map <==== ? Object result = invoker.invoke(methodName, paramTypes, args, returnType, methodInfo); Reduce <==== ? results.add(new SuccessResponse(result, invoker.getServerInfo())); } catch (Throwable t) { results.add(new ExceptionResponse(t, invoker.getServerInfo())); } }
@Test
public void objectToString() { MockInvocationHandler handler = new MockInvocationHandler(); Mock mock = (Mock) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class<?>[] {Mock.class}, handler); mock.toString(); System.out.println("=="); mock.getClass(); }
这个类实现了InvocationHandler,可⻅见这个类一一定负责与服务端通信工工作,完成调用用操 作,所以实现了invoke方方法,这个invoke方方法将会调用用
public Object invoke(String methodName, String[] paramTypes, Object[] args, Class<?> returnType) throws Throwable 和前文文一一样,对于代理的方方法调用用,将会委派给InvocationHandler来处理。
远程调用用框架客户端调用用代码分析
动态代理,通过InvocationHandler来横切的处理逻辑,在业务中使用用的概率不高高,但是 技术层面面是非非常干广广泛的,观摩一一个类似的框架,可以使我们更加明白白的使用用一一个工工具。
由于远程框架非非常众多,诸如Hadoop旗下的Avro和前不久移交Apache的Facebook的 Thrift,均可以完成这些任务(⺫目目前,二二者均是Apache项⺫目目)。当然还有我们自自己己的远程调用用 服务框架,Dubbo。
} else { for (; invokerIndex < invokers.size() && invokerIndex < retryProviders; invokerIndex++) { // 从代码层面面看,如果调用用超时的话或者是内部RpcException(属于Dubbo)的话,客户端会进行行retry ,默认3次 // 调用用选择策略,不多⺫目目前三种 invoker = lbStrategy.select(invokers, totalWeight, maxWeight, minWeight); for (int i = 0; i < retryTimes; i++) { long start = System.currentTimeMillis(); try {
动态代理的主要用用途:
(1)因为代理的Proxy也实现了预定义的接口口,那么就可以在真正的实现调用用前或者调用用 后执行行一一段逻辑,甚至至替换掉原有的真正实现,那么从一一定程度上讲,这种方方式就是Java最 为原生生的AOP;
(2)能够更加方方便的使用用远程调用用,我们调用用一一个Hessian或者Dubbo接口口,其实调用用的 是业务方方提供给我们的接口口的一一个代理,这个代理负责建立立客户端和服务端的Socket链接, 将参数的内容序列化并传输给服务端,服务端处理完成后同步将结果返回给客户端从而而完成 一一次远程调用用,因此可以看出使用用动态代理将业务代码和框架代码的分离成为可能。
ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.addInterface(serviceInterface); <== Proxy实现的接口口 proxyFactory.addAdvice(interceptor); <== InvocationHandler proxy = proxyFactory.getProxy();
<dubbo:reference XXXX />
com.alibaba.dubbo.service.spring.schema.ReferenceBeanDefinitionParser
这个是client的解析,用用来解析配置中的接口口名称、超时时间、版本等属性。
(2)控制反转至至Spring
com.alibaba.dubbo.service.spring.ReferenceFactoryBean
public synchronized <T> T getRemoteService(ServiceInfo serviceInfo, Class<T> serviceInterface, Boolean allowNoProvider)
生生成的一一定是一一个Proxy,那么一一定有一一个InvocationHandler,始终focus基础,其他的 都是次要的。
Dubbo将调用用抽象成了RpcInvoker,每个客户端有一一组RpcInvoker用用来调用用,从代码中 可以看到调用用支支持类似调用用的分发与汇总,还有我们常用用的选择一一个调用用RpcInvoker,然后 单点进行行服务调用用的方方式。其中,Dubbo的选择策略,也就是负载策略也是基于客户端的。
methodName, paramTypes, args, methodInfo == null ? -1 : methodInfo.getStat(), System.currentTimeMillis() - start); } } catch (Throwable shouldBeBizExThrowable) { // ServiceException从这里里抛出 if (logger.isInfoEnabled()) { (String.format(
简单示示例
首首先实现InvocationHandler,确保你需要做什么;
public class MockInvocationHandler implements InvocationHandler { /* (non-Javadoc) * @see ng.reflect.InvocationHandler#invoke(ng.Object, ng.reflect.Method, ng.Object[]) */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("InvokeHandler Invoke."); return null; }
methodName, paramTypes, args, methodInfo == null ? -1 : methodInfo.getStat(), System.currentTimeMillis() - start); } return result; } catch (RpcException rpce) { if (rpce.isBiz()) { throw rpce; } if (rpce.isTimeout()) { Monitor.trace(applicationTimeoutName, service.getName() + ":" + service.getVersion(),
这个是入入口口,一一个FactoryBean,主要观摩其getObject方方法,这个方方法将会产生生一一个依 赖方方所需使用用的引用用。
(3)Dubbo的微容器
com.alibaba.dubbo.service.internal.DefaultServiceManager
使用用微容器来保存服务名称和代理的关系,在后续请求过程中,能够加速访问,但是实 际上,只会在使用用spring的ApplicationContext.getObject时,才会触发这个类用用来生生成代理 的客户端和服务端
反射成员类图
Java对于上述成员描述的类图如下:
反射的简单应用用
如果我们知道了一一个Class里里的字段,那么我们能够很方方便的完成其get/set方方法的生生 成,如果给定两个Class,那么我们就有机会完成从一一个Class get属性然后set到另外一一个 Class的代码片片段生生成工工作。
serviceProxyMap.put(signature, proxy);
这里里负责客户端代理的生生成工工作。 (4)远程调用用 返回一一个代理,这个代理将对接口口的请求统一一委派到这个类
com.alibaba.dubbo.service.internal.DubboServiceClientInterceptor
}
其次,有一一个需要代理的接口口,注意,一一定是接口口;
public interface Mock { public String mock(String value);
}ห้องสมุดไป่ตู้
最后,将这个接口口生生成Proxy的字节码,如果已经生生成则不需要,然后将 InvocationHandler的实例设置入入Proxy的实例,当调用用Proxy的实例时,就会路由到 InvocationHandler中的invoke中执行行。
Object result = invoker.invoke(methodName, paramTypes, args, returnType, methodInfo); if (Monitor.isTraceEnabled()) { Monitor.trace(applicationInvokeName, service.getName() + ":" + service.getVersion(),
Java Reflection
Accessing members 简介
Java通过内置的Field、Method、Constructor等Member来描述一一个Class实例的组成部 分,能够让我们以代码编写的视角角去审视已经成型(被载入入内存)的代码,从而而使后续的代码 能够根据审视自自身身来做出行行为动作,从而而使程序在一一定程度上具备了自自动化或者说智能的特 性。
那么我们就从一一次dubbo调用用的过程,来揭开其面面纱。
一一般来说Dubbo从客户端出发,调用用步骤主要有主要如下:
(1)初始化过程:
com.alibaba.dubbo.service.spring.schema.DubboNamespaceHandler
用用来指定解析的parser
就用用来解析如下标签:
来源于那个类(全名),引用用名,⺫目目的类的全名和引用用名。
看一一下控制台,可以copy过去使用用了。
这样做的好处是,当你重构一一个字段名称的时候,编译器会帮你发现错误。不要使用用 BeanCopy之类的工工具,这只有在非非业务代码开发过程中的一一种简化Utils。
Dynamic Proxy 简介
动态代理使用用了字节码生生成的方方式,生生成了⺫目目标接口口的代理,并且将代理所做的工工作委 派给了代理的InvocationHandler,从实现层面面分开了做什么和怎么做,就算不从技术角角度上 审视动态代理,从设计角角度上看,动态代理的隔离关注的设计思想就值得我们学习。
if (join != null) { List<Response> results = new ArrayList<Response>(); for (; invokerIndex < invokers.size(); invokerIndex ++) { invoker = invokers.get(invokerIndex); try { Map <==== ? Object result = invoker.invoke(methodName, paramTypes, args, returnType, methodInfo); Reduce <==== ? results.add(new SuccessResponse(result, invoker.getServerInfo())); } catch (Throwable t) { results.add(new ExceptionResponse(t, invoker.getServerInfo())); } }
@Test
public void objectToString() { MockInvocationHandler handler = new MockInvocationHandler(); Mock mock = (Mock) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class<?>[] {Mock.class}, handler); mock.toString(); System.out.println("=="); mock.getClass(); }
这个类实现了InvocationHandler,可⻅见这个类一一定负责与服务端通信工工作,完成调用用操 作,所以实现了invoke方方法,这个invoke方方法将会调用用
public Object invoke(String methodName, String[] paramTypes, Object[] args, Class<?> returnType) throws Throwable 和前文文一一样,对于代理的方方法调用用,将会委派给InvocationHandler来处理。
远程调用用框架客户端调用用代码分析
动态代理,通过InvocationHandler来横切的处理逻辑,在业务中使用用的概率不高高,但是 技术层面面是非非常干广广泛的,观摩一一个类似的框架,可以使我们更加明白白的使用用一一个工工具。
由于远程框架非非常众多,诸如Hadoop旗下的Avro和前不久移交Apache的Facebook的 Thrift,均可以完成这些任务(⺫目目前,二二者均是Apache项⺫目目)。当然还有我们自自己己的远程调用用 服务框架,Dubbo。
} else { for (; invokerIndex < invokers.size() && invokerIndex < retryProviders; invokerIndex++) { // 从代码层面面看,如果调用用超时的话或者是内部RpcException(属于Dubbo)的话,客户端会进行行retry ,默认3次 // 调用用选择策略,不多⺫目目前三种 invoker = lbStrategy.select(invokers, totalWeight, maxWeight, minWeight); for (int i = 0; i < retryTimes; i++) { long start = System.currentTimeMillis(); try {
动态代理的主要用用途:
(1)因为代理的Proxy也实现了预定义的接口口,那么就可以在真正的实现调用用前或者调用用 后执行行一一段逻辑,甚至至替换掉原有的真正实现,那么从一一定程度上讲,这种方方式就是Java最 为原生生的AOP;
(2)能够更加方方便的使用用远程调用用,我们调用用一一个Hessian或者Dubbo接口口,其实调用用的 是业务方方提供给我们的接口口的一一个代理,这个代理负责建立立客户端和服务端的Socket链接, 将参数的内容序列化并传输给服务端,服务端处理完成后同步将结果返回给客户端从而而完成 一一次远程调用用,因此可以看出使用用动态代理将业务代码和框架代码的分离成为可能。
ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.addInterface(serviceInterface); <== Proxy实现的接口口 proxyFactory.addAdvice(interceptor); <== InvocationHandler proxy = proxyFactory.getProxy();
<dubbo:reference XXXX />
com.alibaba.dubbo.service.spring.schema.ReferenceBeanDefinitionParser
这个是client的解析,用用来解析配置中的接口口名称、超时时间、版本等属性。
(2)控制反转至至Spring
com.alibaba.dubbo.service.spring.ReferenceFactoryBean
public synchronized <T> T getRemoteService(ServiceInfo serviceInfo, Class<T> serviceInterface, Boolean allowNoProvider)
生生成的一一定是一一个Proxy,那么一一定有一一个InvocationHandler,始终focus基础,其他的 都是次要的。
Dubbo将调用用抽象成了RpcInvoker,每个客户端有一一组RpcInvoker用用来调用用,从代码中 可以看到调用用支支持类似调用用的分发与汇总,还有我们常用用的选择一一个调用用RpcInvoker,然后 单点进行行服务调用用的方方式。其中,Dubbo的选择策略,也就是负载策略也是基于客户端的。
methodName, paramTypes, args, methodInfo == null ? -1 : methodInfo.getStat(), System.currentTimeMillis() - start); } } catch (Throwable shouldBeBizExThrowable) { // ServiceException从这里里抛出 if (logger.isInfoEnabled()) { (String.format(
简单示示例
首首先实现InvocationHandler,确保你需要做什么;
public class MockInvocationHandler implements InvocationHandler { /* (non-Javadoc) * @see ng.reflect.InvocationHandler#invoke(ng.Object, ng.reflect.Method, ng.Object[]) */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("InvokeHandler Invoke."); return null; }
methodName, paramTypes, args, methodInfo == null ? -1 : methodInfo.getStat(), System.currentTimeMillis() - start); } return result; } catch (RpcException rpce) { if (rpce.isBiz()) { throw rpce; } if (rpce.isTimeout()) { Monitor.trace(applicationTimeoutName, service.getName() + ":" + service.getVersion(),
这个是入入口口,一一个FactoryBean,主要观摩其getObject方方法,这个方方法将会产生生一一个依 赖方方所需使用用的引用用。
(3)Dubbo的微容器
com.alibaba.dubbo.service.internal.DefaultServiceManager
使用用微容器来保存服务名称和代理的关系,在后续请求过程中,能够加速访问,但是实 际上,只会在使用用spring的ApplicationContext.getObject时,才会触发这个类用用来生生成代理 的客户端和服务端
反射成员类图
Java对于上述成员描述的类图如下:
反射的简单应用用
如果我们知道了一一个Class里里的字段,那么我们能够很方方便的完成其get/set方方法的生生 成,如果给定两个Class,那么我们就有机会完成从一一个Class get属性然后set到另外一一个 Class的代码片片段生生成工工作。
serviceProxyMap.put(signature, proxy);
这里里负责客户端代理的生生成工工作。 (4)远程调用用 返回一一个代理,这个代理将对接口口的请求统一一委派到这个类
com.alibaba.dubbo.service.internal.DubboServiceClientInterceptor
}
其次,有一一个需要代理的接口口,注意,一一定是接口口;
public interface Mock { public String mock(String value);
}ห้องสมุดไป่ตู้
最后,将这个接口口生生成Proxy的字节码,如果已经生生成则不需要,然后将 InvocationHandler的实例设置入入Proxy的实例,当调用用Proxy的实例时,就会路由到 InvocationHandler中的invoke中执行行。
Object result = invoker.invoke(methodName, paramTypes, args, returnType, methodInfo); if (Monitor.isTraceEnabled()) { Monitor.trace(applicationInvokeName, service.getName() + ":" + service.getVersion(),
Java Reflection
Accessing members 简介
Java通过内置的Field、Method、Constructor等Member来描述一一个Class实例的组成部 分,能够让我们以代码编写的视角角去审视已经成型(被载入入内存)的代码,从而而使后续的代码 能够根据审视自自身身来做出行行为动作,从而而使程序在一一定程度上具备了自自动化或者说智能的特 性。
那么我们就从一一次dubbo调用用的过程,来揭开其面面纱。
一一般来说Dubbo从客户端出发,调用用步骤主要有主要如下:
(1)初始化过程:
com.alibaba.dubbo.service.spring.schema.DubboNamespaceHandler
用用来指定解析的parser
就用用来解析如下标签:
来源于那个类(全名),引用用名,⺫目目的类的全名和引用用名。
看一一下控制台,可以copy过去使用用了。
这样做的好处是,当你重构一一个字段名称的时候,编译器会帮你发现错误。不要使用用 BeanCopy之类的工工具,这只有在非非业务代码开发过程中的一一种简化Utils。
Dynamic Proxy 简介