资讯专栏INFORMATION COLUMN

Alogic-FrameWork源码分析-1.服务开发

LiveVideoStack / 1582人阅读

摘要:介绍是一个轻量级的服务框架,源代码位于。是的消息路由器,是具体负责每一个请求的路由过程。当执行结束后,向服务池归还资源。在多线程模式下,同样也是在服务线程中执行接口的三种方法。是一个接口,主要代表服务输出的消息实例。

1.0 Alogic-FrameWork介绍

Alogic-FrameWork是一个轻量级的Java服务框架,源代码位于Alogic-Github。具有快速开发服务的特点,在alogic-framework下,一个成熟的Java开发者可以快速的开发出实现自己业务逻辑的Restful服务。在这里我们不谈具体的开发逻辑,而是专注于分析该框架的源码。
Alogic-FrameWork的一个HelloWorld级别代码如下:Alogic的HelloWorld-Github
其中主要包括以下几个部分:

HelloWorld.java 服务调用的具体内容

web.xml web项目构建的配置文件

settings.xml Alogic服务目录配置文件

servant.xml 服务描述配置文件

1.1 服务初始化入口

服务由servlet进行拦截,servlet-class对请求进行处理,并返回响应。

在一个HelloWorld级别的应用中,一个典型的web.xml配置如下:


    MessageRouter
    MessageRouter
    com.anysoft.webloader.ServletAgent
    
        handler
        com.logicbus.backend.server.http.MessageRouterServletHandler
    
    1


    MessageRouter
    /services/*

服务通过注册ServletAgent类拦截/services/*的全部路由,其中初始化参数handler为MessageRouterServletHandler类。我们来看一下如何进行这个过程:

1.2 服务上下文的处理

ServletAgent是一个代理类,继承自HttpServlet,主要代理了Servlet的初始化、执行和销毁,其中重写了init(ServletConfig servletConfig),它通过ClassLoader类加载器加载实际处理的ServletHandler,并由ServletHandler去执行它的初始化方法。

public void init(ServletConfig servletConfig) throws ServletException {
    // 获取handler参数
    String handlerClass = servletConfig.getInitParameter("handler");
    // 获取当前Servlet的上下文
    ServletContext sc = servletConfig.getServletContext();
    // 获取当前web项目类加载器
    ClassLoader classLoader = (ClassLoader) sc.getAttribute("classLoader");
    if (classLoader != null) {
        try {
            //创建Handler实例
            handler = (ServletHandler) classLoader.loadClass(handlerClass)
                    .newInstance();
            //执行Handler的初始化方法
            handler.init(servletConfig);
        } catch (Exception e) {
            logger.error("Error occurs when creating handler:"
                    + handlerClass, e);
        }
    } else {
        logger.error("Can not find classLoader");
    }
}

ServletHandler是一个接口,重新封装了关于Servlet的init、service、destory方法;在web.xml中需要配置它的实现方法,MessageRouterServletHandler是它的具体实现类,在init实现方法中,设置了一些关键属性,如Http的编码、跨域、缓存等属性,以及获取服务id、目录、访问控制等。

在doService实现方法中,将上述初始化的一些列属性设置,达到重新封装Http请求的目的;service方法初始化Context,并将参数作为输入传入到action方法中。如下:

    // 初始化HttpContext,HttpContext是Context类的一个实现,它是一个封装后的Http请求的上下文。
    HttpContext ctx = new HttpContext(request,response,encoding,interceptMode);
    // 获取当前服务路径的id
    Path id = normalizer.normalize(ctx, request);
    MessageRouter.action(id,ctx,ac);

1.3 服务请求过程

上文提到过,MessageRouterServletHandler实现了ServletHandler接口,将Http上下文封装起来,同时将doService方法中获取得到的服务id,访问控制给MessageRouter的action方法。MessageRouter是Alogic的消息路由器,是具体负责每一个请求的路由过程。在action方法中,包括以下逻辑:

处理路由追踪

获取服务实例池

通过访问控制器分配访问优先级

从服务实例池获取实例

日志记录

首先,MessageRouter根据获取得到的服务id来获取一个服务实例池,通过资源池模式来保证服务实例的不断重复利用。资源池获取代码如下:

        // 获取服务实例池
        ServantFactory factory = servantFactory;
        // 根据服务id获取服务工厂
        pool = factory.getPool(id);        
        if (!pool.isRunning()){
            throw new ServantException("core.service_paused",
                "The Service is paused:service id:" + id);
        }

而接着,对于已经获得的资源池中根据优先级获得服务实例。在非线程模式下调用execute()方法,在多线程模式下建立服务工作线程。当执行结束后,向服务池归还资源。

        //从服务实例池中拿服务实例,并执行
        servant = pool.borrowObject(priority);
        // 判断是否获取到了服务并输出错误日志
        if (servant == null){
            logger.warn("Can not get a servant from pool in the limited time,check servant.queueTimeout variable.");
            ctx.setReturn("core.time_out", "Can not get a servant from pool in the limited time,check servant.queueTimeout variable.");
        }else{
               if (!threadMode){
                //在非线程模式下,不支持服务超时
                execute(servant,ctx);
            }else{
                // 构建CountDownLatch,用于等待服务工作线程建立。
                CountDownLatch latch = new CountDownLatch(1);
                //建立服务工作线程
                ServantWorkerThread thread = new ServantWorkerThread(servant,ctx,latch,tc != null ? tc.newChild() : null);
                thread.start();
                // 判断服务工作线程是否在指定的时间内建立完成。如果超时则取消主线程阻塞状态,并
                if (!latch.await(servant.getTimeOutValue(), TimeUnit.MILLISECONDS)){
                    ctx.setReturn("core.time_out","Time out or interrupted.");
                }
                thread = null;
            }
        }
    }catch (ServantException ex){
        ctx.setReturn(ex.getCode(), ex.getMessage());
        logger.error(ex.getCode() + ":" + ex.getMessage());
    }catch (Exception ex){
        ctx.setReturn("core.fatalerror",ex.getMessage());
        logger.error("core.fatalerror:" + ex.getMessage(),ex);
    }catch (Throwable t){
        ctx.setReturn("core.fatalerror",t.getMessage());
        logger.error("core.fatalerror:" + t.getMessage(),t);            
    }
    finally {
            ctx.setEndTime(System.currentTimeMillis());
            if (ctx != null){
                // 完成Context
                ctx.finish();
            }
            if (pool != null){
                if (servant != null){
                    // 向服务池归还资源
                    pool.returnObject(servant);        
                }
                // 服务池访问一次                
                pool.visited(ctx.getDuration(),ctx.getReturnCode());
                if (ac != null){
                    ac.accessEnd(sessionId,id, pool.getDescription(), ctx);
                }                
            }                        
            if (bizLogger != null){                
                //需要记录日志
                log(id,sessionId,pool == null ? null : pool.getDescription(),ctx);
            }
            if (tracerEnable){
                boolean ok = ctx.getReturnCode().equals("core.ok");
                Tool.end(tc, "ALOGIC", id.getPath(), ok ?"OK":"FAILED", ok ? ctx.getQueryString() : ctx.getReason(), ctx.getContentLength());
            }
        }

在非线程模式下的execute方法执行了服务调用的前置方法、执行方法和后置方法。

    protected static int execute(Servant servant,Context ctx) throws Exception {
        servant.actionBefore(ctx);
        servant.actionProcess(ctx);
        servant.actionAfter(ctx);
        return 0;
    }

在多线程模式下,同样也是在服务线程中执行Servant接口的三种方法。

    public void run(){
        TraceContext tc = null;
        if (traceCtx != null){
            tc = Tool.start(traceCtx.sn(), traceCtx.order());
        }
        boolean error = false;
        try
        {
            m_servant.actionBefore(m_ctx);
            m_servant.actionProcess(m_ctx);
            m_servant.actionAfter(m_ctx);
        }
    }
1.4 服务响应

在MessageRouter的acion方法中,服务调用的最后会调用ctx.finish(),在这个方法中调用了msg的finish方法。

    try {
            if (!isIgnore()){
                if (msg == null){
                    if (getReturnCode().equals("core.ok")){
                        response.sendError(404, "No message is found,check servant implemention.");
                    }else{
                        response.sendError(404, getReturnCode() + ":" + getReason());
                    }
                }else{
                    response.setCharacterEncoding(encoding);
                    msg.finish(this,!cometMode());
                }
            }
        }

Message是一个接口,主要代表服务输出的消息实例。在Alogic中,Message可以有XML、JSON等协议的消息实例,如输出为RawMessage时,finish方法如下:

    public void finish(Context ctx,boolean closeStream) {
        // 设置输出流
        OutputStream out = null;
        try {
            // 设置返回内容格式
            ctx.setResponseContentType(contentType);
            out = ctx.getOutputStream();
            byte [] bytes = buf.toString().getBytes(ctx.getEncoding());
            contentLength += bytes.length;
            // 将字符串写到输出流中
            Context.writeToOutpuStream(out, bytes);
            // 输出打印
            out.flush();
        }catch (Exception ex){
            logger.error("Error when writing data to outputstream",ex);
        }finally{
            if (closeStream)
            IOTools.close(out);
        }
    }

到此,一个服务的执行逻辑如下:

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67378.html

相关文章

  • 区块链技术学习指引

    摘要:引言给迷失在如何学习区块链技术的同学一个指引,区块链技术是随比特币诞生,因此要搞明白区块链技术,应该先了解下比特币。但区块链技术不单应用于比特币,还有非常多的现实应用场景,想做区块链应用开发,可进一步阅读以太坊系列。 本文始发于深入浅出区块链社区, 原文:区块链技术学习指引 原文已更新,请读者前往原文阅读 本章的文章越来越多,本文是一个索引帖,方便找到自己感兴趣的文章,你也可以使用左侧...

    Cristic 评论0 收藏0
  • Netty4.x 源码实战系列(一):ServerBootstrap 与 Bootstrap 初探

    摘要:而用于主线程池的属性都定义在中本篇只是简单介绍了一下引导类的配置属性,下一篇我将详细介绍服务端引导类的过程分析。 从Java1.4开始, Java引入了non-blocking IO,简称NIO。NIO与传统socket最大的不同就是引入了Channel和多路复用selector的概念。传统的socket是基于stream的,它是单向的,有InputStream表示read和Outpu...

    BakerJ 评论0 收藏0
  • 深入理解 WKWebView(入门篇)—— WebKit 源码调试与分析

    摘要:虽然苹果官方提供了关于的与使用说明,但这并不能满足开发者们的需求,各类复杂场景依旧让我们焦头烂额,而解决方案却不易寻找。二源码下载编译及调试之前我们首先需要获取一份苹果官方的源码。 一、前言移动互联网时代,网页依旧是内容展示的重要媒介,这离不开 WebKit 浏览内核技术的支持与发展。在 iOS 平台下开发者们...

    funnyZhang 评论0 收藏0
  • database

    摘要:它是第一个把数据分布在全球范围内的系统,并且支持外部一致性的分布式事务。目的是使得开发者阅读之后,能对项目有一个初步了解,更好的参与进入的开发中。深度探索数据库并发控制技术并发控制技术是数据库事务处理的核心技术。 存储过程高级篇 讲解了一些存储过程的高级特性,包括 cursor、schema、控制语句、事务等。 数据库索引与事务管理 本篇文章为对数据库知识的查缺补漏,从索引,事务管理,...

    csRyan 评论0 收藏0

发表评论

0条评论

LiveVideoStack

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<