dubbo源码分析-consumer端4-MockClusterInvoker
来源:互联网 发布:vscode xp版本 编辑:程序博客网 时间:2024/06/08 17:18
在前面几篇文章中,我们分析了consumer端的代理生成过程。创建完成后,应用就可以进行调用了,调用的代码如下:
-
- public String sayHello(String paramString) {
-
- Object[] arrayOfObject = new Object[1];
- arrayOfObject[0] = paramString;
-
- Object localObject = this.handler.invoke(this, methods[0], arrayOfObject);
- return (String)localObject;
- }
-
-
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-
- String methodName = method.getName();
- Class<?>[] parameterTypes = method.getParameterTypes();
- if (method.getDeclaringClass() == Object.class) {
- return method.invoke(invoker, args);
- }
- if ("toString".equals(methodName) && parameterTypes.length == 0) {
- return invoker.toString();
- }
- if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
- return invoker.hashCode();
- }
- if ("equals".equals(methodName) && parameterTypes.length == 1) {
- return invoker.equals(args[0]);
- }
-
- return invoker.invoke(new RpcInvocation(method, args)).recreate();
- }
Invocation的主要作用是将(远程)方法调用时需要的信息+Invoker封装起来, 这些信息包括:方法名、参数类型、参数值、附加信息。结合前一篇Invoker创建流程,我们知道此处的invoker为com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker,对应的invoke方法:- public Result invoke(Invocation invocation) throws RpcException {
- Result result = null;
-
- String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim();
- if (value.length() == 0 || value.equalsIgnoreCase("false")){
-
- result = this.invoker.invoke(invocation);
- } else if (value.startsWith("force")) {
- if (logger.isWarnEnabled()) {
- logger.info("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());
- }
-
- result = doMockInvoke(invocation, null);
- } else {
-
-
-
- try {
- result = this.invoker.invoke(invocation);
- }catch (RpcException e) {
- if (e.isBiz()) {
- throw e;
- } else {
- if (logger.isWarnEnabled()) {
- logger.info("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);
- }
- result = doMockInvoke(invocation, e);
- }
- }
- }
- return result;
- }
mock支持的配置方式包含多种: 1、return xxx (注意这里的xxx区分大小写)
empty: 返回空对象,根据Type返回空对象(单纯的new xxx()),如果是基础类型则返回对应的默认值
null: 返回null
true/false: 返回boolean
开头+结尾都是双引号(")或单引号(')的字符串:返回去掉开头、结尾字符的字符串
数字:返回数字
以{开头:按json格式解析,并将结果放入Map, 最终返回一个对象
以[开头:按json格式解析,并将结果放入List,最终返回一个List
其他:直接返回xxx
2、true/default
根据{interfaceName}Mock构造类名(如com.alibaba.dubbo.demo.DemoServiceMock),Mock类必须带有无参构造方法,如果失败则初始化失败,如果成功则在需要mock时会调用该类的对应方法
3、force:
return
+
null
直接往注册中心写入该mock规则,在配置文件中不能使用这种方式。主要是为了临时降级。
- private Result doMockInvoke(Invocation invocation,RpcException e){
- Result result = null;
- Invoker<T> minvoker ;
-
-
- List<Invoker<T>> mockInvokers = selectMockInvoker(invocation);
- if (mockInvokers == null || mockInvokers.size() == 0){
-
- minvoker = (Invoker<T>) new MockInvoker(directory.getUrl());
- } else {
- minvoker = mockInvokers.get(0);
- }
- try {
- result = minvoker.invoke(invocation);
- } catch (RpcException me) {
- if (me.isBiz()) {
- result = new RpcResult(me.getCause());
- } else {
- throw new RpcException(me.getCode(), getMockExceptionMessage(e, me), me.getCause());
- }
- } catch (Throwable me) {
- throw new RpcException(getMockExceptionMessage(e, me), me.getCause());
- }
- return result;
- }
MockInvoker的invoke方法:- public Result invoke(Invocation invocation) throws RpcException {
- String mock = getUrl().getParameter(invocation.getMethodName()+"."+Constants.MOCK_KEY);
- if (invocation instanceof RpcInvocation) {
- ((RpcInvocation) invocation).setInvoker(this);
- }
- if (StringUtils.isBlank(mock)){
- mock = getUrl().getParameter(Constants.MOCK_KEY);
- }
-
- if (StringUtils.isBlank(mock)){
- throw new RpcException(new IllegalAccessException("mock can not be null. url :" + url));
- }
- mock = normallizeMock(URL.decode(mock));
- if (Constants.RETURN_PREFIX.trim().equalsIgnoreCase(mock.trim())){
-
- RpcResult result = new RpcResult();
- result.setValue(null);
- return result;
- } else if (mock.startsWith(Constants.RETURN_PREFIX)) {
-
- mock = mock.substring(Constants.RETURN_PREFIX.length()).trim();
- mock = mock.replace('`', '"');
- try {
- Type[] returnTypes = RpcUtils.getReturnTypes(invocation);
- Object value = parseMockValue(mock, returnTypes);
- return new RpcResult(value);
- } catch (Exception ew) {
- throw new RpcException("mock return invoke error. method :" + invocation.getMethodName() + ", mock:" + mock + ", url: "+ url , ew);
- }
- } else if (mock.startsWith(Constants.THROW_PREFIX)) {
-
- mock = mock.substring(Constants.THROW_PREFIX.length()).trim();
- mock = mock.replace('`', '"');
- if (StringUtils.isBlank(mock)){
- throw new RpcException(" mocked exception for Service degradation. ");
- } else {
- Throwable t = getThrowable(mock);
- throw new RpcException(RpcException.BIZ_EXCEPTION, t);
- }
- } else {
- try {
- Invoker<T> invoker = getInvoker(mock);
- return invoker.invoke(invocation);
- } catch (Throwable t) {
- throw new RpcException("Failed to create mock implemention class " + mock , t);
- }
- }
- }
-
- private Invoker<T> getInvoker(String mockService){
-
- Invoker<T> invoker =(Invoker<T>) mocks.get(mockService);
- if (invoker != null ){
- return invoker;
- } else {
-
-
- Class<T> serviceType = (Class<T>)ReflectUtils.forName(url.getServiceInterface());
- if (ConfigUtils.isDefault(mockService)) {
- mockService = serviceType.getName() + "Mock";
- }
-
- Class<?> mockClass = ReflectUtils.forName(mockService);
- if (! serviceType.isAssignableFrom(mockClass)) {
- throw new IllegalArgumentException("The mock implemention class " + mockClass.getName() + " not implement interface " + serviceType.getName());
- }
-
- if (! serviceType.isAssignableFrom(mockClass)) {
- throw new IllegalArgumentException("The mock implemention class " + mockClass.getName() + " not implement interface " + serviceType.getName());
- }
- try {
-
- T mockObject = (T) mockClass.newInstance();
- invoker = proxyFactory.getInvoker(mockObject, (Class<T>)serviceType, url);
-
- if (mocks.size() < 10000) {
- mocks.put(mockService, invoker);
- }
- return invoker;
- } catch (InstantiationException e) {
- throw new IllegalStateException("No such empty constructor \"public " + mockClass.getSimpleName() + "()\" in mock implemention class " + mockClass.getName(), e);
- } catch (IllegalAccessException e) {
- throw new IllegalStateException(e);
- }
- }
- }
此时的url protocol,proxyFactory最终调用包装了JavassistProxyFactory的StubProxyFactoryWrapper,这里的getInvoker方法直接调用了JavassistProxyFactory.getInvoker(proxy, type, url), JavassistProxyFactory根据mock类生成的代理类,在invoke方法中调用mock类的对应方法。
mock 逻辑并不复杂,但是在系统降级时非常有用。至于如何在线上修改配置进行降级,我们后面再聊。