springboot整合dubbo设置全局唯一ID进行日志追踪

1.新建项目

在这里插入图片描述
利用idea创建一个父项目,三个子项目,其中一个项目为生产者,一个项目为消费者,一个为接口等公共服务项目,生产者和消费者需要有web依赖,可以作为tomcat容器启动。

2.项目依赖

  <dependencies>
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.7.6</version>
        </dependency>

        <!-- zk的依赖 -->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-dependencies-zookeeper</artifactId>
            <version>2.7.6</version>
            <type>pom</type>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>

3.在facade项目中新建接口

在这里插入图片描述

4.编写生产者

4.1 增加dubbo配置

server.port=8081
dubbo.registry.address=zookeeper://localhost:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
dubbo.registry.timeout=30000
dubbo.application.name=dubbo-provider-ll

4.2 编写生产者dubbo filter

public class ProviderFilter implements Filter {
    
    
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
    
    
        Object threadName= invocation.getAttachment("ThreadName");
        if(null!=threadName){
    
    
            Thread thread = Thread.currentThread();
            thread.setName(threadName.toString());
        }
        return invoker.invoke(invocation);
    }
}

注意:此处Filter 是dubbo的filter,不是servlet的filter

这里代码的目的是将从消费端传来的线程名称设置为线程名称

在resources目录下新建META-INF/dubbo/com.alibaba.dubbo.rpc.Filter 文件
即新增目录META-INF/dubbo和文件 com.alibaba.dubbo.rpc.Filter

在文件中增加,等号后面为实现dubbo filter的实现类路径
providerFilter=com.dubbo.spring.provider.filter.ProviderFilter

4.3编写dubbo生产者实现类

@Service(filter = {
    
    "providerFilter"})
public class DemoServiceImpl implements IDemoService {
    
    
    public Logger LOGGER= LoggerFactory.getLogger(DemoServiceImpl.class);
    @Override
    public String getName() {
    
    
        LOGGER.info("provider ThreadName : "+Thread.currentThread().getName());
        return "dubbo-test";
    }
}

5.编写消费者

5.1编写消费者filter

public class DubboFilter implements Filter {
    
    
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
    
    
        String name = Thread.currentThread().getName();
        invocation.setAttachment("ThreadName",name);
        return  invoker.invoke(invocation);
    }
}

此处是将线程名称放入到attachment中,attachment底层是hashmap,后续使用dubbo请求生产者时,会把attachment给到生产者,故在生产中中可以通过key ThreadName来获取消费者端的线程名称
在resources目录下新建META-INF/dubbo/com.alibaba.dubbo.rpc.Filter 文件
即新增目录META-INF/dubbo和文件 com.alibaba.dubbo.rpc.Filter

在文件中增加,等号后面为实现dubbo filter的实现类路径
consumerFilter=com.dubbo.spring.consumer.filter.DubboFilter

5.2 编写response对象

public class Response implements Serializable {
    
    

    private static final long serialVersionUID = -3186818832535757509L;
    private String code;

    private String message;

    private Object result;

    private String index;

    public String getCode() {
    
    
        return code;
    }

    public void setCode(String code) {
    
    
        this.code = code;
    }

    public String getMessage() {
    
    
        return message;
    }

    public void setMessage(String message) {
    
    
        this.message = message;
    }

    public Object getResult() {
    
    
        return result;
    }

    public void setResult(Object result) {
    
    
        this.result = result;
    }

    public String getIndex() {
    
    
        return index;
    }

    public void setIndex(String index) {
    
    
        this.index = index;
    }
}

此response为web端返回到页面统一对象

5.3 编写aop切面

@Aspect
@Component
public class AopContext {
    
    

    @Before("execution(* com.dubbo.spring..*.*(..))")
    public void before(){
    
    
        Thread thread = Thread.currentThread();
        thread.setName(UUIDUtil.getUUID());
    }
    @Around("execution(* com.dubbo.spring..*.*(..))")
    public Object around(ProceedingJoinPoint pjp){
    
    
        Response response=new Response();
        try {
    
    
            Object proceed = pjp.proceed();
            if(proceed instanceof Response){
    
    
                 response=(Response) proceed;
                response.setIndex(Thread.currentThread().getName());
            }
        } catch (Throwable throwable) {
    
    
            throwable.printStackTrace();
        }
        return response;
    }
}

1.before是在请求进入时给线程设置名称,为随机生成的uuid
2.around是环绕通知,在执行完之后,在返回的结果中将线程名称设置进去,便于以后异常追踪

5.4 编写web

@RestController
public class WebController {
    
    

    private Logger LOGGER= LoggerFactory.getLogger(WebController.class);

    @Reference(filter = {
    
    "consumerFilter"})
    private IDemoService iDemoService;

    @GetMapping("/getName")
    public Response getName(){
    
    
        LOGGER.info("consumer ThreadName : "+Thread.currentThread().getName());
        String name = iDemoService.getName();
        Response response=new Response();
        response.setResult(name);
        response.setCode("1001");
        response.setMessage("success");
        return response;
    }
}

请求结果

在这里插入图片描述
此处为postman响应的,index 为1ca55cb7a17148879923265b89102ccf

生产者线程名称:
在这里插入图片描述
消费者线程名称:
在这里插入图片描述
可以看到从web页面到生产者,消费者,都有一个全局唯一id进行贯穿,如果在web页面提示有异常时,可以通过这个uuid进行日志追踪

猜你喜欢

转载自blog.csdn.net/weixin_39427718/article/details/109291787