Eagle

概要

Eagle是一个分布式的RPC框架,支持灵活的配置,支持分布式追踪,支持KryoHessianProtobuf 等序列化协议,默认序列化使用kryo 。提供Spring 和SpringBoot插件,方便与Spring和SpringBoot集成。

特点

jmh基准测试结果

运行基准测试步骤:

  • cd eagle-benchmark
  • mvn clean install
  • cd eagle-benchmark-server/target
  • tar -zxvf eagle-benchmark-server-1.8-assembly.tar.gz
  • cd eagle-benchmark-server-1.8
  • bin/start.sh
  • cd eagle-benchmark/eagle-benchmark-client
  • 在linux上运行 sh benchmark.sh,在window上运行 benchmark.cmd
  • 注(修改benchmark.sh 中的 -t 参数修改线程数)

macOs上的结果(16g内存,2.5 GHz Intel Core i7),启动16个线程。

Image text

linux上的结果(64g内存,24核),启动80个线程。

Image text

例子

内置zookeeper,仅测试使用。生产环境请更换真实zookeeper地址,使用内置zookeeper有可能会报连接警告或者异常,更换真实zk地址即可。运行要求:

添加依赖

如果是spring,添加如下:

    <dependency>
        <groupId>org.jfaster.eagle</groupId>
        <artifactId>eagle-core</artifactId>
        <version>1.8</version>
    </dependency>
    <dependency>
        <groupId>org.jfaster.eagle</groupId>
        <artifactId>eagle-registry-zookeeper</artifactId>
        <version>1.8</version>
    </dependency>
    <dependency>
        <groupId>org.jfaster.eagle</groupId>
        <artifactId>eagle-transport-netty</artifactId>
        <version>1.8</version>
    </dependency>
    <dependency>
        <groupId>org.jfaster.eagle</groupId>
        <artifactId>eagle-spring-support</artifactId>
        <version>1.8</version>
    </dependency>

如果是springBoot,添加如下:

   <dependency>
       <groupId>org.jfaster.eagle</groupId>
       <artifactId>eagle-core</artifactId>
       <version>1.8</version>
   </dependency>
   <dependency>
       <groupId>org.jfaster.eagle</groupId>
       <artifactId>eagle-registry-zookeeper</artifactId>
       <version>1.8</version>
   </dependency>
   <dependency>
       <groupId>org.jfaster.eagle</groupId>
       <artifactId>eagle-transport-netty</artifactId>
       <version>1.8</version>
   </dependency>
   <dependency>
     <groupId>org.jfaster.eagle</groupId>
     <artifactId>spring-boot-starter-eagle</artifactId>
     <version>1.8</version>
   </dependency>

分布式调用追踪

在应用中一个接口通常会涉及到一系列服务的rpc调用,由于服务分布式部署导致出现问题排查相对困难。eagle框架在一次调用中生成的traceId是相同的,只要通过ELK等日志搜集系统把日志集中处理,那么输入traceId就可以获取整个链路的调用过程。
          C
         /    
例如 A - B   A调用B,B又调用C和D,那么在一次调用中,可以通过traceId,把整个调用串联起来。traceId是根据ip+进程号+时间戳+计数,生成的全局唯一id,如果框架内部获取的ip不准确可以通过,如-Dhost=10.110.69.17指定。
         \
          D
在业务代码中,当打印日志的时候,可以通过TraceContex.getOpaque()方法获取当前调用链中的traceId。打印出traceId,logger.info(TraceContex.getOpaque() + "xxxxxx")。这样就可以根据日志追踪整个调用过程。
更简单的方式是使用eagle框架提供的日志组件,配置如下:

logback的配置

分布式追踪在程序中的应用

src/main/java/eagle/jfaster/org/controller/TraceController.java

    package eagle.jfaster.org.controller;

    import eagle.jfaster.org.config.annotation.Refer;
    import eagle.jfaster.org.service.Calculate;
    import eagle.jfaster.org.service.Hello;
    import eagle.jfaster.org.trace.annotation.Trace;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;

    /**
     * Created by fangyanpeng on 2017/12/16.
     */
    @RestController
    @RequestMapping("/")
    public class TraceController {

        private static final Logger logger = LoggerFactory.getLogger(TraceController.class);

        @Refer(baseRefer = "baseRefer")
        private Calculate calculate;

        @Refer(baseRefer = "baseRefer")
        private Hello hello;

        @Trace
        @RequestMapping("/cal")
        public String cal(@RequestParam int a, @RequestParam int b,@RequestParam int code){
            //log会打印出TraceId
            logger.info(hello.hello(code));
            int res = calculate.add(a, b);
            logger.info("calculate {}",res);
            return String.valueOf(res);
        }
    }

同步调用

  1. 创建一个接口类。

    src/main/java/eagle/jfaster/org/service/Calculate.java

    package eagle.jfaster.org.service;
    
    public interface Calculate {
    
        int add(int a,int b);
    
        int sub(int a,int b);
    }
    
  2. 实现接口,并暴露服务。

    src/main/java/eagle/jfaster/org/service/impl/CalculateImpl.java

    package eagle.jfaster.org.service.impl;
    
    import eagle.jfaster.org.service.Calculate;
    import org.springframework.stereotype.Service;
    
    @Service("calculate")
    public class CalculateImpl implements Calculate {
    
        public int add(int a, int b) {
            return a+b;
        }
    
        public int sub(int a, int b) {
            return a-b;
        }
    }
    

    src/main/resources/server.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"
           xmlns:eagle="http://eagle.jfaster.org/schema/eagle"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context
                            http://www.springframework.org/schema/context/spring-context.xsd
                            http://eagle.jfaster.org/schema/eagle
                            http://eagle.jfaster.org/schema/eagle/eagle.xsd
                            ">
    
        <context:component-scan base-package="eagle.jfaster.org" />
        <context:annotation-config/>
    
        <!--注册中心配置可以多个-->
        <eagle:registry name="regCenter" protocol="zookeeper"  address="127.0.0.1:4181" namespace="eagle" base-sleep-time-milliseconds="1000" max-sleep-time-milliseconds="3000" max-retries="3"/>
        <!--协议配置-->
        <eagle:protocol id="proto" name="eagle" serialization="kryo" use-default="true" max-content-length="16777216" max-server-connection="20000" core-worker-thread="20" max-worker-thread="200" worker-queue-size="10"/>
        <eagle:base-service id="baseService" group="eagleGroup" export="proto:9200" registry="regCenter"/>
        <eagle:service interface="eagle.jfaster.org.service.Calculate" ref="calculate" base-service="baseService" export="proto:9300,proto:9400" service-type="cglib"/>

    src/main/java/eagle/jfaster/org/Server.java

    
    package eagle.jfaster.org.server;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import java.util.concurrent.CountDownLatch;
    
    public class Server {
        public static void main(String[] args) throws InterruptedException {
            //启动Curator框架提供的内置zookeeper 仅供测试使用,生产环境请使用真实zookeeper地址
            EmbedZookeeperServer.start(4181);
            ApplicationContext appCtx = new ClassPathXmlApplicationContext("server.xml");
            CountDownLatch latch = new CountDownLatch(1);
            latch.await();
        }
    }
    

    执行main方法,就会在9300和9400端口发布服务。同时eagle还提供了eagle.jfaster.org.container.Main类,会跟据环境变量eagle.container的设置启动不同的容器。 如果没有配置会默认启动SpringContainer,会加载classpath:META-INF/spring/.xml的所有spring配置文件。

  3. 创建和启动客户端

    src/main/resources/client_sync.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"
        xmlns:eagle="http://eagle.jfaster.org/schema/eagle"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context
                            http://www.springframework.org/schema/context/spring-context.xsd
                            http://eagle.jfaster.org/schema/eagle
                            http://eagle.jfaster.org/schema/eagle/eagle.xsd
                            ">
    
        <context:component-scan base-package="eagle.jfaster.org" />
        <context:annotation-config/>
        <!--注册中心配置可以多个-->
        <eagle:registry name="regCenter" protocol="zookeeper"  address="127.0.0.1:4181" namespace="eagle" base-sleep-time-milliseconds="1000" max-sleep-time-milliseconds="3000" max-retries="3"/>
        <!--协议配置-->
        <eagle:protocol name="eagle" serialization="kryo" use-default="true" cluster="eagle" max-content-length="16777216"/>
        <eagle:base-refer id="baseRefer" request-timeout="300" actives="20000" actives-wait="300" loadbalance="roundrobin" ha-strategy="failfast" protocol="eagle" registry="regCenter" compress="false" group="eagleGroup" connect-timeout="10000"/>
        <eagle:refer id="cal" interface="eagle.jfaster.org.service.Calculate" base-refer="baseRefer" max-invoke-error="10" max-client-connection="200" />
    

    src/main/java/eagle/jfaster/org/client/SyncClient.java

    package eagle.jfaster.org.client;
    
    import eagle.jfaster.org.service.Calculate;
    import eagle.jfaster.org.service.HelloWorld;
    import eagle.jfaster.org.service.Notify;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class SyncClient {
        public static void main(String[] args) {
            ApplicationContext appCtx = new ClassPathXmlApplicationContext("client_sync.xml");
            Calculate calculate = appCtx.getBean("cal",Calculate.class);
            System.out.println(calculate.add(1,3));
            System.out.println(calculate.sub(8,3));
        }
    }
    

    执行main方法,就会在控制台打印出信息。

异步调用

  1. 异步调用只需在客户端注册一个MethodInvokeCallBack即可,服务端不用改动,在回调实例中可以引用任意spring容器中的实例。

    src/main/java/eagle/jfaster/org/callback/CalculateCallBack.java

    package eagle.jfaster.org.callback;
    
    import eagle.jfaster.org.rpc.MethodInvokeCallBack;
    import javax.annotation.Resource;
    public class CalculateCallBack implements MethodInvokeCallBack<Integer> {
    
        @Resource
        CalculateDao calculateDao;
    
        public void onSuccess(Integer response) {
            calculateDao.insert(response);
            System.out.println("calculate res:"+response);
        }
    
        public void onFail(Exception e) {
            e.printStackTrace();
        }
    }
    

    src/main/java/eagle/jfaster/org/callback/CalculateDao.java

    package eagle.jfaster.org.callback;
    
    import org.springframework.stereotype.Service;
    
    @Service("calculateDao")
    public class CalculateDao {
        void insert(Integer i){
            System.out.println("-----------insert--------"+i);
        }
    }
    
  2. 创建和启动客户端。

    src/main/resources/client_async.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"
           xmlns:eagle="http://eagle.jfaster.org/schema/eagle"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context
                            http://www.springframework.org/schema/context/spring-context.xsd
                            http://eagle.jfaster.org/schema/eagle
                            http://eagle.jfaster.org/schema/eagle/eagle.xsd
                            ">
    
        <context:component-scan base-package="eagle.jfaster.org" />
        <context:annotation-config/>
        <!--注册中心配置可以多个-->
        <eagle:registry name="regCenter" protocol="zookeeper"  address="127.0.0.1:4181" namespace="eagle" base-sleep-time-milliseconds="1000" max-sleep-time-milliseconds="3000" max-retries="3"/>
        <!--协议配置-->
        <eagle:protocol name="eagle" serialization="kryo" use-default="true" cluster="eagle" max-content-length="80000000" />
        <eagle:base-refer id="baseReferAsync" request-timeout="300" actives="20000" actives-wait="3000" loadbalance="roundrobin" ha-strategy="failfast" protocol="eagle" registry="regCenter" compress="false" group="eagleGroup" connect-timeout="10000"/>
        <eagle:refer id="calAsync" callback="eagle.jfaster.org.callback.CalculateCallBack" interface="eagle.jfaster.org.service.Calculate" base-refer="baseReferAsync" max-invoke-error="10" max-client-connection="200" />
    
    </beans>

    src/main/java/eagle/jfaster/org/client/AsyncClient.java

    
    package eagle.jfaster.org.client;
    
    import eagle.jfaster.org.service.Calculate;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import java.util.concurrent.TimeUnit;
    public class AsyncClient {
       public static void main(String[] args) throws InterruptedException {
           ApplicationContext appCtx = new ClassPathXmlApplicationContext("client_async.xml");
           Calculate calculate = appCtx.getBean("calAsync",Calculate.class);
           calculate.add(1,3);
           calculate.sub(34,9);
           //等待异步结果
           while (true) {
               TimeUnit.SECONDS.sleep(5);
           }
       }
    }

    运行结果如果成功会调用MethodInvokeCallBack的onSuccess方法,否则会调用onFail方法。不要使用异步客户端返回的值,那是不正确的,正确的值通过回调的onSuccess方法获取。

注解的方式

  1. 创建接口

    src/main/java/eagle/jfaster/org/service/Hello.java

    
    package eagle.jfaster.org.service;
    
    public interface Hello {
        String hello();
    }
    
  2. 实现接口,并打上Service注解。

    src/main/java/eagle/jfaster/org/anno/HelloImpl.java

    package eagle.jfaster.org.anno;
    
    import eagle.jfaster.org.config.annotation.Service;
    import eagle.jfaster.org.service.Hello;
    
    @Service(baseService = "baseService",export = "proto:28000", serviceType = "cglib")
    public class HelloImpl implements Hello {
    
        public String hello() {
            return "hello eagle";
        }
    }
    
  3. 创建和启动服务端。

    src/main/resources/server_annotation.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"
           xmlns:eagle="http://eagle.jfaster.org/schema/eagle"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context
                            http://www.springframework.org/schema/context/spring-context.xsd
                            http://eagle.jfaster.org/schema/eagle
                            http://eagle.jfaster.org/schema/eagle/eagle.xsd
                            ">
    
        <context:component-scan base-package="eagle.jfaster.org.anno" />
    
        <context:annotation-config/>
    
        <!--注册中心配置可以多个-->
        <eagle:registry name="regCenter" protocol="zookeeper"  address="127.0.0.1:4181" namespace="eagle" base-sleep-time-milliseconds="1000" max-sleep-time-milliseconds="3000" max-retries="3"/>
    
        <!--协议配置-->
        <eagle:protocol id="proto" name="eagle" serialization="kryo" use-default="true" max-content-length="16777216" max-server-connection="20000" core-worker-thread="20" max-worker-thread="200" worker-queue-size="10"/>
    
        <eagle:base-service id="baseService" group="eagleGroup" export="proto1:9200" registry="regCenter"/>
    
        <eagle:component-scan base-package="eagle.jfaster.org.anno"/>
    

    src/main/java/eagle/jfaster/org/server/ServerAnnotation.java

    package eagle.jfaster.org.server;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import java.util.concurrent.CountDownLatch;
    public class ServerAnnotation {
    
        public static void main(String[] args) throws InterruptedException {
            //启动Curator框架提供的内置zookeeper 仅供测试使用,生产环境请使用真实zookeeper地址         
            EmbedZookeeperServer.start(4181);
            ApplicationContext appCtx = new ClassPathXmlApplicationContext("server_annotation.xml");
            CountDownLatch latch = new CountDownLatch(1);
            latch.await();
        }
    }
    
  4. 创建和启动客户端。

    src/main/resources/client_annotation.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"
        xmlns:eagle="http://eagle.jfaster.org/schema/eagle"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd 
                            http://www.springframework.org/schema/context 
                            http://www.springframework.org/schema/context/spring-context.xsd 
                            http://eagle.jfaster.org/schema/eagle
                            http://eagle.jfaster.org/schema/eagle/eagle.xsd
                            ">
    
        <context:component-scan base-package="eagle.jfaster.org.client" />
    
        <context:annotation-config/>
    
        <!--注册中心配置可以多个-->
        <eagle:registry name="regCenter" protocol="zookeeper"  address="127.0.0.1:4181" namespace="eagle" base-sleep-time-milliseconds="1000" max-sleep-time-milliseconds="3000" max-retries="3"/>
    
        <!--协议配置-->
        <eagle:protocol name="eagle" serialization="kryo" use-default="true" cluster="eagle" max-content-length="16777216"/>
    
        <eagle:base-refer id="baseRefer" request-timeout="300" actives="20000" actives-wait="300" loadbalance="roundrobin" ha-strategy="failfast" protocol="eagle" registry="regCenter" compress="false" group="eagleGroup" connect-timeout="10000"/>
    
        <eagle:component-scan base-package="eagle.jfaster.org.client"/>
    
    </beans>

    src/main/java/eagle/jfaster/org/client/AnnotationClient.java

    package eagle.jfaster.org.client;
    
    import eagle.jfaster.org.config.annotation.Refer;
    import eagle.jfaster.org.service.Hello;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.springframework.stereotype.Service;
    
    /**
    * Created by fangyanpeng on 2017/8/18.
    */
    @Service
    public class AnnotationClient {
    
       @Refer(baseRefer = "baseRefer")
       private Hello hello;
    
       public static void main(String[] args) {
           ClassPathXmlApplicationContext appCtx = new ClassPathXmlApplicationContext("client_annotation.xml");
           appCtx.start();
           AnnotationClient client = appCtx.getBean(AnnotationClient.class);
           System.out.println(client.hello.hello());
       }
    }
    

    注解的方式同样支持同步调用和异步调用两种方式,只要在Refer注解里指定callback属性为MethodInvokeCallBack实现的全限定性名即可。Refer和Service注解里的属性与xml配置的属性一一对应。

SpringBoot例子

  1. 配置yml或properties文件,配置一个即可。

    src/main/resources/application.yml

    eagle:
      #扫描eagle服务,多个包用逗号分隔
      base-package: eagle.jfaster.org
    
      #注册中心配置,可以配置多个
      registry:
        - name: regCenter
          protocol: zookeeper
          address: 127.0.0.1:4181
          namespace: eagle
          base-sleep-time-milliseconds: 1000
          max-sleep-time-milliseconds: 3000
          max-retries: 3
    
      #协议配置,可以配置多个
      protocol:
        - id: proto
          name: eagle
          serialization: kryo
          use-default: true
          max-content-length: 16777216
          max-server-connection: 20000
          core-worker-thread: 20
          max-worker-thread: 400
          worker-queue-size: 10
          cluster: eagle
    
      #baseRefer配置,可以配置多个
      base-refer:
        - id: baseRefer
          request-timeout: 300
          actives: 20000
          actives-wait: 300
          loadbalance: roundrobin
          ha-strategy: failfast
          compress: false
          group: eagleGroup
          connect-timeout: 10000
          protocol: proto
          registry: regCenter
    
      #baseService配置,可以配置多个
      base-service:
        - id: baseService
          group: eagleGroup
          export: proto:9200
          registry: regCenter

    src/main/resources/application.properties

      #扫描eagle服务,多个包用逗号分隔
      eagle.base-package=eagle.jfaster.org
    
      #注册中心配置,可以配置多个
      eagle.registry[0].name=regCenter
      eagle.registry[0].protocol=zookeeper
      eagle.registry[0].address=127.0.0.1:4181
      eagle.registry[0].namespace=eagle
      eagle.registry[0].base-sleep-time-milliseconds=1000
      eagle.registry[0].max-sleep-time-milliseconds=3000
      eagle.registry[0].max-retries=3
    
      #协议配置,可以配置多个
      eagle.protocol[0].id=proto
      eagle.protocol[0].name=eagle
      eagle.protocol[0].serialization=kryo
      eagle.protocol[0].use-default=true
      eagle.protocol[0].max-content-length=16777216
      eagle.protocol[0].max-server-connection=20000
      eagle.protocol[0].core-worker-thread=20
      eagle.protocol[0].max-worker-thread=400
      eagle.protocol[0].worker-queue-size=10
      eagle.protocol[0].cluster=eagle
    
      #baseRefer配置,可以配置多个
      eagle.base-refer[0].id=baseRefer
      eagle.base-refer[0].request-timeout=300
      eagle.base-refer[0].actives=20000
      eagle.base-refer[0].actives-wait=300
      eagle.base-refer[0].loadbalance=roundrobin
      eagle.base-refer[0].ha-strategy=failfast
      eagle.base-refer[0].compress=false
      eagle.base-refer[0].group=eagleGroup
      eagle.base-refer[0].connect-timeout=10000
      eagle.base-refer[0].protocol=proto
      eagle.base-refer[0].registry=regCenter
    
      #baseService配置,可以配置多个
      eagle.base-service[0].id=baseService
      eagle.base-service[0].group=eagleGroup
      eagle.base-service[0].export=proto:9200
      eagle.base-service[0].registry=regCenter 
  2. 创建接口

    src/main/java/eagle/jfaster/org/service/Calculate.java

    
    package eagle.jfaster.org.service;
    
    /**
     * Created by fangyanpeng1 on 2017/8/9.
     */
    public interface Calculate {
    
        int add(int a, int b);
    
        int sub(int a, int b);
    }
    
  3. 实现接口,并打上Service注解。

    src/main/java/eagle/jfaster/org/service/impl/CalculateImpl.java

    package eagle.jfaster.org.service.impl;
    
    import eagle.jfaster.org.config.annotation.Service;
    import eagle.jfaster.org.service.Calculate;
    
    /**
     * Created by fangyanpeng1 on 2017/8/9.
     */
    @Service(id = "calculateService",baseService = "baseService",export = "proto:29001")
    public class CalculateImpl implements Calculate {
    
        public int add(int a, int b) {
            return a+b;
        }
    
        public int sub(int a, int b) {
            return a-b;
        }
    }
    
  4. 启动服务端和客户端

    src/main/java/eagle/jfaster/org/service/Calculator.java

        package eagle.jfaster.org.service;
    
        import eagle.jfaster.org.config.annotation.Refer;
        import org.springframework.stereotype.Service;
    
        /**
         * Created by fangyanpeng on 2017/10/24.
         */
        @Service
        public class Calculator {
    
            @Refer(baseRefer = "baseRefer")
            public Calculate calculate;
    
        }

    src/main/java/eagle/jfaster/org/SpringBootSartup.java

        package eagle.jfaster.org;
    
        import eagle.jfaster.org.service.Calculator;
        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        import org.springframework.context.ApplicationContext;
    
        import java.util.concurrent.TimeUnit;
    
        /**
         * Created by fangyanpeng1 on 2017/8/11.
         */
        @SpringBootApplication
        public class SpringBootSartup {
    
            public static void main(String[] args) throws InterruptedException {
                //启动Curator框架提供的内置zookeeper 仅供测试使用,生产环境请使用真实zookeeper地址
                EmbedZookeeperServer.start(4181);
                ApplicationContext ctx =  SpringApplication.run(SpringBootSartup.class, args);
                TimeUnit.SECONDS.sleep(2);
                Calculator calculator = ctx.getBean(Calculator.class);
                System.out.println(calculator.calculate.add(1,2));
                System.out.println(calculator.calculate.sub(9,5));
            }
        }

    SpringBoot方式同样支持同步调用和异步调用两种方式,只要在Refer注解里指定callback属性为MethodInvokeCallBack实现的全限定性名即可。Refer和Service注解里的属性与xml配置的属性一一对应。 注意此例子中,由于Refer和Service在同一个工程,所以运行main方法Refer和Service就都启动了,实际生产环境中一般都是服务的调用和服务的实现部署在不同的进程中。

拦截器的使用

调用端和服务端都可以使用,以记录方法的远程调用执行时间为例。通过CurrentExecutionContext可以在拦截器的各个方法之间传递参数。 异步调用由于方法调用立即返回,真正的处理逻辑在回调函数中,所以onAfter方法会在结果返回之后,回调方法调用之前执行。onBefore方法在执行调用之前执行,onAfter 方法会在调用方法之后执行,onError方法在发生异常时执行。

实现ExecutionInterceptor接口

src/main/java/eagle/jfaster/org/interceptor/ClientInterceptor.java

    package eagle.jfaster.org.interceptor;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Service;

    import eagle.jfaster.org.interceptor.context.CurrentExecutionContext;

    /**
     * Created by fangyanpeng1 on 2018/3/31.
     */
    @Service("clientInterceptor")
    public class ClientInterceptor implements ExecutionInterceptor {

        private static final Logger logger = LoggerFactory.getLogger(ClientInterceptor.class);

        @Override
        public void onBefore(String interfaceName, String method, Object[] args) {
            logger.info("{}.{} start....", interfaceName, method);
            CurrentExecutionContext.setVariable("begin", System.nanoTime());
        }

        @Override
        public void onAfter(String interfaceName, String method, Object[] args) {
            logger.info("{}.{} end....", interfaceName, method);
            long starTime = (long) CurrentExecutionContext.getVariable("begin");
            logger.info("{}.{} spent {} ns", interfaceName, method, System.nanoTime() - starTime);
        }

        @Override
        public void onError(String interfaceName, String method, Object[] args, Throwable e) {
            logger.info("{}.{} error....", interfaceName, method, e);
            long starTime = (long) CurrentExecutionContext.getVariable("begin");
            logger.info("{}.{} spent {} ns", interfaceName, method, System.nanoTime() - starTime);
        }
    }

配置配置文件

  1. xml配置
    <eagle:refer id="calculate1" interface="eagle.jfaster.org.service.Calculate" 
                    base-refer="baseRefer1" max-invoke-error="10" max-client-connection="20"
                    interceptor="clientInterceptor"/>
  2. 如果是通过注解的方式配置,直接在注解的的属性指定即可@Refer(interceptor="clientInterceptor")或@Service(interceptor="clientInterceptor")

eagle常用配置

注册中心的配置(eagle:registry)

协议配置 (eagle:protocol)

客户端配置(eagle:refer)

服务端配置(eagle:service)

分布式追踪配置(eagle:trace)

贡献者