Eagle分布式rpc调用,借助Zookeeper实现服务注册和发现,基于AQS实现高性能连接池,支持分布式追踪、监控、过载保护等配置。提供Spring和SpringBoot插件,方便与Spring和SpringBoot集成。
Eagle是一个分布式的RPC框架,支持灵活的配置,支持分布式追踪,支持Kryo、Hessian、Protobuf 等序列化协议,默认序列化使用kryo 。提供Spring 和SpringBoot插件,方便与Spring和SpringBoot集成。
运行基准测试步骤:
- 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个线程。
linux上的结果(64g内存,24核),启动80个线程。
内置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框架提供的日志组件,配置如下:
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="eagle.jfaster.org.trace.logback.TraceIdPatternLogbackLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%traceId] [%thread] %-5level %logger{36} -%msg%n</Pattern>
</layout>
</encoder>
</appender>
log4j.appender.CONSOLE.layout=eagle.jfaster.org.trace.log4j.TraceIdPatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d [%T] %-5p %c{1}:%L - %m%n
<eagle:trace/>
配置,springboot不用添加额外配置。然后在需要追踪的类或者方法上打上@Trace注解。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);
}
}
创建一个接口类。
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);
}
实现接口,并暴露服务。
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配置文件。
创建和启动客户端
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方法,就会在控制台打印出信息。
异步调用只需在客户端注册一个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);
}
}
创建和启动客户端。
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方法获取。
创建接口
src/main/java/eagle/jfaster/org/service/Hello.java
package eagle.jfaster.org.service;
public interface Hello {
String hello();
}
实现接口,并打上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";
}
}
创建和启动服务端。
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();
}
}
创建和启动客户端。
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配置的属性一一对应。
配置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
创建接口
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);
}
实现接口,并打上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;
}
}
启动服务端和客户端
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方法在发生异常时执行。
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);
}
}
<eagle:refer id="calculate1" interface="eagle.jfaster.org.service.Calculate"
base-refer="baseRefer1" max-invoke-error="10" max-client-connection="20"
interceptor="clientInterceptor"/>
<eagle:trace/>
配置。配合@Trace注解实现追踪功能。@Trace打在类上,则这个类的所有方法被追踪。打在方法上,则只有这个方法被追踪。只需要在最外层的调用打@Trace注解即可,内层的调用会自动并入当前的调用链中。同一调用链中的日志打印会带有相同的traceId。eagle 提供可视化的后台管理,方便查看和修改配置。 启动后台的步骤
tar -zxvf eagle-ui-1.8.tar.gz
cd eagle-ui-1.8
vim conf/eagle.conf 修改用户名、密码、jvm参数、日志路径、端口号等
sh bin/eagle.sh start