How to set timeout in Spring WebServiceTemplate - java

I am using org.springframework.ws.client.core.WebServiceTemplate for making Web Service calls. How can i configure timeout for the call.

If you are using Spring Webservices 2.1.0 version, You can set timeout using HttpComponentsMessageSender.
CommonsHttpMessageSender are deprecated and not recommended by Spring anymore.
The way I have it implemented, I define my WebServiceTemplate to use HttpComponentsMessageSender.
Values are in Milliseconds
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<property name="defaultUri" value="${endpoint.url}" />
<property name="marshaller" ref="marshaller" />
<property name="unmarshaller" ref="unmarshaller" />
<property name="messageSender">
<bean class="org.springframework.ws.transport.http.HttpComponentsMessageSender">
<property name="connectionTimeout" value="1200000" />
<property name="readTimeout" value="1200000" />
</bean>
</property>
</bean>
Just Make sure you have in your pom file, you added the following
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.2.1</version>
<scope>compile</scope>
</dependency>

Same as Sathish answer, but programmatically (Spring 4+):
#Component
public class MyWebServiceGatewaySupport extends WebServiceGatewaySupport
{
#Value("${my.ws.readtimeout}")
private String readTimeout;
#Value("${my.ws.connectiontimeout}")
private String connectionTimeout;
Object marshalSendAndReceive(String endpoint, Object requestPayload)
{
WebServiceTemplate wsTemplate = this.getWebServiceTemplate();
WebServiceMessageSender[] senders = wsTemplate.getMessageSenders();
for (WebServiceMessageSender sender: senders)
{
try
{
int readTimeoutMsec = Integer.parseInt(readTimeout);
int connTimeoutMsec = Integer.parseInt(connectionTimeout);
HttpComponentsMessageSender httpSender = (HttpComponentsMessageSender) sender;
httpSender.setReadTimeout(readTimeoutMsec);
httpSender.setConnectionTimeout(connTimeoutMsec);
}
catch (ClassCastException|NumberFormatException cex)
{
logger.warn("Cannot set WS timeout: " + cex.getMessage());
}
}
return wsTemplate.marshalSendAndReceive(endpoint, requestPayload);
}
}

Since Spring Webservices 2.2, you can also use Spring's ClientHttpRequestMessageSender:
#Service
public class CustomWebServiceImpl extends WebServiceGatewaySupport implements CustomWebService {
private static final int CONNECTION_TIMEOUT = (10 * 1000);
private static final int READ_TIMEOUT = (10 * 1000);
public CustomWebServiceImpl() {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setConnectTimeout(CONNECTION_TIMEOUT);
requestFactory.setReadTimeout(READ_TIMEOUT);
setMessageSender(new ClientHttpRequestMessageSender(requestFactory));
}
(...)
}
(no dependency to Apache HTTP Components required)

The below code worked for me.
#Bean
public YourClassImpl yourClassImpl(Jaxb2Marshaller marshaller, HttpComponentsMessageSender httpComponentsMessageSender) {
YourClassImpl client = new YourClassImpl();
client.setDefaultUri(PiiProperties.SOAP_ACTION.getValue());
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
client.setMessageSender(httpComponentsMessageSender);
return client;
}
#Bean
public HttpComponentsMessageSender httpComponentsMessageSender() {
HttpComponentsMessageSender sender = new HttpComponentsMessageSender();
sender.setReadTimeout(1000);
sender.setConnectionTimeout(1000);
return sender;
}

If you want that kind of control, you can
either switch to CommonsHttpMessageSender, which uses the Jakarta Commons
HttpClient
or subclass HttpUrlConnectionMessageSender and in the
prepareConnection(HttpURLConnection) method call
UrlConnection.setReadTimeOut(int)

That's how I did:
#Configuration
public class MunisServiceConfig {
#Value("${service.uri}")
private String soapUri;
#Bean
Jaxb2Marshaller jaxb2Marshaller() {
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
jaxb2Marshaller.setContextPath(CheckStatePayment.class.getPackage().getName());
return jaxb2Marshaller;
}
#Bean
public WebServiceTemplate munisService() {
WebServiceTemplate template = new WebServiceTemplate();
template.setMarshaller(jaxb2Marshaller());
template.setUnmarshaller(jaxb2Marshaller());
template.setDefaultUri(soapUri);
HttpComponentsMessageSender httpComponentsMessageSender = new HttpComponentsMessageSender();
httpComponentsMessageSender.setReadTimeout(3000);
httpComponentsMessageSender.setConnectionTimeout(5000);
template.setMessageSender(httpComponentsMessageSender);
return template;
}
}

This article will probably sort you out:
http://onebyteatatime.wordpress.com/2009/03/19/how-to-set-socket-timeout-using-spring-webservicetemplate/
The way I have it implemented, I define my WebServiceTemplate to use CommonsHttpMessageSender:
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory" />
<property name="messageSender">
<bean
class="org.springframework.ws.transport.http.CommonsHttpMessageSender">
</bean>
</property>
</bean>
Then, in code, I get the messageSender and set the timeout on it. You could equally do this in your xml.
CommonsHttpMessageSender messageSender = (CommonsHttpMessageSender)webServiceTemplate.getMessageSenders()[0];
messageSender.getHttpClient().getParams().setSoTimeout(timeoutMillis);

This code works with Spring Boot (verified on 2.1.5.RELEASE):
#Configuration
public class ExampleServiceClientConfiguration {
#Value("${example-service.uri}")
private String exampleServiceUri;
#Value("${example-service.timeout:120}")
private int exampleServiceTimeout;
#Bean
public ExampleServiceClient exampleServiceClient() {
ExampleServiceClient client = new ExampleServiceClient();
client.setMessageSender(httpUrlConnectionMessageSender());
client.setDefaultUri(exampleServiceUri);
client.setMarshaller(marshaller());
client.setUnmarshaller(marshaller());
return client;
}
#Bean
HttpUrlConnectionMessageSender httpUrlConnectionMessageSender() {
HttpUrlConnectionMessageSender sender = new HttpUrlConnectionMessageSender();
Duration timeout = Duration.ofSeconds(exampleServiceTimeout);
sender.setReadTimeout(timeout);
sender.setConnectionTimeout(timeout);
return sender;
}
#Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath(ObjectFactory.class.getPackageName());
return marshaller;
}
}

For the CommonsHttpMessageSender, we can set the timeout in the following way:
<bean id="httpParams" class="org.apache.commons.httpclient.params.HttpClientParams">
<!-- Timeout in milliseconds: in this case 1 minute -->
<property name="soTimeout" value="60000" />
</bean>
<bean id="httpClient" class="org.apache.commons.httpclient.HttpClient">
<property name="params" ref="httpParams" />
</bean>
<!-- Define the message sender used by all web service templates -->
<bean id="webServiceMessageSender" class="org.springframework.ws.transport.http.CommonsHttpMessageSender">
<constructor-arg>
<ref bean="httpClient"/>
</constructor-arg>
</bean>
and ref the webServiceMessageSender as below:
<bean id="genericWebServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<property name="messageSender" ref="webServiceMessageSender"/>
</bean>

Related

How to create DefaultMessageListenerContainer in Spring-Boot?

I am new to Spring-Boot and trying to create DefaultMessageListenerContainer so I can use the weblogic workmanager and run several message listeners in multithreaded fashion.
Can someone please provide some example.
So far, I found the below solution but how do I implement this in Spring-Boot?
<bean class="org.springframework.jms.listener.SimpleMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="destination"/>
<property name="messageListener" ref="receiver"/>
<property name="taskExecutor" ref="taskExecutor"/>
</bean>
Create a ConnectionFactory:
#Bean
public ActiveMQConnectionFactory receiverActiveMQConnectionFactory() {
ActiveMQConnectionFactory activeMQConnectionFactory =
new ActiveMQConnectionFactory();
activeMQConnectionFactory.setBrokerURL("yourBrokerUrl");
return activeMQConnectionFactory;
}
Create a DefaultJmsListenerContainerFactory:
#Bean
public DefaultJmsListenerContainerFactory orderDefaultJmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory =
new DefaultJmsListenerContainerFactory();
factory
.setConnectionFactory(receiverActiveMQConnectionFactory());
factory.setConcurrency("3-10");
return factory;
}
Create your DefaultMessageListenerContainer:
#Bean
public DefaultMessageListenerContainer orderMessageListenerContainer() {
SimpleJmsListenerEndpoint endpoint =
new SimpleJmsListenerEndpoint();
endpoint.setMessageListener(new YourMessageListener());
endpoint.setDestination("yourDestination");
return orderDefaultJmsListenerContainerFactory()
.createListenerContainer(endpoint);
}
For a more detailed example checkout this post I created on Spring JMS listeners.

cxf spring boot schemalocations configuration

I would like to add to webConfWebService configuration class for my spring boot app a schema(xsd).
With xml configuration is as follows:
<jaxws:endpoint address="/nameService" publishedEndpointUrl="">
<jaxws:implementor>
<bean class=name.pkg.ServiceWSImpl" />
</jaxws:implementor>
<jaxws:dataBinding>
<bean class="org.apache.cxf.xmlbeans.XmlBeansDataBinding" />
</jaxws:dataBinding>
<jaxws:serviceFactory>
<bean class="org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean">
<property name="wrapped" value="false" />
</bean>
</jaxws:serviceFactory>
<jaxws:schemaLocations>
<jaxws:schemaLocation>classpath:META-INF/xsd/namexsd1.xsd</jaxws:schemaLocation>
<jaxws:schemaLocation>classpath:META-INF/xsd/namexsd12.xsd</jaxws:schemaLocation>
</jaxws:schemaLocations>
<jaxws:inInterceptors>
<ref bean="authInterceptor" />
</jaxws:inInterceptors>
<jaxws:properties>
<entry key="schema-validation-enabled" value="false" />
</jaxws:properties>
</jaxws:endpoint>
and with annotation i started to create my endPOint as follows and i am blocked to how to import the list of schemalocation, i don't know how to do it:
#Configuration
public class WebServiceConfig {
#Autowired
private Bus bus;
#Bean
public ServletRegistrationBean dispatcherSerlvet() {
return new ServletRegistrationBean(new CXFServlet(), "/services/*");
}
#Bean
public Endpoint namesServiceEndpoint() {
EndpointImpl endpoint = new EndpointImpl(bus, new NameServiceImpl());
endpoint.publish("/Hello");
endpoint.setSchemaLocations(schemaLocations);//HERE ......
return endpoint;
}
It is by adding them in a list as follows:
List<String> schemaLocations = new ArrayList<String>();
Resource resource = resourceLoader.getResource(""classpath:/xsd/nameSchema.xsd);
schemaLocations.add(resource.getFile().getPath());
endpoint.setSchemaLocations(schemaLocations);

Java Spring Interceptor with no XML

I understand that it is possible to configure a Spring application without the use of XML config files, and have commited to this method. I am not sure, however, how to declare HTTP interceptors in this manner. I am using this tutorial, which declares the following XML.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/welcome.htm">welcomeController</prop>
</props>
</property>
<property name="interceptors">
<list>
<ref bean="maintenanceInterceptor" />
<ref bean="executeTimeInterceptor" />
</list>
</property>
</bean>
<bean
class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
<property name="interceptors">
<list>
<ref bean="executeTimeInterceptor" />
</list>
</property>
</bean>
<bean id="welcomeController"
class="com.mkyong.common.controller.WelcomeController" />
<bean class="com.mkyong.common.controller.MaintenanceController" />
<bean id="executeTimeInterceptor"
class="com.mkyong.common.interceptor.ExecuteTimeInterceptor" />
<bean id="maintenanceInterceptor"
class="com.mkyong.common.interceptor.MaintenanceInterceptor">
<property name="maintenanceStartTime" value="23" />
<property name="maintenanceEndTime" value="24" />
<property name="maintenanceMapping" value="/SpringMVC/maintenance.htm" />
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
How to do this in Java? There is no #Interceptor annotation.
SpringApplication.java
#SuppressWarnings("WeakerAccess")
#SpringBootApplication
#PropertySources(value = {#PropertySource("classpath:/application.properties")})
public class SpringbackendApplication {
#Autowired
Environment env;
public static void main(String[] args) {
SpringApplication.run(SpringbackendApplication.class, args);
initializeFirebase();
}
#Bean
public ViewResolver getViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
#Bean
public UserController userController() {
UserController userController = new UserController(getUserDAO(), getYodleeDAO());
userController.setCobrandSession(cobrandSession());
userController.setUserSessionManager(userSessionManager());
userController.setAccountsService(accountsService());
userController.setTransactionsService(transactionsService());
return userController;
}
#Bean
public TestController testController() {
TestController testController = new TestController();
testController.setCobrandSession(cobrandSession());
testController.setUserSessionManager(userSessionManager());
testController.setAccountsService(accountsService());
testController.setTransactionsService(transactionsService());
return testController;
}
#Bean
public CobrandSession cobrandSession() {
CobrandSession cobrandSession = new CobrandSession();
cobrandSession.setApiBase(this.env.getProperty("API_BASE"));
cobrandSession.setLogin(this.env.getProperty("LOGIN"));
cobrandSession.setPassword(this.env.getProperty("PASSWORD"));
cobrandSession.setLocale(this.env.getProperty("LOCALE"));
cobrandSession.setRestTemplate(restTemplate());
cobrandSession.setGson(gson());
return cobrandSession;
}
#Bean
public AccountsService accountsService() {
AccountsService accountsService = new AccountsService();
accountsService.setApiBase(this.env.getProperty("API_BASE"));
accountsService.setRestTemplate(restTemplate());
accountsService.setGson(gson());
return accountsService;
}
#Bean
public RestTemplate restTemplate() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setOutputStreaming(false); // If we don't turn this off, we may get HttpRetryException on 401's.
return new RestTemplate(factory);
}
#Bean
public Gson gson() {
return new Gson();
}
}
To move your Spring beans defined in an XML file to a Configuration class (marked with #Configuration) you would need something like this:
#Configuration
public class MyConfig {
#Bean(name="executeTimeInterceptor")
public ExecuteTimeInterceptor getExecuteTimeInterceptor() {
return new com.mkyong.common.interceptor.ExecuteTimeInterceptor();
}
#Bean(name="maintenanceInterceptor")
public MaintenanceInterceptor getMaintenanceInterceptor(#Value("${properties.maintenanceStartTime}") int maintenanceStartTime,
#Value("${properties.maintenanceEndTime}") int maintenanceEndTime,
#Value("${properties.maintenanceMapping}") String maintenanceMapping) {
MaintenanceInterceptor myInt = new MaintenanceInterceptor();
myInt.setMaintenanceStartTime(maintenanceStartTime);
myInt.setmMaintenanceEndTime(maintenanceEndTime);
myInt.setMaintenanceMapping(maintenanceMapping);
return myInt;
}
}
...then in some propertiesFile.properties on the classpath add these...
properties.maintenanceStartTime=23
properties.maintenanceEndTime=24
properties.maintenanceMapping=/SpringMVC/maintenance.htm
EDIT
I see you are getting your props from the Environment, so instead of #Value injection, use the way you have it in your code right now.
You have to override WebMvcConfigurerAdapter.addInterceptors() method and add your interceptors:
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CustomInterceptor());
}
Don't forget to mark your class with #Configuration

How to set bean using java config in spring

I have below details in spring xml file. Now I want to convert it into spring java config bean.
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="test" />
<property name="port" value="111" />
<property name="username" value="test#gmail.com" />
<property name="password" value="test123" />
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">true</prop>
<prop key="mail.smtp.starttls.enable">true</prop>
</props>
</property>
</bean>
<bean id="utilityObject" class="com.ezone.utility.TestUtility">
<property name="mailSender" ref="mailSender" />
</bean>
Converted mailSender this bean as below. But How to convert utilityObject in java config spring bean. I am new in this.
#Bean(name="mailSender",autowire=Autowire.BY_NAME)
public JavaMailSenderImpl mailConfiguration(){
JavaMailSenderImpl mail = new JavaMailSenderImpl();
mail.setHost("test");
mail.setPort(111);
mail.setUsername("test#gmail.com");
mail.setPassword("test123");
Properties javaMailProperties = new Properties();
javaMailProperties.put("mail.smtp.auth", "true");
javaMailProperties.put("mail.smtp.starttls.enable", "true");
javaMailProperties.setProperty("mail.smtp.auth", "true");
javaMailProperties.setProperty("mail.smtp.starttls.enable", "true");
mail.setJavaMailProperties(javaMailProperties);
return mail;
}
How can I define below bean :
<bean id="utilityObject" class="com.ezone.utility.TestUtility">
<property name="mailSender" ref="mailSender" />
</bean>
The above bean has the reference of mailSender.
You can either put a parameter on the #Bean method, which will get injected:
#Bean
public TestUtility utilityObject(JavaMailSender mailConfiguration) {
return new TestUtility(mailConfiguration);
}
or call from one #Bean method in an #Configuration to another; Spring will proxy them and make sure the singleton behavior gets applied:
#Bean
public TestUtility utilityObject() {
return new TestUtility(mailConfiguration());
}
I think the first one is a bit less magic, but either approach should work.
The methods annotated with #Bean can be called from other methods. Spring makes proxy for #Configuration class and singletons are created only once.
#Bean
public TestUtility utilityObject() {
TestUtility uo = new TestUtility();
uo.setMailSender(mailConfiguration());
return uo;
}
See details http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-java-further-information-java-config
Use #configuration for the JavaMailSenderImpl class
Refer : http://www.tutorialspoint.com/spring/spring_java_based_configuration.htm
EDIT
#Bean
public TestUtility getUtilityObject() {
return new TestUtility(mailConfiguration());
}

setup spring bean configuration for dbcp2 gives "PoolableConnectionFactory not linked to pool. Calling setPool()"

I need to convert dbcp2 java setup code into spring beans
The below code works as expected:
protected void setupDriver(String connectURI, String username, String password) throws ClassNotFoundException, SQLException{
//
// First, we'll create a ConnectionFactory that the
// pool will use to create Connections.
// We'll use the DriverManagerConnectionFactory,
// using the connect string passed in the command line
// arguments.
//
ConnectionFactory connectionFactory =
new DriverManagerConnectionFactory(connectURI, username, password);
//
// Next we'll create the PoolableConnectionFactory, which wraps
// the "real" Connections created by the ConnectionFactory with
// the classes that implement the pooling functionality.
//
poolableConnectionFactory =
new PoolableConnectionFactory(connectionFactory, null);
logger.info("poolableConnectionFactory created");
//
// Now we'll need a ObjectPool that serves as the
// actual pool of connections.
//
// We'll use a GenericObjectPool instance, although
// any ObjectPool implementation will suffice.
//
connectionPool =
new GenericObjectPool<PoolableConnection>(poolableConnectionFactory,getPoolConfig());
logger.info("connectionPool created");
// Set the factory's pool property to the owning pool
poolableConnectionFactory.setPool(connectionPool);
logger.info("connectionPool is set to poolableConnectionFactory");
//
// Finally, we create the PoolingDriver itself...
//
Class.forName("org.apache.commons.dbcp2.PoolingDriver");
driver = (PoolingDriver) DriverManager.getDriver("jdbc:apache:commons:dbcp:");
logger.info("dbcp2 driver is created");
//
// ...and register our pool with it.
//
driver.registerPool(poolName,connectionPool);
logger.info("driver is registered");
//
// Now, we create the PoolingDriver itself,
// passing in the object pool we created.
//
dataSource = new PoolingDataSource<PoolableConnection>(connectionPool);
logger.info("dataSource is created");
//
//Finally we create the JdbcTemplate for sql
//operations in DbDAO class
//
jdbcTemplate = new JdbcTemplate(dataSource);
logger.info("jdbcTemplate is setup");
logger.info("Finally dbcp2 driver setup is completed!");
}
//Pool initial setup values
private GenericObjectPoolConfig getPoolConfig(){
logger.info("Let's create the pool config values");
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setMaxTotal(Integer.parseInt(config.getMaxtotal())); // set number of max connections i.e 25
poolConfig.setMaxWaitMillis(Long.parseLong(config.getMaxwaitmillis())); //ie. wait for a minute = 60000
poolConfig.setMaxIdle(Integer.parseInt(config.getMaxidle())); // set max number of idle connections
/*poolConfig.setTestOnBorrow(true);
poolConfig.setTestOnReturn(true);*/
//poolConfig.setTestWhileIdle(true);
//poolConfig.setTimeBetweenEvictionRunsMillis(10000L);
//poolConfig.setNumTestsPerEvictionRun(5);
//poolConfig.setMinEvictableIdleTimeMillis(5000L);
return poolConfig;
}
And this is the beans.xml
<!-- ============ Trauma Database Connection Pooling Beans Settings ================== -->
<bean id="connectionFactory" class="org.apache.commons.dbcp2.DriverManagerConnectionFactory">
<constructor-arg index="0" value="${tir.jdbc.url}" />
<constructor-arg index="1" value="${tir.jdbc.username}" />
<constructor-arg index="2" value="${tir.jdbc.password}" />
</bean>
<!-- Connection Factory -->
<bean id="poolableConnectionFactory" class="org.apache.commons.dbcp2.PoolableConnectionFactory">
<constructor-arg index="0" ref="connectionFactory"/>
<constructor-arg index="1" > <null/> </constructor-arg>
</bean>
<!-- Pool Configs -->
<bean id="poolConfig" class="org.apache.commons.pool2.impl.GenericObjectPoolConfig">
<property name="maxTotal" value="${pool.maxtotal}"/>
<property name="maxIdle" value="${pool.maxidle}"/>
<property name="minIdle" value="${pool.minidle}"/>
<property name="maxWaitMillis" value="${pool.maxwaitmillis}"/>
</bean>
<!-- Connection Pool -->
<bean id="connectionPool" class="org.apache.commons.pool2.impl.GenericObjectPool">
<constructor-arg index="0" ref="poolableConnectionFactory"/>
<constructor-arg index="1" ref="poolConfig"/>
</bean>
<!-- Datasource gets connection pool -->
<bean id="dataSource" class="org.apache.commons.dbcp2.PoolingDataSource">
<constructor-arg ref="connectionPool"/>
</bean>
<!-- JdbcTemplate bean gets the datasource -->
<bean id="jdbcTemplateTIR" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource" />
</bean>
<!-- Finally, we create our Database object bean -->
<bean id="dbdao" class="edu.uams.dao.impl.DBDAO">
<property name="jdbcTemplate" ref="jdbcTemplateTIR" />
</bean>
<!-- ============= END OF Trauma Database Connection Pooling Settings =========== -->
In both situations I can use the jDBCTemplate objects, however it gives the following warning:
"WARN 0[main] - org.apache.commons.dbcp2.PoolingDataSource.(PoolingDataSource.java:65) PoolableConnectionFactory not linked to pool. Calling setPool() to fix the configuration"
The reason is obvious: In my java code, I setup
poolableConnectionFactory.setPool(connectionPool);
How can I call setPool method from beans?
And how can I also setup this java code in my beans? The constructor of DriverManagerConnectionFactory does not get any constructor of DriverClassName?
// Finally, we create the PoolingDriver itself...
//
Class.forName("org.apache.commons.dbcp2.PoolingDriver");
driver = (PoolingDriver) DriverManager.getDriver("jdbc:apache:commons:dbcp:");
logger.info("dbcp2 driver is created");
//
// ...and register our pool with it.
//
driver.registerPool(poolName,connectionPool);
Wouldn't it be easier if you just used org.apache.commons.dbcp2.BasicDataSource? According to the documentation it provides a "one stop shopping" solution for basic connection pooling.
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.jdbcurl}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="initialSize" value="3"/>
</bean>
I was searching for a solution to exactly this problem given in the question with these specific versions of the libraries. I used the Spring configuration you gave and tweaked it a little bit, and I was able to get it working. Here is how I am using it...
<bean id="poolingDataSourceBean" class="org.apache.commons.dbcp2.PoolingDataSource">
<constructor-arg>
<bean id="genericObjectPoolBean" class="org.apache.commons.pool2.impl.GenericObjectPool">
<constructor-arg>
<bean id="poolableConnectionFactoryBean" class="org.apache.commons.dbcp2.PoolableConnectionFactory">
<constructor-arg index="0">
<bean id="dataSourceConnectionFactoryBean" class="org.apache.commons.dbcp2.DataSourceConnectionFactory">
<constructor-arg>
<bean id="dataSourceBean" class="net.sourceforge.jtds.jdbcx.JtdsDataSource">
<property name="serverName" value="${database.server}"/>
<property name="portNumber" value="${database.port}"/>
<property name="databaseName" value="${database.name}"/>
<property name="user" value="${database.user}"/>
<property name="password" value="${database.password}"/>
</bean>
</constructor-arg>
</bean>
</constructor-arg>
<constructor-arg index="1"><null/></constructor-arg>
</bean>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
You are getting PoolableConnectionFactory not linked to pool. Calling setPool() to fix the configuration" warning because PoolingDataSource has pooling defined while PoolableConnectionFactory does not. With spring you run into circular dependency: PoolableConnectionFactory needs GenericObjectPool that needs PoolableConnectionFactory in constructor.
One way to get around it is to use MethodInvokingFactoryBean (or MethodInvokingBean in spring 4.0+):
<bean id="connectionPoolSetter" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" >
<property name="targetObject" ref="poolableConnectionFactory" />
<property name="targetMethod" value="setPool"/>
<property name="arguments" ref="connectionPool" />
</bean>
then add depends-on attribute to dataSource to make sure connectionPoolSetter is initialized:
<bean id="dataSource" class="org.apache.commons.dbcp2.PoolingDataSource" depends-on="connectionPoolSetter">
<constructor-arg ref="connectionPool"/>
</bean>
Check Pooling Data Source example code:
http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/doc/PoolingDataSourceExample.java?view=markup
By the way, I also have a DBPoolManager which I can manage the pool itself, even printing the stats.. even I haven't find any solution yet, I hope this code will be useful for you..
import java.sql.Connection;
import java.sql.SQLException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
public class DBPoolManager {
private static final Logger logger = LoggerFactory.getLogger(DBPoolManager.class);
private static DBPoolManager dbPoolManager = null;
private static final String POOLNAME = "dbpool";
private DBPoolDriver poolDriver = null;
private String url = null;
private String username = null;
private String password = null;
private static DriverStats stats = null;
protected DBPoolManager(){}
public void init(String url, String username, String password ){
this.url = url;
this.username = username;
this.password = password;
try{
this.poolDriver = new DBPoolDriver(POOLNAME);
}catch(Exception ex){
logger.error(ex.getMessage());
}
}
public static DBPoolManager getInstance(){
if(dbPoolManager == null){
synchronized(DBPoolManager.class){
if(dbPoolManager == null){
dbPoolManager = new DBPoolManager();
logger.info("Created a new singleton of DBPoolManager: "+dbPoolManager);
}
}
}
else{
logger.info("Created the same singleton of DBPoolManager: "+dbPoolManager);
}
return dbPoolManager;
}
public JdbcTemplate getJdbcTemplate(){
return poolDriver.getJdbcTemplate();
}
public Connection getConnection() throws Exception{
return poolDriver.getConnection();
}
public void setupPool() throws ClassNotFoundException, SQLException {
try{
poolDriver.setupDriver(url, username, password);
}
catch(Exception e){
logger.error(e.getMessage());
}
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getMaxTotal() {
return Integer.parseInt(poolDriver.getConfig().getMaxtotal());
}
public void setMaxTotal(int maxTotal) {
poolDriver.getConfig().setMaxtotal(String.valueOf(maxTotal));
}
protected long getMaxWaitMillis() {
return Long.parseLong(poolDriver.getConfig().getMaxwaitmillis());
}
public void setMaxWaitMillis(long maxWaitMillis) {
poolDriver.getConfig().setMaxwaitmillis(String.valueOf(maxWaitMillis));
}
public int getMaxIdle() {
return Integer.parseInt(poolDriver.getConfig().getMaxidle());
}
public void setMaxIdle(int maxIdle) {
poolDriver.getConfig().setMaxidle(String.valueOf(maxIdle));
}
public int getNumActive() throws SQLException{
return poolDriver.getConnectionPool().getNumActive();
}
public int getNumIdle() throws SQLException{
return poolDriver.getConnectionPool().getNumIdle();
}
public void shutDownPool() throws SQLException{
poolDriver.close();
}
public void printDriverStats() throws Exception {
logger.info(Thread.currentThread().getName()+ " NumActive: " + dbPoolManager.getNumActive());
logger.info(Thread.currentThread().getName()+ " NumIdle: " + dbPoolManager.getNumIdle());
}

Categories

Resources