简介摘要
SOFARPC服务调用创建服务引用配置ConsumerConfig,自定义设置接口名称、调用协议、直连调用地址以及连接超时时间等基础配置;通过服务消费者启动类ConsumerBootstrap引用服务,客户端集群Cluster调用消费端调用器ConsumerInvoker实现Client发送数据给Server调用过程。
SOFARPC以基于Netty实现的网络通信框架SOFABolt用作远程通信框架,使用者不用关心如何实现私有协议的细节,直接使用内置RPC通信协议,启动客户端与服务端同时注册用户请求处理器即可完成远程调用:
1调用方式
SOFARPC服务调用提供同步Sync、异步Future、回调Callback以及单向Oneway四种调用类型:
使用Future异步调用SOFABoot配置服务引用需要设置sofa:global-attrs元素的type属性声明调用方式为future:
如上设置为异步调用的方式。客户端获取响应结果有两种方式:
(1)通过 SofaResponseFuture直接获取结果。第一个参数是获取结果的超时时间,第二个参数表示是否清除线程上下文中的结果。
(2)获取原生Futrue,该种方式获取JDK原生的Future,参数表示是否清除线程上下文中的结果。因为响应结果放在JDK原生的Future,需要通过JDK Future的get()方法获取响应结果。
当前线程发起调用得到RpcResponseFuture对象,当前线程可以继续执行下一次调用。在任意时刻使用RpcResponseFuture对象的get()方法来获取结果,如果响应已经回来此时就马上得到结果;如果响应没有回来则阻塞住当前线程直到响应回来或者超时时间到。
(3)Callback回调调用
客户端提前设置回调实现类,在发起调用后不会等待结果,是真正的异步调用,永远不会阻塞线程,结果处理是在异步线程里执行。SOFA-RPC在获取到服务端的接口后会自动执行该回调实现,目前支持 bolt 协议。客户端回调类需要实现comalipaysofarpccoreinvokeSofaResponseCallback接口:
如上设置是服务级别的设置,也可以进行调用级别的设置:
使用Callback回调调用SOFABoot配置服务引用需要设置sofa:global-attrs元素的type属性声明调用方式为callback,通过callback-ref属性声明回调的实现类,使用该服务引用发起调用时结果返回时由SOFARPC自动执行该回调类:
当前线程发起调用则本次调用马上结束执行下一次调用。发起调用时需要注册回调,该回调需要分配异步线程池以待响应回来后在回调的异步线程池来执行回调逻辑。
(4)Oneway单向调用
客户端发送请求后不会等待服务端返回的结果,并且会忽略服务端的处理结果,目前支持bolt协议:
使用Oneway单向调用SOFABoot配置服务引用需要设置sofa:global-attrs元素的type属性声明调用方式为oneway:
当前线程发起调用后,不关心调用结果不做超时控制,只要请求已经发出就完成本次调用。单向调用不关心响应结果,请求线程不会被阻塞,使用Oneway调用需要注意控制调用节奏防止压垮接收方。注意Oneway调用不保证成功,而且发起方无法知道调用结果。因此通常用于可以重试,或者定时通知类的场景,调用过程是有可能因为网络问题、机器故障等原因导致请求失败,业务场景需要能接受这样的异常场景才能够使用。
2直连调用
SOFARPC支持指定地址进行调用的场景,设置直连地址即可:
3泛化调用
SOFARPC泛化调用方式能够在客户端不需要依赖服务端的接口情况下发起调用,目前支持bolt协议。由于不知道服务端的接口,因此需要通过字符串的方式将服务端的接口,调用的方法,参数及结果类进行描述:
如上通过setGeneric设置该服务为泛化服务,设置服务方的接口名。以GenericService作为泛化服务,通过GenericService能够发起泛化调用。发起调用时需要传入方法名、方法类型、方法参数。如果参数或者返回结果在客户端也需要泛化表示则通过GenericObject来实现获取序列化结果等:
(1)接口描述:所有泛化调用都需要在服务引用的时候声明interface为comalipaysofarpcapiGenericService,这是SOFARPC提供的类。真正的服务接口通过sofa:global-attrs元素的generic-interface属性声明完成接口的描述。
(2)参数描述:由于客户端没有调用服务的参数类,因此通过GenericObject进行描述,GenericObject持有Map<String, Object>类型的变量,能够通过GenericObject提供的对该变量的 *** 作方法将参数类的属性放到Map以此来描述参数类。
(3)发起泛化调用:接口描述通过XML配置声明泛化引用的bean,通过该泛化引用能够发起服务调用,发起泛化调用的第一个参数就是方法名,第二个参数就是参数类的全类名,第三个参数就是描述参数类的 GenericObject。
(4)获取泛化结果:发起泛化调用如果客户端同样没有泛化结果的类,那么同样以GenericObject对调用结果进行描述,通过GenericObject的getField方法能够获取结果类的属性值,通过GenericObject的getType方法能够获取结果类的全类名。
(5)泛化调用示例:SOFARPC泛化调用完整的泛化调用方式:
源码解析
1调用方式
参考sofa-rpc-boot-projects范例模块( comalipaysofarpcsamplesinvoke ):
运行调用方式服务端范例类InvokeServerApplication查看调用方式服务端输出日志:
参考1: >
最近做项目,无意间用到了spring注入集合的问题,具体问题如下:
在spring配置文件中配置map如下:
在项目中使用map如下:
@Autowired
private Map<String, HandlerInterceptor> handlerMap;
奇怪的是,当我使用handlerMapget("async")获取处理类时,获取不到具体的bean,这是怎么回事呢?
问题可能出现的原因:
1、map的key值被覆盖,xml配置不起作用
2、注入的map和xml配置的map不是同一个bean
问题排查:
首先我更改了xml配置,把bean的id修改成了handlerMap1重启服务,发现注入的handlerMap值还是存在的,并且map的key值是对应value bean的id。这样基本上排除了提出的第一个假设。那么,我们来看下第二种假设。
通过打断点debug等手段,我们很容易的得到结果,注入的map和xml配置的map实例化的bean不是同一个,问题解决。
那么,为什么我xml配置好一个map对象,注入的时候又会给我创建一个对象呢?
我们来看下@Autowired的注入方式:按照类型注入
然后,我们看下Autowired的注入解析流程,在实例化bean的时候,发现
根据上面的截图我们会发现,当我们用Autowired注入一个map或者其他集合类型时,spring不是根据beanName取bean然后赋值,而是根据设置的type从容器中一次性取出所有符合的bean直接放入到集合中。
现在知道问题的根源了,那我们怎么解决这个问题呢?
既然Autowired是按照类型注入的,那我们是不是可以选择按照名称注入呢@Resource
经测试 @Resource完全能解决问题!
applicationContextxml配置文件中配置的名叫adminprojecttypeAction的这个Action实例化失败了。 主要原因就是对应的AdminProjecrTypeAction这个类的构造方法里出现空的对象,导致空指针异常了。可以加断点调试一下,看看是哪个对象为空了。。。进行修复。
首先验证BeanDefinition, 验证通过之后, 判断BeanDefinition是否已经存在
在 refreshContext()刷新应用上下文 finishBeanFactoryInitialization方法中, 执行了beanFactorypreInstantiateSingletons方法, 预初始化了非延时加载bean
首先从beanDefinitionNames中获取BeanDefinition列表, 递归将parent和child BeanDefinition合并成一个RootBeanDefinition, 然后判断BeanDefinition是否为factoryBean
先判断是否为factoryBean, 如果是的话, 那么会调用其getObject方法, 获取bean, 之后检查bean是否循环依赖, 如果当前beanFactory中获取不到bean, 会尝试递归从父factory中加载bean, 之后把bean标记为已创建, 然后先去实例化依赖的bean, 最后判断bean的scope并实例化bean
先解析beanClass, 尝试重写方法, 执行InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation方法, 可以使用代理生成新的bean
创建bean的过程中, 先执行MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition, 然后执行BeanPostProcessor#postProcessBeforeInitialization, 再判断要采取的实例化策略, 一种是反射, 另一种是cglib动态代理, 然后使用策略实例化bean, 再执行BeanPostProcessor#postProcessAfterInitialization, 对bean进行增强处理
默认策略, 实例化对象, 如果有Override方法, 那么使用cglib实例化对象, 否则使用反射
cglib实例化对象
一 什么是Spring
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架
二 如何在程序中获取Spring配置的bean呢
方法一 在初始化时保存ApplicationContext对象
代码
ApplicationContext ac = new FileSystemXmlApplicationContex( applicationContext xml ); ac getBean( beanId );
ApplicationContext ac = new FileSystemXmlApplicationContex( applicationContext xml );
ac getBean( beanId );说明 这种方式适用于采用Spring框架的独立应用程序 需要程序通过配置文件手工初始化Spring的情况
方法二 通过Spring提供的工具类获取ApplicationContext对象
代码
import sprntext support WebApplicationContextUtils; ApplicationContext ac = WebApplicationContextUtils getRequiredWebApplicationContext(ServletContext sc) ApplicationContext ac = WebApplicationContextUtils getWebApplicationContext(ServletContext sc) ac getBean( beanId ); ac getBean( beanId ); import sprntext support WebApplicationContextUtils; ApplicationContext ac = WebApplicationContextUtils getRequiredWebApplicationContext(ServletContext sc) ApplicationContext ac = WebApplicationContextUtils getWebApplicationContext(ServletContext sc) ac getBean( beanId ); ac getBean( beanId );方法三 继承自抽象类ApplicationObjectSupport
说明 抽象类ApplicationObjectSupport提供getApplicationContext()方法 可以方便的获取到ApplicationContext Spring初始化时 会通过该抽象类的setApplicationContext(ApplicationContext context)方法将ApplicationContext 对象注入
方法四 继承自抽象类WebApplicationObjectSupport
说明 类似方法三 调用getWebApplicationContext()获取WebApplicationContext
方法五 实现接口ApplicationContextAware
lishixinzhi/Article/program/Java/ky/201311/28587
以上就是关于SOFARPC源码解析-服务调用全部的内容,包括:SOFARPC源码解析-服务调用、@Component 无法注入Bean ,无法使用 @value注解问题、spring用@Autowired注入map出现的问题等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)