简体   繁体   中英

How to use COM servers in multiple Java threads

The company I work for wanted some functionality for some software, as it could apply to multiple products and these products are written in different languages, although all only run on Windows, it seemed a good choice to implement it in a COM server. I wrote the COM server using python and the pywin32 extensions, so access to it is late binding and I believe IDispatch.

I am now trying to create Java bindings for the COM server, as it requires use of the dispatch interface, I decided to use JACOB to access COM (it seems to be one of the most recently updated projects and fitted with our needs). Being fairly new to COM and not really seeing any issues with multithreading in the library the COM server wraps, I paid little attention to COM threading at first, so it the Java bindings for the COM objects I did not use any of the threading stuff provided by JACOB, simple tests of it worked fine in Oracle's JVM.

However it has become clear that I cannot ignore COM threading. One issue being that the Java product is compiled using Excelsior Jet, which for some reason was not releasing the COM objects in Java and so the COM server (which is a separate .exe) continued to run after exiting the application. The other issue being that we do actually need to use the COM objects from multiple threads, my original approach was hitting the issue that the COM object could not be used in multiple threads.

I have read the document in the JACOB distribution about how it handles COM objects (both the one about reference counting VS GC and the document on multiple threads). I believe I understand these and how to use the COM object now in multiple threads and get them properly released (using JACOB's ComThread.Release() for each thread does lead to Excelsior Jet releasing the COM objects as well).

My thought is that a multithreaded apartment should be fine with the COM server, so according to the JACOB documentation this simply requires each thread to call com.jacob.com.ComThread.InitMTA() before using the COM objects and then call com.jacob.com.ComThread.Release() at the end of each thread using the COM objects. Also the document suggests that I probably will want JACOB to create a main STA, so this would also mean a call to quit the main STA at the shutdown of the application.

My question is, this calling things at the beginning of a thread does not really seem to fit well with Java way of doing things, is there any way I can try and isolate the rest of the application from these peculiarities of COM, particularly in the threading area?

I have considered, as the application is using my bindings rather than the COM objects directly, could this stuff be handled within those wrapper classes? However I only seem to come up with calling ComThread.InitMTA() and ComThread.Release() in every method of the wrapper object which accesses the COM object. This feels inefficient, however I don't know how much calls to ComThread.InitMTA() and ComThread.Release() actually do so it may not be as bad as it might initially seem.

My other thought is, its very early days of using this library, I don't think we have actually released anything using the COM server, so might there be a better technology to use (eg. RPC, may be XMLRPC)? Such a change probably would not be too painful to make at the moment.

To provide a little context as to what the library is doing, its mainly wrapping various speech output APIs into one (eg. giving a common interface for accessing both SAPI4, SAPI5 and some others). So most calls are just telling the system to say something, to silence speech or to change a setting. In general the communication with the library is very simple (I think returning an array of strings is about as complicated as it gets).

This sounds like a very good candidate for some Aspect Oriented Programming (AOP). The dominating framework in java is AspectJ , but most people use it in the context of Spring-AOP . Depending on your requirements and architecture, you can go in different directions:

  1. Compile-time weaving - pointcuts and advice are applied ("weaved") at compile-time by a special compiler
  2. Load-time weaving - pointcuts and advice are applied at run-time by a JVM agent
  3. Dynamic proxying - pointcuts and advice are applied run-time by wrapping adviced classes in dynamic proxy facades (this is how Spring-AOP does it)

Found this fairly good writeup on aspectj weaving .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM