`
yushl
  • 浏览: 11356 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

对系统未准备好,而拒绝服务的一个想法

 
阅读更多

废话暂且不提,直接开始:

应用场景:

       Mina + Spring 提供对外服务

需求:

      在整个系统没有准备好之前,系统对外拒绝服务,因为本系统涉及到一些初始化索引一些比较耗费时间的问题,所以即使spring启动了,但是数据没有准备好,依然不能提供服务。

刚开始的时候,使用 spring的 init-method,但是经历各种蛋疼以后,发现可行性太低,所以我就想,能不能监听spring的事件来做呢,结果有了如下想法:

public class InitData implements ApplicationListener<ContextRefreshedEvent>, ApplicationContextAware{
   
    private ApplicationContext applicationContext;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        InitDataService service =  applicationContext.getBean(InitDataService.class);
        List<ISearchService> searchServices =  service.getSearchServices();
        int serviceAmount =  searchServices.size();
        final ExecutorService exec = Executors.newFixedThreadPool(serviceAmount);
        final CountDownLatch downLatch = new CountDownLatch(serviceAmount + 1);
        final CyclicBarrier barrier =  new CyclicBarrier(serviceAmount, new ServiceReadyThread(downLatch));

        for (ISearchService iSearchService : searchServices) {
           
            Thread task = new Thread(new InitLuceneIndexThread(iSearchService, barrier, downLatch));
            exec.execute(task);
        }
        try {
            downLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }//等待所有的并发访问完
       
        exec.shutdown();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        this.applicationContext = applicationContext;
       
    }

这个是整个想法的核心,下面围绕这个核心,我来做一些解释。

首先实现了ApplicationListener<ContextRefreshedEvent>, ApplicationContextAware二个接口,一个是监听ContextRefreshedEvent事件,一个是拿到applicationContext。

 

InitDataService service =  applicationContext.getBean(InitDataService.class);

单独写出来的一个类,因为我的service类有很多,那么如果我把这些类都放到配置文件中,以后只要实现各自的方法和更改配置文件就可以了。

 

ublic class InitDataService {

    private List<ISearchService> searchServices;

    public List<ISearchService> getSearchServices() {
        return searchServices;
    }

    public void setSearchServices(List<ISearchService> searchServices) {
        this.searchServices = searchServices;
    }
}

 

<bean id="initDataService" class="com.playsnail.search.service.init.InitDataService">
        <property name="searchServices">
                <list>
                    <ref bean="各种实现了ISearchService的Service"/>
                </list>
        </property>
    </bean>

 

        int serviceAmount =  searchServices.size();
        final ExecutorService exec = Executors.newFixedThreadPool(serviceAmount);
        final CountDownLatch downLatch = new CountDownLatch(serviceAmount + 1);
        final CyclicBarrier barrier =  new CyclicBarrier(serviceAmount, new ServiceReadyThread(downLatch));

因为CyclicBarrier和CountDownLatch在定义的时候要指定需要同步的数量。所以有了        int serviceAmount =  searchServices.size();

然后建立一个线程池,建立CyclicBarrier和CountDownLatch的实例,

这里需要注意ServiceReadyThread这个参数,这个是我打开整个服务的一个标志位

public class ServiceReadyThread  implements Runnable{
    private CountDownLatch downLatch;
    public ServiceReadyThread(CountDownLatch downLatch){
        this.downLatch = downLatch;
    }

    @Override
    public void run() {
        LuceneUtil.setIndexReady(true);
        downLatch.countDown(); 
    }

}

因为这里也需要downLatch.countDown(); 所以上述的CountDownLatch的参数会 +1.

 

        for (ISearchService iSearchService : searchServices) {
           
            Thread task = new Thread(new InitLuceneIndexThread(iSearchService, barrier, downLatch));
            exec.execute(task);
        }

这个目的就是把每个service加入到一个单独的线程中执行,那么这些线程的同步就是CyclicBarrier的工作了。

 

InitLuceneIndexThread的代码public class InitLuceneIndexThread implements Runnable{
    private CyclicBarrier barrier;
    private ISearchService searchService;
    private CountDownLatch downLatch;
   
    public InitLuceneIndexThread(ISearchService searchService, CyclicBarrier barrier, CountDownLatch downLatch){
        this.searchService = searchService;
        this.barrier = barrier;
        this.downLatch = downLatch;
    }

    @Override
    public void run() {
        searchService.createIndexIfInValid();
        try {
            barrier.await();
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
             downLatch.countDown(); //放在finally中执行你懂的
        }
    }
}

 

 

try {
            downLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }//等待所有的并发访问完

 

上面的代码的意思就是等待所有的线程执行完,大家看到,这个是downLatch的事情。

执行完以后,没有以后了。。。。。

 

但是一个问题是我前面说的,这个功能是个服务提供的标识符。那怎么做的呢,

注意到ServiceReadyThread 中的 LuceneUtil.setIndexReady(true);了吗?

接下来看看这个标志符的定义

private static volatile boolean isIndexReady = false; //定义为volatile 你也懂的

get()and set()。。。。。。。

前面提过,我们的服务提供是用Mina做的,那么就在Mina的Handler里面做文章,如果isIndexReady为false

,则不让客户端建立连接。

郑重申明,该想法只是完成了代码部分,没有进行测试,让大家帮我参谋参谋有什么需要改进的地方,毕竟一个人的力量是有限的,我相信群众。Come on, Man, 大家来找茬。

分享到:
评论
1 楼 yushl 2013-09-05  
难道自己的语文功底太差,写的让人不知所云?为什么都莫有人喷呢?自己留言mark一下

相关推荐

    信息的系统安全系统集成服务流程.doc

    信息系统安全集成工作流程 目 录 1 目的 4 2 适用范围 4 3 安装调试 4 3.1 准备阶段 5 3.1.1 准备工作安排 6 3.1.2 技术支持人员要求 6 3.1.3 险点分析与控制 6 3.1.4 工具及材料准备 7 3.2 施工阶段 7 3.2.1 开工 7...

    安装系统前,需要准备好一些东西

    读懂本文需要了解安装操作系统的一些基础知识。 首先是制作一个能启动电脑的带... 先到网上去下载一个叫“老毛桃WinPE”的工具到硬盘里,再把U盘接在电脑上,然后按下面的步骤一步步来就可以制作一个能启动的U盘了。

    花型准备系统3.7T

    花型准备系统3.7T

    ARM32 架构增加一个系统调用.pdf

    系统调用在内核中都是必不可少的一部分,ARM 结构对系统调用的支持相比其他 架构有很多改进,其化繁为简,为开发者提供了一个便捷的方法添加一个新的系统 调用。这里涉及 ARM 架构的系统调用表 syscall.tbl, 以及 ...

    .net服务准备文档

    .net服务准备文档

    ArcGIS server 发布服务

    ArcGIS10.1 地图的发布和之前版本有所改变,文档对10.1发布地图进行了详细的说明,希望可以帮到你。

    解决浪潮服务Windows2003操作系统安装

    这是安装服务器操作系统的一个重要步骤。 驱动程序软盘通过一张随机驱动程序光盘(蓝海豚或睿捷导航软件光盘)或另一张RAID卡的驱动程序光盘制作。下面是蓝海豚或睿捷导航软件截图。建议在台式电脑上运行导航软件。...

    图解!用U盘安装系统的方法(老毛桃WinPEU盘版)

    一个能启动电脑的U盘和一个系统的光盘镜像在安装系统前,需要准备好一些东西。一个 是操作系统的镜像,另一个就是能启动的U盘。下面我们就来讲解怎么利用U盘启动安装 Ghost xp版的XP系统。注:读懂本文需要了解安装...

    ERP系统实施准备ERP系统实施准备.ppt

    ERP系统实施准备ERP系统实施准备

    雨林木风系统准备工具V3.6 绿色免费版(系统封装工具)

    雨林木风系统准备工具V3.6 绿色免费版(系统封装工具),这是一款非常不错的系统封装工具,很好用的。

    Windows 系统错误代码简单分析

    可能是一个包含注册表数据文件的结构已损坏,也可能内存中该文件的系统映像已损坏,或者因为备份副本(或日志)不存在(或损坏)导致无法恢复该文件。  1016 由注册表引起的 I/O 操作发生了不可恢复的错误。...

    用Java写的一个购物系统

    用Java写的一个基于EJB框架的购物系统。

    IBM服务器 Raid安装系统图文档操作 ServerGuide 8

    注意:1、使用ServerGuide光盘安装会清除硬盘上的分区和数据,如果还有要保留的数据请先备份或选择其他安装方式, 2、ServerGuide光盘并不包含操作系统程序,请客户自己准备一张正版Windows操作系统光盘。...

    ERP前期工作Checklist:ERP实施,你准备好了吗?.doc

    ERP前期工作Checklist:ERP实施,你准备好了吗?

    使用opencv,Android,Java web实现一个简单的人脸识别系统

    这个人脸识别系统的开发需要先准备好摄像头,使用OpenCV对摄像头返回的图像进行特征提取,然后使用服务器端算法对用户进行判断,最终返回结果给客户端。这个系统实现了基本的人脸识别功能,但需要注意信息安全和隐私...

    u盘装系统,建立系统

    教你怎么拥有盘装系统,怎么快速德庄系统一个能启动电脑的U盘和一个系统的光盘镜像或文件 (本人目前使用比较稳定的系统GhostXP_SP3简体中文版2010_NTFS.iso) QUFGdHA6Ly8xMTI6MTEyQDYxLjE0NS42Mi45OC9HaG9zdFhQX1...

    单道批处理系统作业调度

    本次课程设计要求用高级语言编写和调试一个单道批处理系统的作业调度的模拟程序,了解作业调度在操作系统中的作用,以加深对作业调度算法的理解 2. 课程设计的开发语言 C语言 3. 功能描述 在批处理系统中,作业进入...

    系统提示,系统的准备,报告系统用声音准备,准备问题的代码的过程

    系统提示,系统的准备,报告系统用声音准备,准备问题的代码的过程 系统提示,系统的准备,报告系统用声音准备,准备问题的代码的过程

    DCS系统检修前要准备什么

    本文给大家介绍了DOS系统检修前需要做的准备工作。

    Android系统移植技术详解

    创建一个新的Android产品项目 4 制作ubifs文件系统 7 android编译系统makefile(Android.mk)写法 10 Android系统移植(一)-让android系统在目标平台上运行起来 18 Android系统移植(二)-按键移植 20 Android系统移植(三...

Global site tag (gtag.js) - Google Analytics