同步操作将从 venwyhk/ikasoa 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
ikasoa是一套java分布式服务化治理解决方案,基于thrift框架开发.其中ikasoa-rpc是ikasoa的开源RPC框架,客户端可以像调用本地接口那样去调用远程接口.
example : 示例代码
ikasoa-core : 基础核心包
ikasoa-rpc : 实现RPC功能的代码
ikasoa-zk : 利用Zookeeper注册和更新服务
需要修改pom.xml文件,添加ikasoa-rpc的依赖:
pom.xml
......
<dependency>
<groupId>com.ikasoa</groupId>
<artifactId>ikasoa-rpc</artifactId>
<version>0.3.1-BETA</version>
</dependency>
......
如果仅使用thrift兼容方式,则可以只添加ikasoa-core依赖:
pom.xml
......
<dependency>
<groupId>com.ikasoa</groupId>
<artifactId>ikasoa-core</artifactId>
<version>0.5.1</version>
</dependency>
......
工程目录下命令行执行命令mvn eclipse:eclipse
,并导入eclipse.(如果IDE非eclipse,则使用相对应的方式导入)
执行命令mvn clean package
打包.
新建例子接口(ExampleService.java),对象(ExampleVO.java)和实现 (ExampleServiceImpl.java)类:
ExampleService.java
public interface ExampleService {
// 查询对象
public ExampleVO findVO(int id);
}
ExampleServiceImpl.java
public class ExampleServiceImpl implements ExampleService {
@Override
public ExampleVO findVO(int id) {
return new ExampleVO(id, "helloworld");
}
}
ExampleVO.java
public class ExampleVO {
private int id;
private String string;
public ExampleVO() {
}
public ExampleVO(int id, String string) {
this.id = id;
this.string = string;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
}
Server.java
import com.ikasoa.rpc.DefaultIkasoaFactory;
import com.ikasoa.rpc.IkasoaException;
import com.ikasoa.rpc.IkasoaServer;
public class Server {
private static IkasoaServer ikasoaServer;
public static void start() {
try {
if (ikasoaServer == null) {
ikasoaServer = new DefaultIkasoaFactory().getIkasoaServer(ExampleServiceImpl.class, 9999);
}
// 启动服务
ikasoaServer.run();
} catch (IkasoaException e) {
e.printStackTrace();
}
}
public static void stop() {
if (ikasoaServer != null && ikasoaServer.isServing()) {
// 停止服务
ikasoaServer.stop();
}
}
}
Client.java
import com.ikasoa.rpc.DefaultIkasoaFactory;
public class Client {
public static void call() {
// 客户端获取远程接口实现
ExampleService es = new DefaultIkasoaFactory().getIkasoaClient(ExampleService.class, "localhost", 9999);
// 客户端输出结果
System.out.println(es.findVO(1).getString());
}
}
Main.java
public class Main {
public static void main(String[] args) {
try {
// 启动服务
Server.start();
Thread.sleep(100);
// 客户端调用
Client.call();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 停止服务
Server.stop();
}
}
}
执行Main.java,或单独调用Server.start()
启动服务后再调用Client.call()
执行.
如输出“helloworld”则表示执行成功.
可参考ikasoa-example的示例.
此示例程序需要使用到Spring框架.
bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
......
<!-- 服务端配置 -->
<bean id="rpcServer" class="example.ikasoa.RpcServer" init-method="run" destroy-method="stop">
<constructor-arg index="0" ref="ikasoaFactory"/>
<constructor-arg index="1">
<value>9993</value><!-- 设置服务开放端口 -->
</constructor-arg>
</bean>
<bean id="ikasoaFactory" class="com.ikasoa.rpc.DefaultIkasoaFactory"/>
......
</beans>
RpcServer.java
package example.ikasoa;
import com.ikasoa.rpc.IkasoaException;
import com.ikasoa.rpc.IkasoaFactory;
import com.ikasoa.rpc.IkasoaServer;
public class RpcServer {
private IkasoaServer server;
public RpcServer(IkasoaFactory ikasoaFactory, int serverPort) throws IkasoaException {
// 实现类不能是抽象类
this.server = ikasoaFactory.getIkasoaServer(ExampleServiceImpl.class, serverPort);
// 如果已有实例化后的对象(例如通过Spring注入的对象),则可以通过ImplClsCon类进行封装,ikasoa-rpc将会直接引用该类的实例,而不会重新实例化.
// 例子如下:
// this.server = ikasoaFactory.getIkasoaServer(new ImplClsCon(ExampleServiceImpl.class, exampleServiceImpl), serverPort);
// 如有多个接口实现,可以传入List.
// 例子如下:
// List<ImplClsCon> sList = new ArrayList<ImplClsCon>();
// sList.add(new ImplClsCon(ExampleServiceImpl.class));
// sList.add(new ImplClsCon(Example2ServiceImpl.class));
// this.server = ikasoaFactory.getIkasoaServer(sList, serverPort);
System.out.println("服务端口:" + serverPort);
for (String key : this.server.getIkasoaServiceKeys()) {
System.out.println("加载服务:" + key);
}
}
public void run() {
server.run();
}
public void stop() {
server.stop();
}
}
RpcClient.java
package example.ikasoa;
import com.ikasoa.rpc.DefaultIkasoaFactory;
public class RpcClient {
public static void main(String[] args) {
// 如果接口之间有继承关系,则只需要配置子接口类
// 设置服务器地址为”hocalhost”,端口为9993
ExampleService es = new DefaultIkasoaFactory().getIkasoaClient(ExampleService.class, "localhost", 9993);
// 如果有多个服务提供者,服务器地址和端口也可以传入List,系统将自动执行负载均衡(默认负载均衡规则为轮询,此外还支持随机,详见'负载均衡'文档目录).
// 例子如下:
// List<ServerInfo> serverInfoList = new ArrayList<ServerInfo>();
// serverInfoList.add(new ServerInfo("localhost", 9993));
// serverInfoList.add(new ServerInfo("192.168.1.41", 9993));
// ExampleService es = new DefaultIkasoaFactory().getIkasoaClient(ExampleService.class, serverInfoList);
System.out.println(es.findVO(1).getString());
}
}
如输出”helloworld”则表示执行成功.
ThriftClientDemo.java
package example.ikasoa;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportFactory;
import com.ikasoa.core.thrift.client.ThriftClient;
import com.ikasoa.core.thrift.client.ThriftClientConfiguration;
import com.ikasoa.rpc.DefaultIkasoaFactory;
import com.ikamobile.tmcs.controller.thrift.server.acceptor.GeneralThriftAcceptor;
public class ThriftClientDemo {
public static void main(String[] args) {
ThriftClientConfiguration configuration = new ThriftClientConfiguration();
configuration.setTransportFactory(new TTransportFactory()); // 协议需要与服务端匹配
// 如果只依赖ikasoa-core,这里也可以使用com.ikasoa.core.thrift.GeneralFactory来替代DefaultIkasoaFactory
ThriftClient thriftClient = new DefaultIkasoaFactory(configuration).getThriftClient("121.40.119.240", 9201); // 配置Thrift的服务器地址和端口
TTransport transport = null;
try {
transport = thriftClient.getTransport();
transport.open();
// GeneralThriftAcceptor为ThriftIDL配置所生成的service
GeneralThriftAcceptor.Client client = new GeneralThriftAcceptor.Client(
thriftClient.getProtocol(transport, "GeneralThriftAcceptor")); // 参数"GeneralThriftAcceptor"为服务的key,如果没有则可以不传
// 打印结果
System.out.println(client.getTmc(1));
} catch (Exception e) {
e.printStackTrace();
} finally {
transport.close();
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
......
<!-- Thrift服务配置 -->
<bean id="thriftServer2" class="com.ikasoa.core.thrift.server.impl.DefaultThriftServerImpl" init-method="run" destroy-method="stop">
<property name="serverName" value="xxxServer" /><!-- 服务名称 -->
<property name="serverPort" value="9899" /><!-- 服务端口 -->
<property name="thriftServerConfiguration">
<bean class="com.ikasoa.core.thrift.server.ThriftServerConfiguration">
<property name="transportFactory"><!-- 指定传输协议工厂(可选,默认为TFramedTransport.Factory) -->
<bean class="org.apache.thrift.transport.TTransportFactory" />
</property>
</bean>
</property>
<property name="processor">
<bean class="com.xxx.service.ThriftService.Processor"><!-- ThriftService为通过idl生成的服务类 -->
<constructor-arg ref="thriftService" />
</bean>
</property>
</bean>
<bean id="thriftService" class="com.xxx.service.impl.ThriftServiceImpl"/><!-- ThriftService.Iface接口的实现 -->
......
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
......
<!-- Thrift服务配置(嵌套方式) -->
<bean id="thriftServer1" class="com.ikasoa.core.thrift.server.impl.DefaultThriftServerImpl" init-method="run" destroy-method="stop">
<property name="serverName" value="xxxServer" /><!-- 服务名称 -->
<property name="serverPort" value="9898" /><!-- 服务端口 -->
<property name="thriftServerConfiguration">
<bean class="com.ikasoa.core.thrift.server.ThriftServerConfiguration">
<property name="transportFactory"><!-- 指定传输协议工厂(可选,默认为TFramedTransport.Factory) -->
<bean class="org.apache.thrift.transport.TTransportFactory" />
</property>
</bean>
</property>
<property name="processor">
<bean class="com.ikasoa.core.thrift.server.MultiplexedProcessor">
<constructor-arg>
<map>
<entry key="Service1"><!-- 这里的key可以随便取,保证唯一就行,Client调用的时候需要用 -->
<bean class="com.xxx.service.ThriftService1.Processor"><!-- ThriftService1和ThriftService2为通过idl生成的服务类 -->
<constructor-arg ref="thriftService1" />
</bean>
</entry>
<entry key="Service2">
<bean class="com.xxx.service.ThriftService2.Processor">
<constructor-arg ref="thriftService2" />
</bean>
</entry>
</map>
</constructor-arg>
</bean>
</property>
</bean>
<bean id="thriftService1" class="com.xxx.service.impl.ThriftService1Impl"/><!-- ThriftService1.Iface接口的实现 -->
<bean id="thriftService2" class="com.xxx.service.impl.ThriftService2Impl"/><!-- ThriftService2.Iface接口的实现 -->
......
</beans>
需新增Servlet类.
TestThriftServlet.java
package example.ikasoa.servlet;
import com.ikasoa.core.thrift.server.CompactThriftServerConfiguration;
import com.ikasoa.core.thrift.server.ThriftServlet;
import com.ikasoa.core.thrift.server.impl.ServletThriftServerImpl;
public class TestThriftServlet extends ThriftServlet {
private static final long serialVersionUID = 1L;
private static ThriftServer server = new ServletThriftServerImpl("TestThriftServlet", new CompactThriftServerConfiguration(), new com.xxx.service.ThriftService.Processor<com.xxx.service.ThriftService.Iface>(new com.xxx.service.impl.ThriftServiceImpl()));
public TestThriftServlet() {
super(server);
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1" metadata-complete="true">
......
<servlet>
<servlet-name>TestServiceServlet</servlet-name>
<servlet-class>example.ikasoa.servlet.TestServiceServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>TestServiceServlet</servlet-name>
<url-pattern>/TestService</url-pattern>
</servlet-mapping>
......
</web-app>
修改完毕后需要启动Servlet容器.
......
// Servlet访问地址根据容器的配置而定,协议类型需于服务端一致(例如服务端使用CompactThriftServerConfiguration,客户端则必须使用CompactThriftClientConfiguration).
ThriftClient thriftClient = new HttpThriftClientImpl("http://localhost:8080/TestService", new CompactThriftClientConfiguration());
TTransport transport = thriftClient.getTransport();
transport.open();
// 这里的client对象就是ThriftService的实例,获取后可以直接操作.
com.xxx.service.ThriftService.Client client = new com.xxx.service.ThriftService.Client(thriftClient.getProtocol(transport));
......
transport.close();
......
ikasoa默认使用Thrift作为服务类型的实现,但也提供了Netty以供选择.
......
IkasoaFactory ikasoaFactory = new DefaultIkasoaFactory();
......
......
IkasoaFactory ikasoaFactory = new NettyIkasoaFactory();
......
ikasoa服务端默认使用的是阻塞式IO,在高并发场景中建议改为非阻塞式IO方式.
......
Configurator configurator = new Configurator();
configurator.setNonBlockingIO(true);
IkasoaFactory ikasoaFactory = new DefaultIkasoaFactory(configurator);
......
ikasoa提供了3种负载均衡方式,分别为轮循(含权重),随机和一致性hash.
ikasoa-rpc支持其中2种,分别为轮循和随机,默认使用轮循.
......
XService xs = new DefaultIkasoaFactory().getIkasoaClient(XService.class, serverInfoList);
// 也可以写为如下方式:
// Class loadBalanceClass = Class.forName("com.ikasoa.core.loadbalance.impl.PollingLoadBalanceImpl");
// XService xs = new DefaultIkasoaFactory().getIkasoaClient(XService.class, serverInfoList, loadBalanceClass);
......
serverInfoList中的元素对象com.ikasoa.core.loadbalance.ServerInfo
定义了单个服务信息,其中weightNumber
属性为权重值,用于轮循负载均衡.
......
Class loadBalanceClass = Class.forName("com.ikasoa.core.loadbalance.impl.RandomLoadBalanceImpl");
XService xs = new DefaultIkasoaFactory().getIkasoaClient(XService.class, serverInfoList, loadBalanceClass);
......
创建自定义序列化类(例如com.xxx.XLoadBalanceImpl).
自定义序列化类(com.xxx.XLoadBalanceImpl)需实现接口com.ikasoa.core.loadbalance.LoadBalance
.
通过如下方式获取服务:
......
Class loadBalanceClass = Class.forName("com.xxx.XLoadBalanceImpl");
XService xs = new DefaultIkasoaFactory().getIkasoaClient(XService.class, serverInfoList, loadBalanceClass);
......
ikasoa提供了3种序列化方式,分别为fastjson,xml,kryo,默认使用fastjson.
......
IkasoaFactory ikasoaFactory = new DefaultIkasoaFactory();
// 也可以写为如下方式:
// Class protocolHandlerClass = Class.forName("com.ikasoa.rpc.handler.impl.JsonProtocolHandlerImpl");
// IkasoaFactory ikasoaFactory = new DefaultIkasoaFactory(new Configurator(protocolHandlerClass));
......
......
Class protocolHandlerClass = Class.forName("com.ikasoa.rpc.handler.impl.XmlProtocolHandlerImpl");
IkasoaFactory ikasoaFactory = new DefaultIkasoaFactory(new Configurator(protocolHandlerClass));
......
......
Class protocolHandlerClass = Class.forName("com.ikasoa.rpc.handler.impl.KryoProtocolHandlerImpl");
IkasoaFactory ikasoaFactory = new DefaultIkasoaFactory(new Configurator(protocolHandlerClass));
......
创建自定义序列化类(例如com.xxx.XProtocolHandlerImpl).
自定义序列化类(com.xxx.XProtocolHandlerImpl)需实现接口com.ikasoa.rpc.handler.ProtocolHandler
.
通过如下方式获取IkasoaFactory:
......
Class protocolHandlerClass = Class.forName("com.xx.XProtocolHandlerImpl");
IkasoaFactory ikasoaFactory = new DefaultIkasoaFactory(new Configurator(protocolHandlerClass));
......
使用fastjson作为序列化方式时,fastjson依赖版本建议与ikasoa所依赖的版本一致.否则可能出现服务名不能匹配,无法调用服务的情况.
使用kryo作为序列化方式时,如果参数或返回值以父类(或抽象类)的形式传递,转换为子类时可能会丢失子类属性值,建议尽量以子类形式传递参数.fastjson方式非集合类参数或返回值没有问题,xml方式都没有问题.
使用fastjson作为序列化方式时,传递的Bean对象必须要有默认构造方法(建议使用类似lombok这样的工具来处理Bean对象).
使用kryo作为序列化方式时,暂不支持自定义异常对象,如果抛出自定义异常对象,异常类型不能正确识别.
部分单元测试需要启动Socket,执行单元测试时请确保相关端口可用.
ikasoa is free to use under MIT license.
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。