Is there a way to config relative address attribute for <jaxws:client> tag?
I'm stuck with a problem that appears to be simple, but cannot figure it out.
I need to configure a Spring MVC web app with CXF so that I can deploy it on multiple locations (different servlet containers, different ports). Everything works fine, but in my XML configuration of CXF where I configure a JAX-WS client the tag requires the "address" attribute with specified absolute URL in order to work.
Here's the code:
<jaxws:client id="wsClient" serviceClass="com.foo.WebServiceInterface" address="http://localhost:8092/WSApp/WebServiceImplPort" /&g开发者_Python百科t;
Is there any way to change the address to relative or any other simple solution to accomplish my goal? Thank you!
If you use maven (or possibly even in ant) to do the deployment you can use properties in your xml file and enable resource filtering in your pom to set this parameter for each environment.
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<!-- Turn on filtering of test resources to allow the correct environment for unit tests -->
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
</testResource>
</testResources>
</build>
Another option is within the code when actually creating the client reference there is a parameterised option to pass a URL when creating the client reference.
SomeServiceClientEP client = new SomeServiceClientEP(url, qname);
dynamicallySetEndpoint((BindingProvider) SomeService, destinationURL);
/**
* Change the destination endpoint url for some service to the
* provided in the <i>destinationURL</i> parameter
*
* @param service
* The {@link SomeService} JAXWS proxy for accessing the
* service
* @param destinationURL
* The URL of the SomeService to send the
* request to. If the URL contains ?wsdl at the end it will be
* stripped prior to attempting delivery
*/
protected void dynamicallySetEndpoint( BindingProvider service, final String destinationURL) {
Map<String,Object> rc = service.getRequestContext();
// Strip the ?wsdl off the end of the URL
String url = destinationURL;
if (destinationURL.toLowerCase().matches(WsdlSuffixPattern)) {
url = destinationURL.substring(0, destinationURL.length() - WsdlSuffix.length());
}
rc.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, url);
}
Well, where to place the configuration is a controversial matter, and it depends of tastes. Relying on maven resources filters requires to package again the war in every deployment. For me, it's not an option.
Option 1 Spring profiles
You could define different spring profiles according to your deployment settings, and for example define in a property file where is rest services is deployed.
<beans profile="develop">
<context:property-placeholder location="classpath:develop-config.properties" />
</beans>
<beans profile="production">
<context:property-placeholder location="classpath:production-config.properties" />
</beans>
<jaxws:client id="wsClient" serviceClass="com.foo.WebServiceInterface" address="${address}" />
production-config.properties could have:
address=http://localhost:8092/WSApp/WebServiceImplPort
To active your favourite profile: Start the application using -Dspring.profiles.active=production
Option 2 Spring enviroments
Spring introduces a mechanism to enable or active profiles programmatically. This can be uses to read different configuration file for every enviroment. Or you can make available for your spring context java system variables or operative system enviroment variables. If you would like to follow the 12 factor application guideline about configuration. They say that the configuration should be place on Enviroment variables. Or rather you rather prefer 1 war Many deployment approach. This is your choice.
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.io.support.ResourcePropertySource;
import org.springframework.web.context.ConfigurableWebApplicationContext;
public class EnviromentDiscovery implements org.springframework.context.ApplicationContextInitializer.ApplicationContextInitializer<org.springframework.context.ApplicationContextInitializer.ConfigurableWebApplicationContext> {
public void initialize(ConfigurableWebApplicationContext ctx) {
ConfigurableEnvironment environment = ctx.getEnvironment();
// This variable has the same meaning as host, but i can be redefined in
// case of cluster deployment.
String hostname= InetAddress.getLocalHost().getHostName();
logger.info("Application deployed int host {} using context path: {}", engineName, contextPath);
// You should define a method which load your config.properties according your own criteria depending for example on your hostname.
InputStream configurationSource = getResourceAsStream(hostname);
Properties config = new Properties();
config.load(configurationSource);
// Take your address endpoint
String address = config.getProperty("address");
Map<String, Object> props = new HashMap<>();
props.put("address", address);
MapPropertySource mapSource = new MapPropertySource("props", props);
// Voilá! your property address is available under spring context!
environment.getPropertySources().addLast(mapSource);
ctx.registerShutdownHook();
}
}
Now your context file looks like:
Don't forget to add in your web.xml
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>net.sf.gazpachoquest.bootstrap.EnviromentDiscovery</param-value>
</context-param>
More info about Spring environment here : or if you want to check out my proof of concept here.
精彩评论