`

openoffice 致使应用宕机处理

    博客分类:
  • java
阅读更多
openoffice是单线程的,如果并发操作,不管是通过java调用,还是命令调用,都会出问题,异常处理,可能会在openoffice服务器生成文件锁,导致命令一直执行不下去造成线程死锁;这种情况,tomcat线程被占满,tomcat默认连接数10000,等待执行队列数100,也就是服务器会接受10100个连接,服务器最多产生10100个文件句柄,所以,线程假死执行不下去,文件句柄会飙升;所以要防止应用假死,防止openoffice并发操作, 应用在负载均衡的时候,nginx必须对openoffice转换文件的请求指向同一台机器或者每个应用单独部署一个openoffice服务;同时程序里面应用的连接开启一个就行了,无需新建多个链接对象。




java版本针对openoffice单线程和可能线程假死的问题,我采取的方案有:
1、线程隔离转换文件,主线程异步关闭连接的;
2、转换接口采用jdk动态代理
3、openoffice连接采用单例。

代码如下:
转化器动态代理类:
/**
 * DocumentConverter动态代理
 * 线程隔离,openoffice文件转换操作,此步骤可能会导致宕机; 为了不影响主线程,转换过程采用线程隔离;
 * 转换文件执行超时后,通过主线程关闭连接,同时输出日志
 * @author lyq
 * @date 2020-09-16
 *
 */
public class DocumentConverterDynaProxy implements InvocationHandler {
	
	private static final Logger logger = LoggerFactory.getLogger(DocumentConverterDynaProxy.class);
	
	
	private static ThreadPoolExecutor executor = null;
	static{
		//有限队列,缓存30个请求等待,线程池默认策略,缓存超出上限报错,此配置与tomcat max-threads(100) 值有关
		BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(30);
		//初始化1个线程,最多1个线程
		executor = new ThreadPoolExecutor(1, 1, 10, TimeUnit.SECONDS, workQueue,new ThreadFactory() {
			
			@Override
			public Thread newThread(Runnable r) {
				Thread thread = new Thread(r);
				thread.setName("openoffice-convert-thread");
				return thread;
			}
		} );
	}
	private DocumentConverter documentConverter;
	
	private Integer timeoutSec = 30;//转换超时时间,单位:秒
	
	
	/**
	 * 绑定并获取代理对象
	 * @param documentConverter 转换器接口
	 * @param timeoutSec,执行转换超时时间,单位:秒
	 * @return DocumentConverter代理对象
	 * @author lyq
	 * @date 2020-09-16
	 */
	public Object bind(DocumentConverter documentConverter,Integer timeoutSec){
			this.documentConverter = documentConverter;
			
			this.timeoutSec = timeoutSec;
			Class [] clzz = {DocumentConverter.class};
			Object obj = Proxy.newProxyInstance(
	        this.documentConverter.getClass().getClassLoader(),clzz , this);
			return obj;
	}
	/**
	 * 
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		ExecCallable runner = new ExecCallable(method, args);
		Future future = null;
		 try{
//			 synchronized (executor) {
			 
				 future = executor.submit(runner);
				 return future.get(timeoutSec, TimeUnit.SECONDS);
//			}
		 }catch(TimeoutException e){
			 synchronized (runner.isExec) {
				 if(runner.isExec.get()){
					 if(OfficePatch.execExceptionCount.get()>3){
						 logger.error("openoffice执行"+timeoutSec+"秒转换超时了,请系统管理员检测openoffice服务器应用是否正常使用");
					 }else{
						 OfficePatch.execExceptionCount.incrementAndGet();
						 logger.error("openoffice执行"+timeoutSec+"秒转换超时,关闭连接。");
					 }
					 asynDisconnect();//断开连接线程才会跑下去;
				 }else{
					 runner.isExec.set(true); 
					 logger.error("openoffice 缓存中等待"+timeoutSec+"秒超时,未执行转换,当前等待队列数量:"+executor.getQueue().size());
				 }
				 throw new OpenOfficeConvertException(e);
			 }
		 }catch(RejectedExecutionException e2){
			 //abort策略,缓存超出容量,报错。
			 logger.error("openoffice 超出等待执行缓存",e2);
			 throw new OpenOfficeConvertException(e2);
		 }finally{
//			 this.conn.disconnect();
			 if(future!=null){
				 future.cancel(true);
			 }
		 }
		
	}
	
	/**
	 * 
	 * 异步关闭连接
	 * OpenOfficeConnection的disconnect跟StreamOpenOfficeDocumentConverter类的转换的
	 * 方法convertInternal会加同步锁,但是convertInternal转换过程会假死,造成线程永久不释放,
	 * 所以disconnect执行不了,通过异步关闭,避免tomcat线程被永久占用,最终造成应用崩溃。
	 * @author lyq
	 * @date 2020-09-16
	 */
	private void asynDisconnect() {
		try{
			 XComponent component = (XComponent)readSuperPrivateField( OfficePatch.getConnection(), "bridgeComponent");
			 logger.debug("disconnecting");
			 writeSuperPrivateField(OfficePatch.getConnection(),"expectingDisconnection",false);
			 component.dispose();
		 }catch(Exception e2){
			 logger.error("openoffice关闭连接失败。",e2);
		 }
	}
	
	private static Object readSuperPrivateField(Object target,String filedname) {
		if( target == null){
			throw new RuntimeException("ClassUtils.readSuperPrivateField:属性target  为空");
		}
		if( target.getClass().getSuperclass()  == Object.class){
			throw new RuntimeException("readSuperPrivateField:属性target"+target.getClass().getName()+"  没有超类");
		}
		Field field = FieldUtils.getDeclaredField(target.getClass().getSuperclass(), filedname,true);
		if (field == null) {
			throw new RuntimeException("readSuperPrivateField:属性target"+target.getClass().getName()+" 超类 没有属性:"+ filedname);
        }
		Object value;
		try {
			value = FieldUtils.readField(field, target, true);
		} catch (IllegalAccessException e) {
			throw new RuntimeException(e.getMessage());
		}
		return value;
		
	}
	private static Object writeSuperPrivateField(Object target,String filedname,Object value) {
		if( target == null){
			return new RuntimeException("readSuperPrivateField:属性target  为空");
		}
		if( target.getClass().getSuperclass()  == Object.class){
			return new RuntimeException("readSuperPrivateField:属性target "+target.getClass().getName()+"  没有超类");
		}
		Field field = FieldUtils.getDeclaredField(target.getClass().getSuperclass(), filedname,true);
		if (field == null) {
			return new RuntimeException("readSuperPrivateField:属性target "+target.getClass().getName()+" 超类 没有属性:"+ filedname);
        }
		try {
			FieldUtils.writeField(field, target, value,true);
		} catch (IllegalAccessException e) {
			return new RuntimeException(e.getMessage());
		}
		return value;
		
	}
	
	class ExecCallable implements Callable{
		private AtomicBoolean isExec = new AtomicBoolean(false);
		private Method method = null;
		private Object[] args = null;
		public ExecCallable(Method method,Object[] args) {
			// TODO Auto-generated constructor stub
			this.method = method;
			this.args = args;
		}
		@Override
		public Object call() throws Exception {
			// TODO Auto-generated method stub
			synchronized (this.isExec) {
				if(!isExec.get()){//未超时
					isExec.set(true);
					Object result = method.invoke(documentConverter, args);
					return result;
				}else{
					return null;
				}
			}
		}
		
	}

}




外部调用类:
import java.net.ConnectException;
import java.util.concurrent.atomic.AtomicInteger;

import com.artofsolving.jodconverter.DocumentConverter;
import com.artofsolving.jodconverter.openoffice.connection.OpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.connection.SocketOpenOfficeConnection;



/**
 * 连接单例
 * @author lyq
 * 2020.9.17
 */
public class OfficePatch {
	static AtomicInteger execExceptionCount =  new AtomicInteger(0) ; //连接异常处理次数,重连后清0
	private static OpenOfficeConnection conn = null;
	private static String LOCK_ = "";
	
	public static OpenOfficeConnection getConnection() throws ConnectException{
		if(conn==null){
			synchronized (LOCK_) {
				if(conn==null){
					conn = new SocketOpenOfficeConnection("ip", 端口);
					System.out.println("openOffice正在连接。。");
					conn.connect();
				}
			}
		}
		if(!conn.isConnected()){
			synchronized (LOCK_) {
				if(!conn.isConnected()){
					System.out.println("openOffice正在重新连接。。");
					execExceptionCount.set(0);
					conn.connect();
				}
			}
		}
		return conn;
	}
	
	/**
	 * 绑定并获取代理转换对象
	 * @param converter openoffice转换器
	 * @param connection converter所调用的连接
	 * @param timeoutSec 超时时间,单位:秒
	 * @return
	 */
	public static DocumentConverter getDocmentConverterProxy(DocumentConverter converter,Integer timeoutSec){
		DocumentConverterDynaProxy proxy = new DocumentConverterDynaProxy();
		return (DocumentConverter)proxy.bind(converter,timeoutSec);
	}
}




调用方法:
OpenOfficeConnection connection = OfficePatch.getConnection();
DocumentConverter converter = new StreamOpenOfficeDocumentConverter(connection);
converter = OfficePatch.getDocmentConverterProxy(converter, 100);



以上,完美处理openoffice宕机与单线程的问题。
分享到:
评论

相关推荐

    OpenOffice安装包 OpenOffice下载

    OpenOffice是一款开源的办公软件套件,它包含了与Microsoft Office相似的各种组件,如文字处理、电子表格、演示文稿制作、绘图以及数据库管理工具。这个压缩包包含了两个针对Linux操作系统的版本:OpenOffice_4.1.6_...

    openoffice的C#应用各种文档格式转换pdf

    在实际应用中,需要注意异常处理,比如文件不存在、OpenOffice服务未启动等问题。此外,可以考虑并发转换以提高效率,但要注意OpenOffice可能对并行转换的数量有限制。 七、示例代码 下面是一个简单的C#代码片段,...

    openoffice中文开发文档

    2. Web开发集成:OpenOffice可以作为服务器端的服务,处理Web应用中的文档操作。例如,用户可以在网页上提交一个文档,通过后端的OpenOffice服务进行格式转换、数据提取等处理,然后返回结果。这在B/S架构的应用中...

    openoffice完整jar包

    "实现openoffice文档转换在线预览"说明了主要的应用场景,即通过编程方式处理OpenOffice支持的文档格式(如ODT、DOC、XLS等),并生成预览。参考链接提供了具体的实现步骤和技术细节。 **标签解析** "openoffice ...

    c#使用openoffice组件操作文件

    6. **性能优化**:由于启动OpenOffice进程可能会消耗较多资源,因此在处理大量文件转换时,可以考虑使用多线程或者异步处理,提高并发性能。 7. **安全问题**:在实际应用中,考虑到用户可能上传含有恶意代码的文件...

    openOffice字体.zip

    OpenOffice是一款开源的办公软件套件,它包含了字处理、电子表格、演示文稿和图形编辑等组件,可与Microsoft Office兼容。在处理文档时,可能会遇到文本显示为乱码的问题,这通常是因为缺少特定的字体导致的。针对这...

    OpenOffice API的例程

    OpenOffice API是一个强大的工具,允许开发者通过编程方式与OpenOffice套件进行交互,...通过深入学习和实践,你可以构建出能够无缝集成OpenOffice功能的应用程序,无论是批量处理文档还是自定义办公自动化解决方案。

    openoffice

    在IT领域,特别是开源软件社区,Apache OpenOffice(简称OpenOffice)是一款备受推崇的免费办公套件,它提供了包括文字处理、电子表格、演示文稿、数据库管理等在内的多种功能,是Microsoft Office的一个强有力的...

    Openoffice转换多列EXCEL为PDF行列对应解决方法

    1. **打开OpenOffice Calc**:启动OpenOffice,选择“组件”中的“Calc”,这将是我们的电子表格应用程序。 2. **导入Excel文件**:点击菜单栏上的“文件”&gt;“打开”,找到你的Excel文件(可能带有.xlsx或.xls扩展...

    openoffice所需jar包

    在Java开发环境中,如果需要与OpenOffice进行交互,例如自动化处理文档或数据转换,开发者通常会用到特定的Java库,这些库被打包成JAR文件。在给定的标题和描述中,提到的是用于集成OpenOffice功能的一系列jar包。 ...

    java使用OpenOffice实现的Excel转pfd

    Java作为一种广泛应用的编程语言,提供了多种库和工具来处理这样的需求。本话题主要关注如何使用OpenOffice API在Java环境中将Excel文件转换为PDF格式,同时确保图片等复杂元素能够完美保留。 OpenOffice是一个开源...

    OpenOffice应用

    ### OpenOffice应用:常见问题与解决方案深度解析 #### 开源软件OpenOffice的使用心得与技巧 OpenOffice作为一款开源的办公软件套装,以其强大的功能、跨平台的兼容性以及自由的许可证模式,受到了广大用户的喜爱...

    openoffice sdk开发文档中文版

    《OpenOffice SDK开发文档中文版》主要面向希望开发OpenOffice应用程序的开发者,文档中详尽介绍了OpenOffice的开发接口以及编程模型,通过API函数详解、类和接口的介绍,以及实际的例子来帮助开发者更好地理解和...

    OpenOffice在线预览文件

    OpenOffice是一款开源的办公软件套件,它包含了与Microsoft Office相似的应用程序,如Writer(文字处理)、Calc(电子表格)、Impress(演示文稿)和Draw(绘图)。这款软件的强大之处在于其跨平台的兼容性和对多种...

    OpenOffice 4.1.8 Ubuntu 安装包

    OpenOffice 4.1.8 是一款开源的办公软件套件,专为各种操作系统,包括Ubuntu,提供免费的文档处理、电子表格、演示文稿、绘图和数据库管理工具。这款软件是Apache软件基金会的项目之一,旨在替代商业化的Microsoft ...

    openoffice二次开发报告

    OpenOffice是一款开源的办公软件套件,它包含了文字处理、电子表格、演示文稿、绘图等多种组件,可以与Microsoft Office兼容。OpenOffice提供了丰富的API和工具,允许开发者进行二次开发,创建自定义功能、插件或者...

    openoffice示例.rar

    OpenOffice是一款开源的办公软件套件,它包含了与Microsoft Office相似的各种组件,如文字处理、电子表格、演示文稿制作、绘图以及数据库管理等工具。这个名为"openoffice示例.rar"的压缩包文件很可能是为了提供...

    openoffice实现预览功能

    OpenOffice是一款开源的办公软件套件,包含了文字处理、电子表格、演示文稿等多种应用程序,同时也提供了API供开发者使用。在IT行业中,OpenOffice的其中一个应用是实现文档的预览功能,尤其对于需要在线预览doc、...

Global site tag (gtag.js) - Google Analytics