Define Spring #PropertySource in xml and use it in Environment - java

In spring JavaConfig, I can define property source and inject into Environment
#PropertySource("classpath:application.properties")
#Inject private Environment environment;
How do I do that if in xml?
I am using context:property-placeholder, and on the JavaConfig class #ImportResource to import the xml. But I cannot retrieve property defined in the properties file using environment.getProperty("xx")
<context:property-placeholder location="classpath:application.properties" />

AFAIK, there is no way of doing this by pure XML. Anyways, here is a little code I did this morning:
First, the test:
public class EnvironmentTests {
#Test
public void addPropertiesToEnvironmentTest() {
ApplicationContext context = new ClassPathXmlApplicationContext(
"testContext.xml");
Environment environment = context.getEnvironment();
String world = environment.getProperty("hello");
assertNotNull(world);
assertEquals("world", world);
System.out.println("Hello " + world);
}
}
Then the class:
public class PropertySourcesAdderBean implements InitializingBean,
ApplicationContextAware {
private Properties properties;
private ApplicationContext applicationContext;
public PropertySourcesAdderBean() {
}
public void afterPropertiesSet() throws Exception {
PropertiesPropertySource propertySource = new PropertiesPropertySource(
"helloWorldProps", this.properties);
ConfigurableEnvironment environment = (ConfigurableEnvironment) this.applicationContext
.getEnvironment();
environment.getPropertySources().addFirst(propertySource);
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
}
And the testContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<util:properties id="props" location="classpath:props.properties" />
<bean id="propertySources" class="org.mael.stackoverflow.testing.PropertySourcesAdderBean">
<property name="properties" ref="props" />
</bean>
</beans>
And the props.properties file:
hello=world
It is pretty simple, just use a ApplicationContextAware bean and get the ConfigurableEnvironment from the (Web)ApplicationContext. Then just add a PropertiesPropertySource to the MutablePropertySources

If what you need is just access the property "xx" of the file "application.properties", you can accomplish that without Java code by declaring the following bean in your xml file:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="application.properties"/>
</bean>
Then if you want to inject the property in a bean just reference it as a variable:
<bean id="myBean" class="foo.bar.MyClass">
<property name="myProperty" value="${xx}"/>
</bean>

Related

'javax.servlet.ServletContext' that could not be found

I have a Springboot application as follows:
#SpringBootApplication
#ImportResource("classpath:/config/applicationContext.xml")
public class TaxBatchMain {
#Autowired
TaxIdService taxIdService;
private static final Logger LOGGER = LogManager.getLogger(TaxBatchMain.class);
public static void main(String[] args) {
new SpringApplicationBuilder(TaxBatchMain.class).web(false).run(args);
TaxBatchMain taxBatchMain = new TaxBatchMain();
}
public TaxBatchMain() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
#PostConstruct
public void checkForTransactions() {
try {
////
String tab = "someother content";
String footer = taxIdService.formatFooter();
////
////
}catch(){
//////////
}
}
}
TaxIdServiceImpl class is as follows:
#Service
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public class TaxIdServiceImpl implements TaxIdService {
#Autowired
private ServletContext servletContext;
private String formatFooter(String footer) {
String[] searchList = {"<ENVIRONMENT_NAME>", "<MS_ENV_NAME>"};
String[] replacementList = {(String) servletContext.getAttribute(ServletContextKey.EMAIL_HOST_NAME.name()),
(String) servletContext.getAttribute(ServletContextKey.MS_EMAIL_HOST_NAME.name())};
return StringUtils.replaceEach(footer, searchList, replacementList);
}
}
Application Context looks like:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"....................///
<context:annotation-config />
<context:property-placeholder location="classpath:/config.properties" />
<util:properties id="configProperties" location="classpath:/config.properties" />
<!-- <context:property-placeholder location="classpath:data/application.properties"/> -->
<context:component-scan base-package="com.tax.main" />
<context:component-scan base-package="com.tax.service" />
<context:component-scan base-package="com.tax.model" />
<context:component-scan base-package="com.tax.mapper" />
<context:component-scan base-package="com.tax.util" />
/////
When I run the main class i get foll. error
APPLICATION FAILED TO START
Description:
Field servletContext in com.tax.service.TaxIdServiceImpl required a bean of type 'javax.servlet.ServletContext' that could not be found.
Action:
Consider defining a bean of type 'javax.servlet.ServletContext' in your configuration.
Try enabling webEnvironment. It appears your SpringApplicationBuilder is not enabled with web environment.
new SpringApplicationBuilder(TaxBatchMain.class).web(true).run(args);
Since you are using spring-boot you can consider using Annotation based approach rather xml based.

Autowiring xml bean into #Configuration Class

I use generally xml configuration in my Spring project under the three files:
applicationContext.xml:
This file contains the main xml configuration: component scan, annotation-config and also an include of two other xml configuration files:
applicationContext-db.xml
This file contains all database beans: dataSource, SessionFactory, ...
applicationContext-security.xml
This file contains all spring security config.
I need to use also Spring Security ACL, for this I created a configuration class:
AclMethodSecurityConfiguration.java
package com.medkhelifi.tutorials.todolist.conf;
/**
/* all imports goes here.
**/
#Configuration
#ImportResource({"classpath*:conf/applicationContext-db.xml"})
#EnableGlobalMethodSecurity (prePostEnabled = true, securedEnabled = true)
public class AclMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
#Autowired
DataSource dataSource;
#Bean
public MethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
AclPermissionEvaluator permissionEvaluator = new AclPermissionEvaluator(aclService());
expressionHandler.setPermissionEvaluator(permissionEvaluator);
return expressionHandler;
}
#Bean
public JdbcMutableAclService aclService() {
return new JdbcMutableAclService(dataSource, lookupStrategy(), aclCache());
}
#Bean
public AclAuthorizationStrategy aclAuthorizationStrategy() {
return new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_ADMIN"));
}
#Bean
public PermissionGrantingStrategy permissionGrantingStrategy() {
return new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger());
}
#Bean
public EhCacheBasedAclCache aclCache() {
return new EhCacheBasedAclCache(
aclEhCacheFactoryBean().getObject(),
permissionGrantingStrategy(),
aclAuthorizationStrategy()
);
}
#Bean
public EhCacheFactoryBean aclEhCacheFactoryBean() {
EhCacheFactoryBean ehCacheFactoryBean = new EhCacheFactoryBean();
ehCacheFactoryBean.setCacheManager(aclCacheManager().getObject());
ehCacheFactoryBean.setCacheName("aclCache");
return ehCacheFactoryBean;
}
#Bean
public EhCacheManagerFactoryBean aclCacheManager() {
return new EhCacheManagerFactoryBean();
}
#Bean
public LookupStrategy lookupStrategy() {
return new BasicLookupStrategy(
dataSource,
aclCache(),
aclAuthorizationStrategy(),
new ConsoleAuditLogger());
}
}
My problem is the datasource autowired into Configuration file is null, I don't kwno if i missed something.
My XMLs files are all under: src/main/resources/conf/
There is my datasource bean definition in applicationContext-db.xml
<!-- DATASOURCE -->
<bean name="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.driver}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
</bean>
I already used this bean into Sessionfactory bean defined in the same applicationContext-db.xml file.
PS: When I remove the extended class GlobalMethodSecurityConfiguration my datasource is defined, but I need this org.springframework.security.config.annotation.method.configurationclass to set up my Spring Security ACL configuration.
I found a way to define my datasource bean by using the BeanFactoryAware interface.
BeanFactoryAware is used to inject the BeanFactory object. This way we get access to the BeanFactory which created the object.
#EnableGlobalMethodSecurity (prePostEnabled = true, securedEnabled = true)
#Configuration
#ImportResource({"classpath:/conf/applicationContext-db.xml"})
public class AclMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration implements BeanFactoryAware {
DataSource dataSource;
#Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.dataSource = beanFactory.getBean("dataSource", DataSource.class);
}
// rest of code goes here
}
I read that if we use this technic that means we are doing something wrong, I'll continue searching for a proper solution.
Please rename your bean as name="dataSource"

Hibernate4 configuration without xml files - sessionFactory is null

I have a web project working with Spring3 and Hibernate4 and now I want to test the DAOs without using the xml files. To do so I have created a class that creates a LocalSessionFactoryBean with the data contained in the application's xml file and a simple test class.
However, the sessionFactory returned by localSessionFactoryBean.getObject() is null. I have been looking at some examples like this and they have the same problem when I modify them to run without Spring. Do you have any idea?
This is the code that prepares the sessionFactory:
#Configuration
#Transactional
#EnableTransactionManagement
#ComponentScan({ "com.company" })
public class HibernateInitializator {
public SessionFactory getSessionFactory() {
Properties hibernateProperties = getHibernateProperties();
DataSource dataSource = getDatasourceConfiguration();
LocalSessionFactoryBean localSessionFactoryBean = generateSessionFactoryBean(new String[] { "com.company" },
dataSource, hibernateProperties);
SessionFactory sessionFactory = localSessionFactoryBean.getObject();
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory);
return sessionFactory;
}
private DataSource getDatasourceConfiguration() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/dbName");
dataSource.setUsername("username");
dataSource.setPassword("password");
return dataSource;
}
private static LocalSessionFactoryBean generateSessionFactoryBean(String[] basePackage, DataSource dataSource,
Properties hibernateProperties) {
LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
localSessionFactoryBean.setDataSource(dataSource);
localSessionFactoryBean.setPackagesToScan(basePackage);
localSessionFactoryBean.setHibernateProperties(hibernateProperties);
return localSessionFactoryBean;
}
private static Properties getHibernateProperties() {
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
hibernateProperties.put("hibernate.show_sql", false);
hibernateProperties.put("hibernate.generate_statistics", false);
hibernateProperties.put("hibernate.hbm2ddl.auto", "update");
hibernateProperties.put("hibernate.use_sql_comments", false);
return hibernateProperties;
}
}
And this is a simple test class that uses it:
public class GenericDAOHibernateTest {
private GenericDAOHibernate dao;
#BeforeTest
private void testInitialization() {
dao = new GenericDAO();
HibernateInitializator initializator = new HibernateInitializator();
SessionFactory sessionFactory = initializator.getSessionFactory();
dao.setSessionFactory(sessionFactory);
}
#Test(description = "Checks that returns the user list ")
public void shouldReturnsUserList() throws SQLException, Exception {
List<Object[]> openResultSetList = dao.doSomeOperation();
...
}
}
Try adding this line
localSessionFactoryBean.afterPropertiesSet();
in the method after the properties of LocalSessionFactoryInstance has been set. Your method will be as
private static LocalSessionFactoryBean generateSessionFactoryBean(String[] basePackage, DataSource dataSource,
Properties hibernateProperties) {
LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
localSessionFactoryBean.setDataSource(dataSource);
localSessionFactoryBean.setPackagesToScan(basePackage);
localSessionFactoryBean.setHibernateProperties(hibernateProperties);
// Added the below line
localSessionFactoryBean.afterPropertiesSet();
return localSessionFactoryBean;
}
This link may add more insight to the problem.
As per Documentation,
public void afterPropertiesSet() throws IOException
Invoked by a BeanFactory after it has set all bean properties supplied (and satisfied BeanFactoryAware and ApplicationContextAware).
This method allows the bean instance to perform initialization only possible when all bean properties have been set and to throw an exception in the event of misconfiguration.
In your case, I think you need to call it in your code manually.
I asked how to do it without an xml file and the solution proposed by #Octopus fixed the problem I had. However, after fixing that arised other errors with transactions... so I decided to do it in a different way that doesn't interfere with the application.
To do so I created a simplified version of the xml file in /src/test/resources removing many configurations like c3p0's one and hardcoding the values so that the tests won't fail if the application's properties files are changed.
This is the content of the xml file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" ...>
<!-- Spring DataSource -->
<bean id="testDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/testDatabase" />
<property name="username" value="testUsername" />
<property name="password" value="testPassword" />
</bean>
<!-- Hibernate 4 SessionFactory -->
<bean id="testSessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" p:dataSource-ref="testDataSource">
<property name="packagesToScan" value="com.company" />
<property name="hibernateProperties">
<props>
<!-- Hibernate basic configuration -->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.generate_statistics">false</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.use_sql_comments">false</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="dataSource" ref="testDataSource" />
<property name="sessionFactory" ref="testSessionFactory" />
</bean>
<context:annotation-config />
<tx:annotation-driven />
<!-- Initialization of DAOs -->
<bean id="userDao" name="userDao" class="com.company.dao.UserDAOHibernate" autowire="byName"/>
...
</beans>
In the test class I have used JUnit because I haven't managed to do it with TestNG although I tried extending AbstractTestNGSpringContextTests. I would recommend using JUnit 4.4 version instead of newer versions because it has classes like AssumptionViolatedException that are used by spring-test 2.5.
This is the code:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "file:src/test/resources/application-config-tests.xml" })
public class SimpleUserDAOTest {
#Autowired
private UserDAO dao;
#Autowired
private SessionFactory sessionFactory;
#Before
public void setUp() throws Exception {
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(sessionFactory.openSession()));
}
#After
public void tearDown() throws Exception {
SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
SessionFactoryUtils.closeSession(sessionHolder.getSession());
}
#Test
public void shouldReturnActiveUsers() {
List<User> userList = dao.getActiveUsers();
...
}
}
I hope this helps you in your future developments
When you are using Spring 3+ and Hibernate 4, I would suggest you a better way, define everything as annotated Spring Configurations and this work smoothly.
Below is the detailed code, just copy and paste in your project and you can Autowire SessionFactory anywhere in the DAO layer or any spring component :)
#Configuration
#Import(HibernateConfig.class)
#EnableWebMvc
#ComponentScan(basePackages = "com.mypackages")
public class WebConfig extends WebMvcConfigurationSupport {
#Override
protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.parameterName("mediaType").ignoreAcceptHeader(true)defaultContentType(MediaType.APPLICATION_JSON).mediaType("xml", MediaType.APPLICATION_XML).mediaType("json", MediaType.APPLICATION_JSON);
}
#Bean(name = "validator")
public Validator validator() {
return new LocalValidatorFactoryBean();
}
}
Then define a HibernateConfig as below:
#Configuration
#EnableTransactionManagement
#EnableAspectJAutoProxy
#PropertySource({"classpath:app.properties"})
#ComponentScan(basePackages = "com.mypackages")
public class HibernateConfig {
#Value(Constants.HIBERNATE_DIALECT)
private String hibernateDialect;
#Autowired
private DataSource dataSource;
#Bean(name = "appProperty")
public static PropertySourcesPlaceholderConfigurer appProperty() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean(name = "sessionFactory")
public SessionFactory getSessionFactory() throws Exception {
Properties properties = new Properties();
properties.put(Constants.HIBERNATE_DIALECT_PROPERTY,
hibernateDialect);
properties.put(Constants.HIBERNATE_SHOW_SQL_PROPERTY,
"false");
properties
.put(Constants.HIBERNATE_CURRENT_SESSION_CONTEXT_CLASS_PROPERTY,
"thread");
properties
.put("dynamic-update","true");
LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
factory.setPackagesToScan(new String[] { Constants.DOMAIN_MODEL_PACKAGE });
factory.setDataSource(dataSource);
factory.setHibernateProperties(properties);
factory.afterPropertiesSet();
return factory.getObject();
}
#Bean(name = "transactionManager")
public HibernateTransactionManager getTransactionManager() throws Exception {
return new HibernateTransactionManager(getSessionFactory());
}
}
Then define a JndiConfig as below:
#Configuration
public class JndiConfig {
#Value(Constants.DRIVER_CLASS)
private String driverClassName;
#Value(Constants.DATABASE_URL)
private String databaseURL;
#Value(Constants.USER_NAME)
private String username;
#Value(Constants.PASSWORD)
private String password;
#Value(Constants.MAX_ACTIVE)
private int maxActive;
#Value(Constants.MAX_IDLE)
private int maxIdle;
#Value(Constants.MAX_WAIT)
private long maxWait;
#Value(Constants.MIN_IDLE)
private int minIdle;
#Value(Constants.INITIAL_SIZE)
private int initialSize;
#Value(Constants.TIME_BETWEEN_EVICTION)
private long timeBetweenEvictionRunsMillis;
#Bean(name = "dataSource")
public DataSource dataSource() throws Exception {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(databaseURL);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setTestOnBorrow(true);
dataSource.setTestWhileIdle(true);
dataSource.setValidationQuery("SELECT 1");
dataSource.setMaxActive(maxActive);
dataSource.setMaxIdle(maxIdle);
dataSource.setMaxWait(maxWait);
dataSource.setMinIdle(minIdle);
dataSource
.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
return dataSource;
}
}

NullPointerException: #Autowired does not set field

I am learning SPRING and this is not web application code; I am getting NLP while using #Autowired annotation in field level.
Q1) Please help what is wrong?
Q2) If i have #Scope annotation at the class level; do i still need at XML bean level?
#Controller
#Scope(value = BeanDefinition.SCOPE_SINGLETON)
public class StreamingController implements psConsolePortListener.Implementation{
#Autowired
#Qualifier("scMgr")
private StreamingControllerManager streamingMgr = null;
public static void main(String[] args) {
logger.info("StreamingController testing");
XmlBeanFactory factory = new XmlBeanFactory (new ClassPathResource(BEAN_FILE));
StreamingController obj = (StreamingController) factory.getBean("streamingController");
obj.streamingMgr.test();
}
}
#Service
#Scope(value = BeanDefinition.SCOPE_SINGLETON)
#Qualifier("scMgr")
public class StreamingControllerManager {
/** Logger */
private static final Logger logger = LoggerFactory.getLogger(StreamingControllerManager.class);
private StreamingControllerManager(){
logger.info("StreamingControllerManager is called!!");
}
public void test(){
logger.info("StreamingControllerManager test!!");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<context:annotation-config />
<context:component-scan base-package="com.xxx.streamingController"/>
<bean id="scMgr" class="com.xxx.streamingController.StreamingControllerManager">
</bean>
<bean id="streamingController" class="com.xxx.streamingController.StreamingController">
</bean>
</beans>
Output:
Exception in thread "main" java.lang.NullPointerException
at com.pactolus.streamingController.StreamingController.main(
Use an ApplicationContext instead of a BeanFactory.
public static void main(String[] args) {
logger.info("StreamingController testing");
ApplicationContext ctx = new ClassPathXmlApplicationContext(BEAN_FILE);
StreamingController obj = (StreamingController) ctx.getBean("streamingController");
obj.streamingMgr.test();
}
Also remove <context:annotation-config /> that is already impllied by <context:component-scan /> and remove the bean declarations. You are using component-scanning so no need to declare the beans.
Basically leaving you with.
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<context:component-scan base-package="com.xxx"/>
</beans>

using Spring JdbcTemplate - injecting datasource vs jdbcTemplate

As per Spring documentation,
the steps to use Spring JdbcTemplate is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- Scans within the base package of the application for #Components to configure as beans -->
<context:component-scan base-package="org.springframework.docs.test" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<context:property-placeholder location="jdbc.properties"/>
</beans>
And then,
#Repository
public class JdbcCorporateEventDao implements CorporateEventDao {
private JdbcTemplate jdbcTemplate;
#Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
// JDBC-backed implementations of the methods on the CorporateEventDao follow...
}
Basically, the JdbcTemplate is created inside the Component class using the setter for datasource.
Is there anything wrong with doing it this way instead so that there is exactly ONE instance of jdbcTemplate in the application?
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSource"
/>
And then injecting the jdbcTemplate itself directly into the Component
#Repository
public class JdbcCorporateEventDao implements CorporateEventDao {
#Resource("jdbcTemplate")
private JdbcTemplate jdbcTemplate;
// JDBC-backed implementations of the methods on the CorporateEventDao follow...
}
Is there a reason why the jdbcTemplate itself must not be injected into the component class directly?
SGB
You can do what you want. The javadoc of JdbcTemplate even clearly says it:
Can be used within a service implementation via direct instantiation with a DataSource reference, or get prepared in an application context and given to services as bean reference.
In the spring-context.xml add the following and
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
and directly you can use jdbcTemplate by autowiring like
#Autowired JdbcTemplate jdbcTemplate;
example:
this.jdbcTemplate.query("select * from ******",new RowMapper());
You can also do it like
#Configuration
#Import({PersistenceConfig.class})
#ComponentScan(basePackageClasses = {
ServiceMarker.class,
RepositoryMarker.class }
)
public class AppConfig {
/**
* To resolve ${} in #Values, you must register a static PropertySourcesPlaceholderConfigurer in either XML or
* annotation configuration file.
*/
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
}
PersistenceConfig
#Configuration
#PropertySource(value = { "classpath:database/jdbc.properties" })
#EnableTransactionManagement
public class PersistenceConfig {
#Autowired
private Environment env;
/**
* The #Bean annotation is used to declare a Spring bean and the DI requirements. The #Bean annotation is equivalent to
* the <bean> tag, the method name is equivalent to the id attribute within the <bean> tag.
*
* <bean id="mySqlDataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"
p:driverClassName="${jdbc.mysql.driverClassName}"
p:url="${jdbc.mysql.url}"
p:username="${jdbc.mysql.username}"
p:password="${jdbc.mysql.password}" />
*
* #return
*/
#Bean(destroyMethod = "close")
public DataSource mySqlDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.mysql.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.mysql.url"));
dataSource.setUsername(env.getProperty("jdbc.mysql.username"));
dataSource.setPassword(env.getProperty("jdbc.mysql.password"));
return dataSource;
}
#Bean(destroyMethod = "close")
public DataSource ls360DataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.ls360.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.ls360.url"));
dataSource.setUsername(env.getProperty("jdbc.ls360.username"));
dataSource.setPassword(env.getProperty("jdbc.ls360.password"));
return dataSource;
}
}
MySqlDaoImpl
#Repository
public class MySqlDaoImpl implements MySqlDao{
private static final Logger logger = LogManager.getLogger();
#Inject
private DataSource mySqlDataSource;
private JdbcTemplate mySqlJdbcTemplate;
#PostConstruct
public void afterPropertiesSet() throws Exception {
if (mySqlDataSource == null) {
throw new BeanCreationException("Must set mySqlDataSource on " + this.getClass().getName());
}
this.mySqlJdbcTemplate = new JdbcTemplate(mySqlDataSource);
}
#Override
public void callStoredProcedure(String storedProcedureName, Map<String, Object> inParamMap) throws Exception {
SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(mySqlJdbcTemplate).withProcedureName(storedProcedureName);
SqlParameterSource in = new MapSqlParameterSource(inParamMap);
logger.info("Calling stored Procedure: " + storedProcedureName);
Map<String, Object> simpleJdbcCallResult = simpleJdbcCall.execute(in);
logger.info("Stored Procedure Result: " + simpleJdbcCallResult);
}
}
Main
public static void main(String[] args ) {
try (GenericApplicationContext springContext = new AnnotationConfigApplicationContext(AppConfig.class)) {
MySQLDao mySqlDao = springContext.getBean(MySQLDaoImpl.class);
try {
Map<String, Object> inParamMap = new HashMap<String, Object>();
inParamMap.put("iCourseId", 1);
mySqlCourseRenewalDao.callStoredProcedure("usp_processCourseRenewal", inParamMap);
} catch (Exception e) {
logger.error("Exception occurs", e);
}
} catch (Exception e) {
logger.error("Exception occurs in loading Spring context: ", e);
}
}
Thanks
There's nothing technically wrong with injecting and sharing JdbcTemplate in place of the underlying DataSource.
However, there are some design drawbacks to sharing JdbcTemplate, which may favor injecting DataSource instead:
Use of JdbcTemplate is an implementation detail of the DAO, and we like to keep those details hidden
JdbcTemplate is lightweight, so sharing it for efficiency is likely a premature optimization
Sharing a JdbcTemplate isn't risk-free as it has some mutable state (in addition to mutable state in the underlying DataSource)
That's assuming the the typical case where JdbcTemplate is used with its default configuration (fetchSize, maxRows, etc). If configuration is required, that may drive the design in a particular direction, e.g. a shared pre-configured JdbcTemplate injected from context, or even multiple JdbcTemplate instances owned by a single DAO.

Categories

Resources