背景
时光荏苒,进入阿里中间件团队已经快两年时间了。这期间,有幸参与了第四届中间件性能挑战赛的题目组,筹备了以“Dubbo Mesh”为主题的初赛题;和团队一起开展了Dubbo线下meetup活动;将阿里多年双11积累的中间件基础设施最佳实践和方法论,通过阿里云的商业化产品,为广大开发者和企业提供服务。很庆幸能有这样一段难忘的经历。回想起来,能进入中间件团队,和我当初的一个Github项目还有关系。今天把该项目分享给大家。
来自中间件的邀请
2017年的时候,我带领团队对后端架构进行了微服务重构。选型时使用了Dubbo框架。得益于Dubbo的高性能,使用简单和高扩展性,微服务改造很顺利,公司的业务也越来越稳定。我对Dubbo也产生了浓厚的兴趣,希望可以更深入地了解这个优秀的RPC框架。我研究了下Dubbo的源码,自己从零开始编写了一个mini版的Dubbo。
恰好时值阿里又重启了Dubbo项目,且成为Apache的孵化项目(编写文本时已正式成为Apache项目)。Dubbo新的官网有一个“Wanted: who's using dubbo”页面,我也留下了自己的信息,来给Dubbo点个赞。其中包含了mini版Dubbo的项目地址。
其实是很随意的一个举动,没想到会发生后面的故事。一个小时后,我收到了一封邮件:
这是一封来自中间件团队Dubbo负责人的邮件。当时感觉挺意外的,也很欣喜。中间件团队一直是我认为技术和影响力都很强的团队,如果可以加入该团队,是一个很好的机会。
于是接下来就是例行的投简历,面试流程。要吐槽下阿里的面试流程,前后历时快两个月了,一共有五轮,真的是持久战呀。面试的时候,面试官问了一些关于mini Dubbo的问题。结果还不错,很侥幸的通过了面试,正式加入中间件的Dubbo团队。后来听我的老板说,当初是因为对我的mini Dubbo项目感兴趣,才有了面试邀约。
iris
mini版Dubbo的项目地址为:https://github.com/vangoleo/iris-java。我给它取名为iris。
iris是一个轻量级,微内核加插件机制,基于Java的RPC框架。提供服务注册,发现,负载均衡,支持API调用,Spring集成和Spring Boot starter使用。
有如下特性:
- 网络通信: Netty4。
- 注册中心: 可扩展,已支持etcd。
- 动态代理: byte-buddy。
- 序列化: Protobuff(Protostuff)。
- 可以脱离Spring,提供API调用。自己实现了IoC容器。
- 集成Spring,提供XML,Java配置。
- 提供Spring Boot Starter(开发该项目时,Dubbo官方还不支持Spring Boot Starter)。
- 提供SPI机制,实现微内核加插件的架构。实现可扩展,开发者可以为iris开发组件,以插件的形式集成到iris中。插件的加载使用另一个微容器框架见coco项目。该项目fork于阿里的cooma。
如何使用
iris支持以下使用方式:
- 原生API形式,不依赖Spring,非Spring项目也可以使用。
- Spring配置方式,和Spring很好的集成。
- Spring Boot配置方式,提供了一个spring boot starter,以自动配置,快速启动。
API使用
Iris核心代码不依赖Spring,可脱离Spring使用。
第一步:启动etcd注册中心
编写一个接口IHelloService
public interface IHelloService {
String hello(String name);
}
第二步:编写一个IHelloService的实现
public class HelloService implements IHelloService {
@Override
public String hello(String name){
return "Hello, " + name;
}
}
第三步:启动Server
IRegistry registry = new EtcdRegistry("http://127.0.0.1:2379");
RpcServer server = new RpcServer(registry)
.port(2017)
.exposeService(IHelloService.class,new HelloService());
server.run();
第四步:启动client
RpcClient client = new RpcClient(registry);
IHelloService helloService = client.create(IHelloService.class);
String s = helloService.hello("leo");
System.out.println(s); // hello, leo
第五步:试着停止server
因为服务没有provider,client报错找不到provider
第六步:启动server
Server启动后,会去etcd注册中心注册服务,client端马上正常工作。
Spring配置方式
第一步:编写服务提供者
服务提供者,使用自定义注解@Service来暴露服务,通过interfaceClass来指定服务的接口。该@Service注解是iris提供的,并非Spring的注解。
@Service(interfaceClass = IHelloService.class)
public class HelloService implements IHelloService {
@Override
public String hello(String name) throws Exception {
return "hello" + name;
}
}
第二步:编写服务消费者
服务使用者,通过@Reference来引用远程服务,就像使用本地的SpringBean一样。背后的SpringBean封装和Rpc调用对开发者透明。使用体验和Dubbo是一样的。
public class Baz {
@Reference(interfaceClass = IHelloService.class)
private IHelloService helloService;
public void hello(String name) throws Exception {
System.out.println(helloService.hello(name));
}
}
第三步:配置Spring Bean
配置服务提供者,本例子使用XML配置,使用Java Code配置也可以。
<bean id="registry" class="com.leibangzhu.iris.registry.EtcdRegistry">
<constructor-arg name="registryAddress" value="http://127.0.0.1:2379"></constructor-arg>
</bean>
<bean id="server" class="com.leibangzhu.iris.server.RpcServer">
<constructor-arg name="registry" ref="registry"></constructor-arg>
</bean>
<bean id="serviceAnnotationBeanPostProcessor" class="com.leibangzhu.iris.spring.ServiceAnnotationBeanPostProcessor"></bean>
<bean id="helloService" class="com.leibangzhu.iris.spring.HelloService"></bean>
第四步:配置服务消费者,本例子使用XML配置,使用Java Code配置也可以。
<bean id="registry" class="com.leibangzhu.iris.registry.EtcdRegistry">
<constructor-arg name="registryAddress" value="http://127.0.0.1:2379"></constructor-arg>
</bean>
<bean id="client" class="com.leibangzhu.iris.client.RpcClient">
<constructor-arg name="registry" ref="registry"></constructor-arg>
</bean>
<bean id="referenceAnnotationBeanPostProcessor" class="com.leibangzhu.iris.spring.ReferenceAnnotationBeanPostProcessor"></bean>
<bean id="foo" class="com.leibangzhu.iris.spring.Baz"></bean>
Spring Boot配置
使用原生的Spring配置还是有些繁琐,可以使用Spring Boot来获得更好的开发体验。
第一步:编写服务提供者
@Service(interfaceClass = IHelloService.class)
public class HelloService implements IHelloService {
@Override
public String hello(String name) throws Exception {
return "Hello, " + name + ", from com.leibangzhu.iris.springboot.HelloService";
}
}
第二步:编写服务消费者
@Component
public class Foo {
@Reference(interfaceClass = IHelloService.class)
private IHelloService helloService;
public String hello(String name) throws Exception {
return helloService.hello(name);
}
}
第三步:在application.properties文件中配置服务提供者
iris.registry.address=http://127.0.0.1:2379
iris.server.enable=true
iris.server.port=2017
iris.annotation.package=com.leibangzhu.iris.springboot
第四步:在application.properties文件中配置服务消费者
iris.registry.address=http://127.0.0.1:2379
iris.client.enable=true
使用SpringBoot时,不许再手动配置相关的spring bean,Iris提供的spring boot starter会自动配置好这些spring bean。
为什么取名iris
iris
取名于梵高的画鸢尾花。我自己比较喜欢绘画,梵高是我比较喜欢的画家,所以用梵高的鸢尾花为项目取名。
最后附上我自己的几幅画,不知道大家能不能认出来他们^_^