背景

时光荏苒,进入阿里中间件团队已经快两年时间了。这期间,有幸参与了第四届中间件性能挑战赛的题目组,筹备了以“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的项目地址。
分享一个让我进入阿里中间件的个人项目-LMLPHP
其实是很随意的一个举动,没想到会发生后面的故事。一个小时后,我收到了一封邮件:
分享一个让我进入阿里中间件的个人项目-LMLPHP
这是一封来自中间件团队Dubbo负责人的邮件。当时感觉挺意外的,也很欣喜。中间件团队一直是我认为技术和影响力都很强的团队,如果可以加入该团队,是一个很好的机会。
分享一个让我进入阿里中间件的个人项目-LMLPHP
于是接下来就是例行的投简历,面试流程。要吐槽下阿里的面试流程,前后历时快两个月了,一共有五轮,真的是持久战呀。面试的时候,面试官问了一些关于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取名于梵高的画鸢尾花。我自己比较喜欢绘画,梵高是我比较喜欢的画家,所以用梵高的鸢尾花为项目取名。

最后附上我自己的几幅画,不知道大家能不能认出来他们^_^

分享一个让我进入阿里中间件的个人项目-LMLPHP

分享一个让我进入阿里中间件的个人项目-LMLPHP

分享一个让我进入阿里中间件的个人项目-LMLPHP

分享一个让我进入阿里中间件的个人项目-LMLPHP

11-12 11:24