废话暂且不提,直接开始:
应用场景:
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, 大家来找茬。
相关推荐
INT:中间代码,当一个源程序经过语法检查后编译产生一个可执行代码 IOF:Findit文档 IQY:Microsoft Internet查询文件 ISO:根据ISD 9660有关CD-ROM文件系统标准列出CD-ROM上的文件 ISP:X-Internet签字文件 ...
采用多线程方式对指定IP地址段(或单机)进行安全漏洞检测,支持插件功能,提供了图形界面和命令行两种操作方式,扫描内容包括:远程服务类型、操作系统类型及版本,各种弱口令漏洞、后门、应用服务漏洞、网络设备漏洞...
采用多线程方式对指定IP地址段(或单机)进行安全漏洞检测,支持插件功能,提供了图形界面和命令行两种操作方式,扫描内容包括:远程服务类型、操作系统类型及版本,各种弱口令漏洞、后门、应用服务漏洞、网络设备漏洞...
通过以上内容,我们可以看到性能测试不仅仅是技术层面的考量,更是对产品品质和服务水平的一种保障。对于那些想要进入这一领域的专业人士而言,积极面对挑战、不断学习新知识是必不可少的态度。
I already have a great idea about how to do that.(我已经有了一个好主意)。Let me know if you need my help.(如果需要我的帮助,请告诉我)。Bring Ms. Steen to the party without telling her so that she ...
扫描内容包括:远程服务类型、操作系统类型及版本,各种弱口令漏洞、后门、应用服务漏洞、网络设备漏洞、拒绝服务漏洞等二十几个大类。对于多数已知漏洞,我们给出了相应的漏洞描述、解决方案及详细描述链接,其它...
务类型、操作系统类型及版本,各种弱口令漏洞、后门、应用服务漏洞、网络设备漏洞、拒绝服务漏洞等 二十几个大类。对于多数已知漏洞,我们给出了相应的漏洞描述、解决方案及详细描述链接,其它漏洞资 料正在进一步...
49. **文章筛选**:长篇文章,先判断立场,同意且已清楚的不必读,不同意则关注第一个论据。 50. **找到最佳学习方式**:了解自己吸收信息的最佳环境和方式,如静谧、音乐或朗读。 这些方法旨在帮助学生优化学习...
奥美基础知识训练管理.pptx 是一份关于奥美公司(Ogilvy & Mather)针对初级员工的基础训练材料,主要涵盖了品牌管理和...通过这样的系统培训,员工可以全面理解品牌建设和有效沟通的重要性,从而更好地服务于客户。
- **提升沟通技巧**:建立有效的沟通机制,以便更好地了解队员的需求和想法,同时也能更好地指导和激励他们。 - **强化安全意识**:定期组织训练,提高队员的安全意识和应对突发事件的能力。 - **严格门岗管理**:对...
【标题】43种方法简化你的生活.doc 【描述】这份文档列举了43个实用技巧,...这些方法旨在帮助我们创建一个更有序、更高效、更轻松的生活方式,通过简化生活,我们可以更好地管理时间,减少压力,享受生活中的每一刻。
- 预先准备好谈话要点; - 尽量用最少的时间表达最关键的信息; - 选择上级较为轻松的时间段进行沟通。 **初入职场太过粗心,什么都做不好,该如何去改变和提升自己?** - **关键点:**建立检查清单、注重细节、...
- **实习的重要性:** 实习提供了一个接触真实工作环境的机会,它可以帮助学生更好地了解自己的兴趣所在以及职场的基本运作模式。通过实习,可以建立起初步的职业网络,并学习如何在团队中发挥作用。 - **实习成功的...
- **解释**:回避焦虑型人格障碍是一种以过分敏感和担心被拒绝为特征的心理障碍。 - **知识点扩展**: - **特征**:过度依赖他人的认可、避免社交场合。 - **治疗**:认知行为疗法、心理动力学治疗等。 4. **...
6. “一个学生在社交媒体上抨击教授”可以用“A student criticized a professor on social media”来表述。 7. “如果营地的空气质量好”可以翻译为“If the air quality in your camping area is good”。 8. ...