JAX-WS客户端为什么需要在运行时访问WSDL?

8
使用wsimport生成JAX-WS客户端后,您需要进行以下步骤:
wsimport -keep WebService.wsdl

JAX-WS在运行时查找wsdl位置的原因是什么?这是一个错误吗?
我找到了这篇很棒的文章:JAX-WS客户端:访问本地WSDL的正确路径是什么?,但它没有说明为什么我们需要在运行时使用wsdl。
2个回答

7

这是一个bug吗?

不是,从概念上讲这是合理的。

JAX-WS在运行时查找wsdl位置有什么原因呢?

在构建时,您需要从WSDL生成类,这意味着您需要知道服务支持哪些操作以及消息的结构(即portTypestypesmessages)。

在运行时,会涉及到大量不同的信息。例如,服务实际运行的地址可能已更改。 bindings变得重要:消息应该以SOAP 1.1还是1.2发送,或者两种格式都可以吗?此外,可能会将各种策略(安全性、可靠性消息等)附加到服务。所有这些都是动态的,在构建时大多数情况下都不相关。理想情况下,您应该能够将客户端指向使用相同结构的不同服务,它应该可以直接工作。

我想回答另一个我认为您可能会问的问题:

对于只有一个永远不会更改其构建时状态的特定WSDL的单个服务,这是否完全是一种开销?

是的,确实如此。对于只有一个特定WSDL的单个服务,其构建时状态永远不会更改的情况下,在运行时重新加载WSDL是不必要的,也是资源浪费。但是如果JAX-WS不允许更复杂的情况,例如信息(例如绑定或策略)发生更改或服务有多个端点,则它将做得很糟糕。

尽管如此,大多数JAX-WS实现都允许某种机制将WSDL存储在本地并且不会在运行时加载它。在RI中,只需将您的@WebServiceClient中的wsdlLocation指向类路径上的文件即可。


1
我想,也许你需要一个代码解决方案。以下解决方案要求您将WSDL文件存储在资源文件夹中,该资源文件夹是maven项目的资源文件夹。
@Bean
public WeatherWebServiceServiceSoap weatherWebServiceServiceSoap() throws Exception{
    URL wslLocation = generatedWsdlLocation();
    if(log.isDebugEnabled()) {
        log.debug("WSDL Location: " + wslLocation.toString());
    }
    // cover wslLocation with the arg constructor
    WeatherWebServiceService weatherWebServiceService = new WeatherWebServiceService(wslLocation);
    weatherWebServiceService.setHandlerResolver(
        portInfo -> webServiceSOAPHandlerList.stream().map(s -> (Handler)s).collect(Collectors.toList()));

    WeatherWebServiceServiceSoap serviceSoap = weatherWebServiceService.getWeatherWebServiceServiceSoap();
    BindingProvider bindingProvider = ((BindingProvider)serviceSoap);

    bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
        wsdlProperties.getAddressLocation());

    return serviceSoap;
}

private URL generatedWsdlLocation() throws MalformedURLException {
    URL baseUrl = ClassUtil.getLocation(this.getClass());
    // the value of WebServiceConstants.WEATHER_WSDL_RESOURCES_LOCATION should be the relative path of your wsdl in resources(e.g. src/main/resources/wsdl, then the value should be wsdl/).
    return new URL(baseUrl, WebServiceConstants.WEATHER_WSDL_RESOURCES_LOCATION);
}

ClassUtil 可以帮助您获取存储 wsdl 文件的 jar 文件中的类路径。

/**
 * ref: https://github.com/scijava/scijava-common/blob/scijava-common-2.62.1/src/main/java/org/scijava/util/ClassUtils.java#L296-L355
 */
@Slf4j
public class ClassUtil {

    /**
     * get the jar classes path where the <code>clazz</codee> belongs to.
     *
     * <p>
     * if in file system(e.g. /path/to/package/TheClass.class) return file directory (e.g. file:/path/to); if in jar (e.g.
     * /path/to/the-jar.jar!/the/package/TheClass), return path in jar( e.g. jar:file:/path/to/the-jar.jar!/BOOT-INF/classes!/)
     * return null when error occured.
     * </p>
     */
    public static URL getLocation(Class<?> clazz) {
        if (clazz == null) {
            // could not load the class
            return null;
        }
        try {
            URL codeSourceLocation = clazz.getProtectionDomain().getCodeSource().getLocation();
            if (codeSourceLocation != null) {
                return codeSourceLocation;
            }
        } catch (Exception e) {
            // SecurityException: Cannot access protection domain.
            // NullPointerException: Protection domain or code source is null.
        }
        final URL classResource = clazz.getResource(clazz.getSimpleName() + ".class");
        if (classResource == null) {
            // cannot find class resource
            return null;
        }
        String url = classResource.toString();
        // java.io.File -> java/io/File.class
        String suffix = clazz.getCanonicalName().replace('.', '/') + ".class";
        if (!url.endsWith(suffix)) {
            if (isDebugEnable()) {
                log.debug("Weired URL: {} should end with {}", url, suffix);
            }
            // weired URL
            return null;
        }

        String classesUrl = url.substring(0, url.length() - suffix.length());
        try {
            return new URL(classesUrl);
        } catch (MalformedURLException e) {
            if (isDebugEnable()) {
                log.debug(e.getMessage(), e);
            }
            return null;
        }
    }

    public static URL getFileLocation(Class<?> clazz) {
        URL url = getLocation(clazz);
        if(url == null) {
            return url;
        }
        String path = url.toString();
        if(path.startsWith("jar:")) {
            // remove "jar:" prefix and "!/" suffix
            path = path.substring(4, path.length() - 2);
        }
        try {
            return new URL(path);
        } catch (MalformedURLException e) {
            if (isDebugEnable()) {
                log.debug(e.getMessage(), e);
            }
            return null;
        }
    }

    private static boolean isDebugEnable() {
        return log.isDebugEnabled();
    }
}

一些参考:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接