[Dubbo开发]Dubbo日志插件实现(未打包)

本文需要实现的是一个Dubbo的日志插件,日志插件的原理如上图所示。

一、原理

简单的Dubbo生产者和消费者实现服务调用的原理为:

①生产者在注册中心上注册服务;

②消费者在注册中心上订阅服务;

③一旦建立了订阅,消费者和生产者将进行点对点的通信;

此时会产生一个问题:如果作为第三方需要对服务的调用过程进行日志记录(有实际生产需求),那么将失去对调用服务的控制。

于是,在Dubbo简单生产者和消费者的基础上,增加一个日志服务器(本质上也是一个Dubbo生产者),并使用Dubbo拦截器实现日志的记录功能,实现的原理为:

④消费者向生产者发送request请求之前,先由拦截器(filter)向日志服务器发送一条日志,将请求的信息,诸如接口、方法名、参数等信息记录到日志服务器上;

⑤消费者对生产者发送request请求;

⑥生产者对消费者的请求进行响应(Response),当然前提是网络连接畅通,生产者服务可以正常被调用;

⑦在消费者收到响应之后,由拦截器(filter)再向日志服务器发送一条日志,将返回的信息,诸如返回值等信息记录到日志服务器上。

以上就是以Dubbo拦截器方式实现的日志插件的原理。

二、实现

接下来是具体的实现过程:

消费者端的文件目录结构

FilterDesc.java

package com.mohrss.service;
/*
 * Class: FilterDesc
 * Function:拦截对象
 */
public class FilterDesc {
	private String interfaceName ;//接口名
    private String methodName ;//方法名
    private Object[] args ;//参数

    public FilterDesc(){

    }

    public String getInterfaceName() {
        return interfaceName;
    }

    public void setInterfaceName(String interfaceName) {
        this.interfaceName = interfaceName;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public Object[] getArgs() {
        return args;
    }

    public void setArgs(Object[] args) {
        this.args = args;
    }
}

LogFilter.java

package com.mohrss.service;

import com.alibaba.dubbo.rpc.*;
import com.alibaba.dubbo.rpc.service.GenericService;
import com.alibaba.fastjson.JSON;
/*
 * Class:LogFilter
 * Function:日志拦截器
 */
public class LogFilter implements Filter {
	private static final FilterDesc filterReq = new FilterDesc();
	private static final FilterDesc filterRsp = new FilterDesc();
	private LogService ls = null;
	public LogFilter(){
		ls = (LogService)SpringContextUtil.getApplicationContext().getBean("testLogService");
	}

	public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
		try{
			//request部分
			filterReq.setInterfaceName(invocation.getInvoker().getInterface().getName());
			filterReq.setMethodName(invocation.getMethodName());
			filterReq.setArgs(invocation.getArguments());
			ls.printLog("Dubbo请求数据" + JSON.toJSONString(filterReq));

			Result result = invoker.invoke(invocation);

			if(GenericService.class != invoker.getInterface() && result.hasException()){
				ls.printLog("Dubbo执行异常"+result.getException().toString());

			}else{
				ls.printLog("Dubbo执行成功");

				filterRsp.setInterfaceName(invocation.getMethodName());
				filterRsp.setMethodName(invocation.getMethodName());
				filterRsp.setArgs(new Object[]{result.getValue()});
				ls.printLog("Dubbo返回数据" + JSON.toJSONString(filterRsp));
			}

			return result;
		}
		catch(RuntimeException e){
			ls.printLog("Dubbo未知异常" + RpcContext.getContext().getRemoteHost()
					+ ".service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()
					+ ", exception: " + e.getClass().getName() + ": " + e.getMessage());
			throw e;
		}
	}
}

LogService.java(由日志服务器提供的接口文件,实际中应该是打包成jar包)

package com.mohrss.service;

public interface LogService {
	public void printLog(String log);
}

ProviderService.java(由生产者提供的接口文件,实际中应该是打包成jar包)

package com.mohrss.service;

public interface ProviderService {
	public void sayHello();
	public int calc(int a, int b);
}

SpringContextUtil.java

package com.mohrss.service;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/*
 * Class: SpringContextUtil
 * Function:用于获得当前Spring上下文环境的工具类
 */
public class SpringContextUtil implements ApplicationContextAware {

	// Spring应用上下文环境
    private static ApplicationContext context;  

    /**
     * 实现ApplicationContextAware接口的回调方法。设置上下文环境
     *
     * @param applicationContext
     */
    public void setApplicationContext(ApplicationContext applicationContext) {
        SpringContextUtil.context = applicationContext;
    }  

    /**
     * @return ApplicationContext
     */
    public static ApplicationContext getApplicationContext() {
        return context;
    }  

    public static Object getBean(String name) throws BeansException {
        return context.getBean(name);
    }  

}

com.alibaba.dubbo.rpc.filter(拦截器配置文件)

logFilter=com.mohrss.service.LogFilter

dubbo-consumer.xml(消费者自己的dubbo配置文件)

<?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:dubbo="http://code.alibabatech.com/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://code.alibabatech.com/schema/dubbo
        http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">   

    <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
    <!-- <dubbo:application name="consumer" />   --> 

    <!-- 使用multicast广播注册中心暴露发现服务地址 -->
    <!-- <dubbo:registry  protocol="zookeeper" address="127.0.0.1:2181" />  -->      

    <!-- 生成远程服务代理,可以和本地bean一样使用testProviderService -->
    <!-- 对谁拦截,就给谁加filter -->
    <dubbo:reference id="testProviderService" interface="com.mohrss.service.ProviderService" filter="logFilter" async="true"/>

    <!-- 引入外部插件的配置文件 -->
	<import resource="classpath:filter.xml" />
</beans>

dubbo.properties(更加规范的配置文件,可以避免经常修改dubbo-consumer.xml文件,文件名必须叫dubbo.properties,不然会加载不到)

# Consumer application name
dubbo.application.name=consumer
# Zookeeper registry address
dubbo.registry.protocol=zookeeper
dubbo.registry.address=127.0.0.1:2181

filter.xml(插件的配置文件,因为是作为插件使用,所以单独放在filter.xml中,在dubbo-consumer.xml里用import resource引用)

<?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:dubbo="http://code.alibabatech.com/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://code.alibabatech.com/schema/dubbo
        http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
    <bean id="springContextUtil" class="com.mohrss.service.SpringContextUtil" />

    <dubbo:reference id="testLogService" interface="com.mohrss.service.LogService" />
</beans>

TestConsumerService.java

package com.mohrss.consumer;

import java.io.IOException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mohrss.service.ProviderService;
/*
 * Class: TestConsumerService
 * Function: 程序入口,访问生产者,被拦截的对象
 */
public class TestConsumerService {

    public static void main(String[] args) {
    	//读取xml配置文件
        ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext(new String[]{"dubbo-consumer.xml"});
        context.start();

        ProviderService testService = (ProviderService) context.getBean("testProviderService");
        testService.calc(1, 2);
        testService.calc(5, 6);
        testService.sayHello();
        testService.calc(7, 8);

        try {
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

生产者代码实现参考之前的博客:https://www.cnblogs.com/Vivianwang/p/9408493.html

日志服务器文件目录:

LogService.java

package com.mohrss.service;

public interface LogService {
	public void printLog(String log);
}

LogServiceImpl.java

package com.mohrss.service.impl;

import org.springframework.stereotype.Service;

import com.mohrss.service.LogService;

@Service("logService")
public class LogServiceImpl implements LogService {
	public void printLog(String log){
		System.out.println(log);
	}
}

dubbo-log.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://code.alibabatech.com/schema/dubbo
        http://code.alibabatech.com/schema/dubbo/dubbo.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd ">   

	<!--用注解方式实现bean-->
	<context:component-scan base-package="com.mohrss.service">
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
	</context:component-scan>

    <!-- 提供方应用信息,用于计算依赖关系 -->
    <dubbo:application name="logservice"  />    

    <!-- 使用zookeeper注册中心暴露服务地址  配置后spring管理-->
    <dubbo:registry address="zookeeper://127.0.0.1:2181" />     

    <!-- 用dubbo协议在20881端口暴露日志服务 -->
    <dubbo:protocol name="dubbo" port="20881" />  

    <!-- 声明需要暴露的服务接口 -->
    <dubbo:service interface="com.mohrss.service.LogService" ref="logService" />
</beans>

TestLogService.java

package com.mohrss.service;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestLogService {
	public static void main(String[] args) {
        ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext(new String[]{"dubbo-log.xml"});
        context.start();
        System.out.println("日志服务已经注册成功!");
        try {
            System.in.read();//让此程序一直跑,表示一直提供服务
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

  

注:原创博客,转载请注明。

 

原文地址:https://www.cnblogs.com/Vivianwang/p/9451006.html

时间: 2024-11-09 18:38:53

[Dubbo开发]Dubbo日志插件实现(未打包)的相关文章

dubbo开发前戏--ZooKeeper集群部署(3.4.6)

最近在开发dubbo服务的时候一直用的是公司提供的zk平台,因为使用的人太多或者没人维护老是出问题,导致dubbo服务偶尔可以调通,偶尔调不通的情况,所以花点时间自己部署一套,后面出问题还方便看日志排查. 1 下载包上传linux服务器 zookeeper-3.4.6.tar.gz 2 解压tar -zxvf zookeeper-3.4.6.tar.gz 3 进入zookeeper-3.4.6/conf目录 4 拷贝一份zoo_sample.cfg重命名为zoo.cfg (如果你用过lts这个轻

Spring Dubbo 开发笔记

第一节:概述 Spring-Dubbo 是我自己写的一个基于spring-boot和dubbo,目的是使用Spring boot的风格来使用dubbo.(即可以了解Spring boot的启动过程又可以学习一下dubbo的框架) 项目介绍: github: https://github.com/Athlizo/spring-dubbo-parent 码云: https://git.oschina.net/null_584_3382/spring-dubbo-parent 声明: 这个只是个人研究

dubbo管控台的安装记录及dubbo开发调试记录

一.dubbo管控台的安装 1.所需的环境:linux tomcat jdk duboo-admin-xx.war(下载地址:https://github.com/alibaba/dubbo) 2.安装jdk,上传tomcat并解压 3.上传dubbo管控台程序duboo-admin-xx.war到tomcat的webapps目录下 4.解压并命名为ROOT:unzip duboo-admin-xx.war -d Root 5.配置dubbo.properties dubbo.registry.

开发dubbo应用程序(一)入门demo详解

1.简介: 引用自Dubbo官方文档简介: http://dubbo.apache.org/zh-cn/docs/user/dependencies.html 随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进. 单一应用架构 当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本.此时,用于简化增删改查工作量的数据访问框架(ORM)是关键. 垂直应用架构 当访问量逐渐增大,

基于开源 Openfire 聊天服务器 - 开发Openfire聊天记录插件[转]

上一篇文章介绍到怎么在自己的Java环境中搭建openfire插件开发的环境,同时介绍到怎样一步步简单的开发openfire插件.一步步很详细的介绍到简单插件开发,带Servlet的插件的开发.带JSP页面插件的开发,以及怎么样将开发好的插件打包.部署到openfire服务器. 如果你没有看上一篇文章的话,请你还是看看.http://www.cnblogs.com/hoojo/archive/2013/03/07/2947502.html 因为这篇文章是基于上篇文章讲叙的基础上完成插件开发.而且

vs微软开发工具(插件配置文件/VS2010)

C:\Users\Administrator\Documents\Visual Studio 2010\addins <?xml version="1.0" encoding="UTF-16" standalone="no"?><Extensibility xmlns="http://schemas.microsoft.com/AutomationExtensibility"> <HostAppl

c#的日志插件NLog基本使用

本文介绍c#的日志插件NLog 安装插件 创建logger 日志级别 书写日志信息 配置 包装器 布局 安装插件 直接下载插件包 Install-Package NLog.Config 创建logger 使用LogManager创建Logger实例,最好一个类里面一个Logger实例 写法一 这种写法,记录的日志文件,显示的logger名字,是命名空间加上logger所在类的类名,如 ConsoleApp1.Program private static Logger mylogger = Log

简化网站开发:SiteMesh插件

在编写一个网站时,几乎所有的页面都会有相同的部分.比如顶部的导航栏,每个页面都是一样的,底部的版权声明,每个页面也都是一样的. 那么在编写顶部导航栏的时候,第一种方法就是直接复制导航栏的全部代码,这种方法初期开发很简单但是后期维护简直就是噩梦,要是导航栏要增加一个按钮,所有的页面都要修改,非常麻烦. 第二种方法是将顶部导航栏专门写到一个文件中,所有的页面include这个文件.这样每个页面都要写一个include语句.后期修改只要改一个文件就可以了.但是这种方法写出来的导航栏文件它不是一个完整的

[Dubbo实战]dubbo + zookeeper + spring 实战 (转)

这里最熟悉的就是spring了,项目中应用很多.dubbo是一个实现分布式的框架,zookeeper是注册中心.给我的感觉就像多对多关系的两者表,zookeeper相当于第三张表维护关系.下面通过一个小程序加深认识. 一.安装zookeeper 去官网下载zookeeper, 然后解压到目录中,我解压到了E:\zookeeper-3.3.6,在启动zookeeper之前,首先找到conf文件夹下的 zoo_sample.cfg,重新命名为zoo.cfg,网上说zookeeper启动的时候这个文件