dubbo源码-服务发现

本是古典 何须时尚 2021-11-22 13:44 476阅读 0赞

服务消费者

  1. <!-- consumer's application name, used for tracing dependency relationship (not a matching criterion),
  2. don't set it same as provider -->
  3. <dubbo:application name="dubbo-consumer"/>
  4. <!-- protocol="zookeeper"必须有 -->
  5. <dubbo:registry protocol="zookeeper" address="${dubbo.registry.address}"/>
  6. <!-- generate proxy for the remote service, then demoService can be used in the same way as the
  7. local regular interface -->
  8. <dubbo:reference id="userService" check="false" interface="com.study.dubbo.userapi.service.UserService" loadbalance="consistenthash"/>

ReferenceBean

  1. public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean {
  2. private static final long serialVersionUID = 213195494150089726L;
  3. private transient ApplicationContext applicationContext;
  4. public ReferenceBean() {
  5. super();
  6. }
  7. public ReferenceBean(Reference reference) {
  8. super(reference);
  9. }
  10. public void setApplicationContext(ApplicationContext applicationContext) {
  11. this.applicationContext = applicationContext;
  12. SpringExtensionFactory.addApplicationContext(applicationContext);
  13. }
  14. public Object getObject() throws Exception {
  15. return get();
  16. }
  17. public Class<?> getObjectType() {
  18. return getInterfaceClass();
  19. }
  20. @Parameter(excluded = true)
  21. public boolean isSingleton() {
  22. return true;
  23. }
  24. @SuppressWarnings({"unchecked"})
  25. public void afterPropertiesSet() throws Exception {
  26. if (getConsumer() == null) {
  27. Map<String, ConsumerConfig> consumerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ConsumerConfig.class, false, false);
  28. if (consumerConfigMap != null && consumerConfigMap.size() > 0) {
  29. ConsumerConfig consumerConfig = null;
  30. for (ConsumerConfig config : consumerConfigMap.values()) {
  31. if (config.isDefault() == null || config.isDefault().booleanValue()) {
  32. if (consumerConfig != null) {
  33. throw new IllegalStateException("Duplicate consumer configs: " + consumerConfig + " and " + config);
  34. }
  35. consumerConfig = config;
  36. }
  37. }
  38. if (consumerConfig != null) {
  39. setConsumer(consumerConfig);
  40. }
  41. }
  42. }
  43. if (getApplication() == null
  44. && (getConsumer() == null || getConsumer().getApplication() == null)) {
  45. Map<String, ApplicationConfig> applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false, false);
  46. if (applicationConfigMap != null && applicationConfigMap.size() > 0) {
  47. ApplicationConfig applicationConfig = null;
  48. for (ApplicationConfig config : applicationConfigMap.values()) {
  49. if (config.isDefault() == null || config.isDefault().booleanValue()) {
  50. if (applicationConfig != null) {
  51. throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config);
  52. }
  53. applicationConfig = config;
  54. }
  55. }
  56. if (applicationConfig != null) {
  57. setApplication(applicationConfig);
  58. }
  59. }
  60. }
  61. if (getModule() == null
  62. && (getConsumer() == null || getConsumer().getModule() == null)) {
  63. Map<String, ModuleConfig> moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, false, false);
  64. if (moduleConfigMap != null && moduleConfigMap.size() > 0) {
  65. ModuleConfig moduleConfig = null;
  66. for (ModuleConfig config : moduleConfigMap.values()) {
  67. if (config.isDefault() == null || config.isDefault().booleanValue()) {
  68. if (moduleConfig != null) {
  69. throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config);
  70. }
  71. moduleConfig = config;
  72. }
  73. }
  74. if (moduleConfig != null) {
  75. setModule(moduleConfig);
  76. }
  77. }
  78. }
  79. if ((getRegistries() == null || getRegistries().isEmpty())
  80. && (getConsumer() == null || getConsumer().getRegistries() == null || getConsumer().getRegistries().isEmpty())
  81. && (getApplication() == null || getApplication().getRegistries() == null || getApplication().getRegistries().isEmpty())) {
  82. Map<String, RegistryConfig> registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false);
  83. if (registryConfigMap != null && registryConfigMap.size() > 0) {
  84. List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();
  85. for (RegistryConfig config : registryConfigMap.values()) {
  86. if (config.isDefault() == null || config.isDefault().booleanValue()) {
  87. registryConfigs.add(config);
  88. }
  89. }
  90. if (registryConfigs != null && !registryConfigs.isEmpty()) {
  91. super.setRegistries(registryConfigs);
  92. }
  93. }
  94. }
  95. if (getMonitor() == null
  96. && (getConsumer() == null || getConsumer().getMonitor() == null)
  97. && (getApplication() == null || getApplication().getMonitor() == null)) {
  98. Map<String, MonitorConfig> monitorConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, false, false);
  99. if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
  100. MonitorConfig monitorConfig = null;
  101. for (MonitorConfig config : monitorConfigMap.values()) {
  102. if (config.isDefault() == null || config.isDefault().booleanValue()) {
  103. if (monitorConfig != null) {
  104. throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config);
  105. }
  106. monitorConfig = config;
  107. }
  108. }
  109. if (monitorConfig != null) {
  110. setMonitor(monitorConfig);
  111. }
  112. }
  113. }
  114. Boolean b = isInit();
  115. if (b == null && getConsumer() != null) {
  116. b = getConsumer().isInit();
  117. }
  118. if (b != null && b.booleanValue()) {
  119. getObject();
  120. }
  121. }
  122. @Override
  123. public void destroy() {
  124. // do nothing
  125. }
  126. }

afterPropertiesSet初始化,调用getObject方法获取bean

ReferenceConfig

  1. public synchronized T get() {
  2. if (destroyed) {
  3. throw new IllegalStateException("Already destroyed!");
  4. }
  5. if (ref == null) {
  6. init();
  7. }
  8. return ref;
  9. }
  10. private void init() {
  11. if (initialized) {
  12. return;
  13. }
  14. initialized = true;
  15. if (interfaceName == null || interfaceName.length() == 0) {
  16. throw new IllegalStateException("<dubbo:reference interface=\"\" /> interface not allow null!");
  17. }
  18. // get consumer's global configuration
  19. checkDefault();
  20. appendProperties(this);
  21. if (getGeneric() == null && getConsumer() != null) {
  22. setGeneric(getConsumer().getGeneric());
  23. }
  24. if (ProtocolUtils.isGeneric(getGeneric())) {
  25. interfaceClass = GenericService.class;
  26. } else {
  27. try {
  28. interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
  29. .getContextClassLoader());
  30. } catch (ClassNotFoundException e) {
  31. throw new IllegalStateException(e.getMessage(), e);
  32. }
  33. checkInterfaceAndMethods(interfaceClass, methods);
  34. }
  35. String resolve = System.getProperty(interfaceName);
  36. String resolveFile = null;
  37. if (resolve == null || resolve.length() == 0) {
  38. resolveFile = System.getProperty("dubbo.resolve.file");
  39. if (resolveFile == null || resolveFile.length() == 0) {
  40. File userResolveFile = new File(new File(System.getProperty("user.home")), "dubbo-resolve.properties");
  41. if (userResolveFile.exists()) {
  42. resolveFile = userResolveFile.getAbsolutePath();
  43. }
  44. }
  45. if (resolveFile != null && resolveFile.length() > 0) {
  46. Properties properties = new Properties();
  47. FileInputStream fis = null;
  48. try {
  49. fis = new FileInputStream(new File(resolveFile));
  50. properties.load(fis);
  51. } catch (IOException e) {
  52. throw new IllegalStateException("Unload " + resolveFile + ", cause: " + e.getMessage(), e);
  53. } finally {
  54. try {
  55. if (null != fis) fis.close();
  56. } catch (IOException e) {
  57. logger.warn(e.getMessage(), e);
  58. }
  59. }
  60. resolve = properties.getProperty(interfaceName);
  61. }
  62. }
  63. if (resolve != null && resolve.length() > 0) {
  64. url = resolve;
  65. if (logger.isWarnEnabled()) {
  66. if (resolveFile != null && resolveFile.length() > 0) {
  67. logger.warn("Using default dubbo resolve file " + resolveFile + " replace " + interfaceName + "" + resolve + " to p2p invoke remote service.");
  68. } else {
  69. logger.warn("Using -D" + interfaceName + "=" + resolve + " to p2p invoke remote service.");
  70. }
  71. }
  72. }
  73. if (consumer != null) {
  74. if (application == null) {
  75. application = consumer.getApplication();
  76. }
  77. if (module == null) {
  78. module = consumer.getModule();
  79. }
  80. if (registries == null) {
  81. registries = consumer.getRegistries();
  82. }
  83. if (monitor == null) {
  84. monitor = consumer.getMonitor();
  85. }
  86. }
  87. if (module != null) {
  88. if (registries == null) {
  89. registries = module.getRegistries();
  90. }
  91. if (monitor == null) {
  92. monitor = module.getMonitor();
  93. }
  94. }
  95. if (application != null) {
  96. if (registries == null) {
  97. registries = application.getRegistries();
  98. }
  99. if (monitor == null) {
  100. monitor = application.getMonitor();
  101. }
  102. }
  103. checkApplication();
  104. checkStubAndMock(interfaceClass);
  105. Map<String, String> map = new HashMap<String, String>();
  106. Map<Object, Object> attributes = new HashMap<Object, Object>();
  107. map.put(Constants.SIDE_KEY, Constants.CONSUMER_SIDE);
  108. map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion());
  109. map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
  110. if (ConfigUtils.getPid() > 0) {
  111. map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
  112. }
  113. if (!isGeneric()) {
  114. String revision = Version.getVersion(interfaceClass, version);
  115. if (revision != null && revision.length() > 0) {
  116. map.put("revision", revision);
  117. }
  118. String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
  119. if (methods.length == 0) {
  120. logger.warn("NO method found in service interface " + interfaceClass.getName());
  121. map.put("methods", Constants.ANY_VALUE);
  122. } else {
  123. map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
  124. }
  125. }
  126. map.put(Constants.INTERFACE_KEY, interfaceName);
  127. appendParameters(map, application);
  128. appendParameters(map, module);
  129. appendParameters(map, consumer, Constants.DEFAULT_KEY);
  130. appendParameters(map, this);
  131. String prefix = StringUtils.getServiceKey(map);
  132. if (methods != null && !methods.isEmpty()) {
  133. for (MethodConfig method : methods) {
  134. appendParameters(map, method, method.getName());
  135. String retryKey = method.getName() + ".retry";
  136. if (map.containsKey(retryKey)) {
  137. String retryValue = map.remove(retryKey);
  138. if ("false".equals(retryValue)) {
  139. map.put(method.getName() + ".retries", "0");
  140. }
  141. }
  142. appendAttributes(attributes, method, prefix + "." + method.getName());
  143. checkAndConvertImplicitConfig(method, map, attributes);
  144. }
  145. }
  146. String hostToRegistry = ConfigUtils.getSystemProperty(Constants.DUBBO_IP_TO_REGISTRY);
  147. if (hostToRegistry == null || hostToRegistry.length() == 0) {
  148. hostToRegistry = NetUtils.getLocalHost();
  149. } else if (isInvalidLocalHost(hostToRegistry)) {
  150. throw new IllegalArgumentException("Specified invalid registry ip from property:" + Constants.DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
  151. }
  152. map.put(Constants.REGISTER_IP_KEY, hostToRegistry);
  153. //attributes are stored by system context.
  154. StaticContext.getSystemContext().putAll(attributes);
  155. ref = createProxy(map);
  156. ConsumerModel consumerModel = new ConsumerModel(getUniqueServiceName(), this, ref, interfaceClass.getMethods());
  157. ApplicationModel.initConsumerModel(getUniqueServiceName(), consumerModel);
  158. }

ReferenceConfig创建代理

  1. @SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
  2. private T createProxy(Map<String, String> map) {
  3. URL tmpUrl = new URL("temp", "localhost", 0, map);
  4. final boolean isJvmRefer;
  5. if (isInjvm() == null) {
  6. if (url != null && url.length() > 0) { // if a url is specified, don't do local reference
  7. isJvmRefer = false;
  8. } else if (InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl)) {
  9. // by default, reference local service if there is
  10. isJvmRefer = true;
  11. } else {
  12. isJvmRefer = false;
  13. }
  14. } else {
  15. isJvmRefer = isInjvm().booleanValue();
  16. }
  17. if (isJvmRefer) {
  18. URL url = new URL(Constants.LOCAL_PROTOCOL, NetUtils.LOCALHOST, 0, interfaceClass.getName()).addParameters(map);
  19. invoker = refprotocol.refer(interfaceClass, url);
  20. if (logger.isInfoEnabled()) {
  21. logger.info("Using injvm service " + interfaceClass.getName());
  22. }
  23. } else {
  24. if (url != null && url.length() > 0) { // user specified URL, could be peer-to-peer address, or register center's address.
  25. String[] us = Constants.SEMICOLON_SPLIT_PATTERN.split(url);
  26. if (us != null && us.length > 0) {
  27. for (String u : us) {
  28. URL url = URL.valueOf(u);
  29. if (url.getPath() == null || url.getPath().length() == 0) {
  30. url = url.setPath(interfaceName);
  31. }
  32. if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
  33. urls.add(url.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)));
  34. } else {
  35. urls.add(ClusterUtils.mergeUrl(url, map));
  36. }
  37. }
  38. }
  39. } else { // assemble URL from register center's configuration
  40. List<URL> us = loadRegistries(false);
  41. if (us != null && !us.isEmpty()) {
  42. for (URL u : us) {
  43. URL monitorUrl = loadMonitor(u);
  44. if (monitorUrl != null) {
  45. map.put(Constants.MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
  46. }
  47. urls.add(u.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)));
  48. }
  49. }
  50. if (urls == null || urls.isEmpty()) {
  51. throw new IllegalStateException("No such any registry to reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", please config <dubbo:registry address=\"...\" /> to your spring config.");
  52. }
  53. }
  54. if (urls.size() == 1) {
  55. invoker = refprotocol.refer(interfaceClass, urls.get(0));
  56. } else {
  57. List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
  58. URL registryURL = null;
  59. for (URL url : urls) {
  60. invokers.add(refprotocol.refer(interfaceClass, url));
  61. if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
  62. registryURL = url; // use last registry url
  63. }
  64. }
  65. if (registryURL != null) { // registry url is available
  66. // use AvailableCluster only when register's cluster is available
  67. URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME);
  68. invoker = cluster.join(new StaticDirectory(u, invokers));
  69. } else { // not a registry url
  70. invoker = cluster.join(new StaticDirectory(invokers));
  71. }
  72. }
  73. }
  74. Boolean c = check;
  75. if (c == null && consumer != null) {
  76. c = consumer.isCheck();
  77. }
  78. if (c == null) {
  79. c = true; // default true
  80. }
  81. if (c && !invoker.isAvailable()) {
  82. throw new IllegalStateException("Failed to check the status of the service " + interfaceName + ". No provider available for the service " + (group == null ? "" : group + "/") + interfaceName + (version == null ? "" : ":" + version) + " from the url " + invoker.getUrl() + " to the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion());
  83. }
  84. if (logger.isInfoEnabled()) {
  85. logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl());
  86. }
  87. // create service proxy
  88. return (T) proxyFactory.getProxy(invoker);
  89. }

DubboProtocol

  1. public <T> Invoker<T> refer(Class<T> serviceType, URL url) throws RpcException {
  2. optimizeSerialization(url);
  3. // create rpc invoker.
  4. DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);
  5. invokers.add(invoker);
  6. return invoker;
  7. }

DubboInvoker

  1. public class DubboInvoker<T> extends AbstractInvoker<T> {
  2. public DubboInvoker(Class<T> serviceType, URL url, ExchangeClient[] clients, Set<Invoker<?>> invokers) {
  3. super(serviceType, url, new String[]{Constants.INTERFACE_KEY, Constants.GROUP_KEY, Constants.TOKEN_KEY, Constants.TIMEOUT_KEY});
  4. this.clients = clients;
  5. // get version.
  6. this.version = url.getParameter(Constants.VERSION_KEY, "0.0.0");
  7. this.invokers = invokers;
  8. }
  9. @Override
  10. protected Result doInvoke(final Invocation invocation) throws Throwable {
  11. RpcInvocation inv = (RpcInvocation) invocation;
  12. final String methodName = RpcUtils.getMethodName(invocation);
  13. inv.setAttachment(Constants.PATH_KEY, getUrl().getPath());
  14. inv.setAttachment(Constants.VERSION_KEY, version);
  15. ExchangeClient currentClient;
  16. if (clients.length == 1) {
  17. currentClient = clients[0];
  18. } else {
  19. currentClient = clients[index.getAndIncrement() % clients.length];
  20. }
  21. try {
  22. boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);
  23. boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
  24. int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
  25. if (isOneway) {
  26. boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
  27. currentClient.send(inv, isSent);
  28. RpcContext.getContext().setFuture(null);
  29. return new RpcResult();
  30. } else if (isAsync) {
  31. ResponseFuture future = currentClient.request(inv, timeout);
  32. RpcContext.getContext().setFuture(new FutureAdapter<Object>(future));
  33. return new RpcResult();
  34. } else {
  35. RpcContext.getContext().setFuture(null);
  36. return (Result) currentClient.request(inv, timeout).get();
  37. }
  38. } catch (TimeoutException e) {
  39. throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
  40. } catch (RemotingException e) {
  41. throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
  42. }
  43. }

AbstractInvoker

  1. public Result invoke(Invocation inv) throws RpcException {
  2. if (destroyed.get()) {
  3. throw new RpcException("Rpc invoker for service " + this + " on consumer " + NetUtils.getLocalHost()
  4. + " use dubbo version " + Version.getVersion()
  5. + " is DESTROYED, can not be invoked any more!");
  6. }
  7. RpcInvocation invocation = (RpcInvocation) inv;
  8. invocation.setInvoker(this);
  9. if (attachment != null && attachment.size() > 0) {
  10. invocation.addAttachmentsIfAbsent(attachment);
  11. }
  12. Map<String, String> context = RpcContext.getContext().getAttachments();
  13. if (context != null) {
  14. invocation.addAttachmentsIfAbsent(context);
  15. }
  16. if (getUrl().getMethodParameter(invocation.getMethodName(), Constants.ASYNC_KEY, false)) {
  17. invocation.setAttachment(Constants.ASYNC_KEY, Boolean.TRUE.toString());
  18. }
  19. RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
  20. try {
  21. return doInvoke(invocation);
  22. } catch (InvocationTargetException e) { // biz exception
  23. Throwable te = e.getTargetException();
  24. if (te == null) {
  25. return new RpcResult(e);
  26. } else {
  27. if (te instanceof RpcException) {
  28. ((RpcException) te).setCode(RpcException.BIZ_EXCEPTION);
  29. }
  30. return new RpcResult(te);
  31. }
  32. } catch (RpcException e) {
  33. if (e.isBiz()) {
  34. return new RpcResult(e);
  35. } else {
  36. throw e;
  37. }
  38. } catch (Throwable e) {
  39. return new RpcResult(e);
  40. }
  41. }

doInvoke模板方法,子类DubboInvoker实现

Invoker接口,核心是invoke方法

  1. public interface Invoker<T> extends Node {
  2. /**
  3. * get service interface.
  4. *
  5. * @return service interface.
  6. */
  7. Class<T> getInterface();
  8. /**
  9. * invoke.
  10. *
  11. * @param invocation
  12. * @return result
  13. * @throws RpcException
  14. */
  15. Result invoke(Invocation invocation) throws RpcException;
  16. }

然后看createProxy方法的最后面,getProxy
AbstractProxyFactory

  1. public abstract class AbstractProxyFactory implements ProxyFactory {
  2. public <T> T getProxy(Invoker<T> invoker) throws RpcException {
  3. Class<?>[] interfaces = null;
  4. String config = invoker.getUrl().getParameter("interfaces");
  5. if (config != null && config.length() > 0) {
  6. String[] types = Constants.COMMA_SPLIT_PATTERN.split(config);
  7. if (types != null && types.length > 0) {
  8. interfaces = new Class<?>[types.length + 2];
  9. interfaces[0] = invoker.getInterface();
  10. interfaces[1] = EchoService.class;
  11. for (int i = 0; i < types.length; i++) {
  12. interfaces[i + 1] = ReflectUtils.forName(types[i]);
  13. }
  14. }
  15. }
  16. if (interfaces == null) {
  17. interfaces = new Class<?>[]{invoker.getInterface(), EchoService.class};
  18. }
  19. return getProxy(invoker, interfaces);
  20. }
  21. public abstract <T> T getProxy(Invoker<T> invoker, Class<?>[] types);
  22. }

JavassistProxyFactory

  1. public class JavassistProxyFactory extends AbstractProxyFactory {
  2. @SuppressWarnings("unchecked")
  3. public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
  4. return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
  5. }
  6. public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
  7. // TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
  8. final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
  9. return new AbstractProxyInvoker<T>(proxy, type, url) {
  10. @Override
  11. protected Object doInvoke(T proxy, String methodName,
  12. Class<?>[] parameterTypes,
  13. Object[] arguments) throws Throwable {
  14. return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
  15. }
  16. };
  17. }
  18. }

发表评论

表情:
评论列表 (有 0 条评论,476人围观)

还没有评论,来说两句吧...

相关阅读