自己编写spingcloud微服务启动工具 --纯Java实现

首先是效果图
自己编写spingcloud微服务启动工具 --纯Java实现_第1张图片
当微服务很多时,部署和管理都是一件很麻烦的事情。会打开多个控制台,实施人员水平也是参差不齐,部署的时候,容易出错导致某个服务没有成功启动,排查困难。

使用这个窗体程序,可以简化发布。只需要把所有需要部署的微服务放在一个指定的文件夹下,就可以扫描到。

设置可以配置端口和启动顺序,同一优先级的同时启动,优先级高的先启动,高优先级的启动完了,才能启动低一级的服务。这里配置的端口是用于监听服务是否正常启动的(不能影响服务的启动端口)。

左边列表显示的服务默认是黑色,启动成功后是蓝色。启动异常是红色。

因为使用端口监听判断服务是否正常启动,所以如果有端口冲突,那么启动过程中,该服务可能是蓝色的名字,但是启动完后,如果端口冲突,启动会失败,那么颜色还是会恢复成黑色,所以最终是蓝色的一定是成功启动的。

右边的消息显示的是一些系统提示。

工具栏的内存显示,每秒刷新一次。

这个程序的一个难点是多线程多进程之间的交互,启动服务的方式多样,造成一些复杂性。

另一个难点是自定义一个控制台,把原有的控制台消息显示到自定义的地方(这个是属于难者不会,会者不难)。

关于重定向控制台的消息到自定义的文本域:

首先是创建一个进程,获取它的inputstream,然后把流读取到自定义的文本域中,这里需要创建一个线程处理,不然主进程会阻塞。

Process process= getAndCreateProcessIfNull();
		started=true;
		status=ProcessStatus.RUNNABLE;
		InputStream iStream=process.getInputStream();
		
		ServiceStartSupervisor.register(this);
new Thread(()->{
	            BufferedReader br = new BufferedReader(new InputStreamReader(iStream));
	            String c =null;
	            try{  	           
	                while(started && (c = br.readLine()) != null){
						getjTextArea().append(c+"\r\n");
						if (getjTextArea().getLineCount()>100){
							int start=getjTextArea().getLineStartOffset(0);
							int end=getjTextArea().getLineEndOffset(getjTextArea().getLineCount()-70);
							getjTextArea().replaceRange("",start,end);
						}
						getjTextArea().setCaretPosition(getjTextArea().getLineEndOffset(getjTextArea().getLineCount()-1));
					}
	                
	                
	            }catch(Exception e){  
	            	this.close();
	                throw new RuntimeException(e);
	            } finally {
	            	if (BatServiceProcessDefinition.this.status==ProcessStatus.RUNNING) {
	                	BatServiceProcessDefinition.this.status=ProcessStatus.RUNNABLE;
					}else {
	            		if (started)
							BatServiceProcessDefinition.this.status=ProcessStatus.DEFATED;
						if (getCountDownLatch()!=null) {
							getCountDownLatch().countDown();
						}
					}
	                
	                ServiceStartSupervisor.unregister(this);
	                setCountDownLatch(null);
	                System.out.println("end");
				} 
	        }).start();

监听服务启动情况(在没有端口冲突的情况下有效):
先启动一个控制台进程,获取进程的outputstream,然后定时扫描,当获得返回消息时,说明端口已经监听了,服务正常启动。

端口有冲突的情况,需要使用其它方式额外校验。

一种简单的处理方式是启动前就扫描需要的所有端口,如果有冲突,直接就提示先解决冲突在启动服务。

executorService.execute(()->{
            			Process process=null;
            			try {
            				process=Runtime.getRuntime().exec("cmd");
            				map.put(service.getPort(), process);
							OutputStream os= process.getOutputStream();
							InputStream is=process.getInputStream();
							
							final AtomicBoolean continuteSearch=new AtomicBoolean(true);
							
							executorService.execute(()->{
								byte[] bs=("netstat  -ano|findstr "+service.getPort()+" \r\n").getBytes();
								while (continuteSearch.get()) {	
									try {
										os.write(bs);
										os.flush();
										Thread.sleep(2000);
									} catch (IOException e) {
										// TODO Auto-generated catch block
										e.printStackTrace();
									} catch (InterruptedException e) {
										// TODO Auto-generated catch block
										e.printStackTrace();
									}
									
								}
								
								
							});
							
							
							BufferedReader br = new BufferedReader(new InputStreamReader(is,Charset.forName("GBK")));
								 String c;
								 while ((c=br.readLine())!=null) {
				
									 if (c.contains("TCP")) {
										 continuteSearch.set(false);
										 //启动成功
										 service.setStatus(ProcessStatus.RUNNING);
										 mainWindow.changeListColor();
										 if (service.getCountDownLatch()!=null) {
												service.getCountDownLatch().countDown();
											}
										 break;
									}	
									
								}
							 map.remove(service.getPort());
						} catch (IOException e) {						
							e.printStackTrace();
						}finally {
							if (process!=null && process.isAlive()) {
								process.destroy();
							}
						}
            			
            		});

使用ServiceProcessDefinition这个类来描述一个服务进程以及相关的信息(启动命令,服务名,端口,级别)。

详细源码后续会放在git上。

使用jsmooth打包成exe后,点击即可启动。
自己编写spingcloud微服务启动工具 --纯Java实现_第2张图片

你可能感兴趣的:(其它)