简体   繁体   中英

How does Java initialize the JAXB/JAX-WS/etc implementation?

I'm just digging around a bit trying to understand how Java can have standard reference implementations included in the JRE (eg JAXB/JAX-WS in JRE6), while still allowing 3rd-party implementations to override that (eg CXF).

I've gotten to the place that I found the javax.xml.ws.spi.FactoryFinder.find() method which either locates the class specified in META-INF/services/java.xml.ws.spi.Provider or com.sun.xml.internal.ws.spi.ProviderImpl (for the JAX-WS case) and creates an instance of that.

What I can't find is how/where/at which stage the JRE calls that FactoryFinder.find() method.

Can anybody enlighten me?

[edit] I've found the answer but am not allowed to post it myself for another 3 hours...

Figured out the complete logic. Actually nothing happens on JVM startup. It's all based on lazy loading, eg the real JAX-WS/whatever provider is only loaded/instantiated the first time it's needed.

In the case of loading the JAX-WS implementation:

Assume we want to call a web service, using code like:

MyService     service = new MyService_Service();
MyServiceSoap port    = service.getMyServiceSoap();

port.mymethod(); 

then the following happens to initialize the JAX-WS implementation:

  • Any JAX-WS webservice extends javax.xml.ws.Service, so MyService_Service extends Service
  • When you create an instance of your web service, its superclass (javax.xml.ws.Service) is also initialized (constructor)
  • The constructor for "Service" calls javax.xml.ws.spi.Provider.provider(), which is a static method that uses javax.xml.ws.spi.FactoryFinder.find() to find and instantiate the implementation as configured.

Assume we want to publish a web service using code like:

@WebService(endpointInterface = "my.package.MyService")
public class MyServiceImp implements MyService {
    ...
}

MyServiceImp      service  = new MyServiceImp();
InetSocketAddress addr     = new InetSocketAddress(8080);
Executor          executor = Executors.newFixedThreadPool(16);
HttpServer        server   = new HttpServer(addr);
server.setExecutor(executor);

HttpContext       context  = server.createContext("/MyService");
Endpoint          endpoint = Endpoint.create(service);
endpoint.publish(context);
server.start();

then the following happens to initialize the JAX-WS implementation:

  • Endpoint.create() runs Provider.provider().createEndpoint()
  • Provider.provider() is a static method that uses javax.xml.ws.spi.FactoryFinder.find() to find and instantiate the implementation as configured.

The following links helped me understand this:

You can change the default behavior using system property javax.xml.bind.context.factory . Its value should be the fully qualified class name of the factory.

The default value of this property is com.sun.xml.internal.bind.v2.ContextFactory . This factory is not required to implement any specific interface by it must implement method createContext(String, ClassLoader, Map)

There are a few mechanisms which control which implementation you use. each jre/jdk has a built in "default" implementation hardcoded into the init code. There are also some system properties you can use to specify a specific implementation (as @AlexR mentioned). however, that is not the standard mechanism for specifying a different implementation. most alternate implementations include a special file in their META-INF directory (within the jar) which indicate to the jre/jdk that they should be used instead of the default implementation (this works without setting any system properties, you just drop the jars into the classpath). these special files are found by ServiceLoader utility and enable the alternate implementation to be automatically loaded.

I found that a working JAXB sample fails after putting a weblogicfullclient.jar onto the classpath, because the jar contains a META-INF/services/javax.xml.bind.JAXBContext but not the implementation. Unfortunately, one cannot tell JAXB to "just use PLATFORM_DEFAULT_FACTORY_CLASS", you have to put it on a System property (-Djavax.xml.bind.JAXBContext=com.sun.xml.internal.bind.v2.ContextFactory for 1.6 and -Djavax.xml.bind.context.factory=.. for 1.7), the javax.xml.bind.ContextFinder.find(String, String, ClassLoader, Map) implementations differ for 1.6 and 1.7

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