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"
Related
I'm working on a project in Spring using SpringMVC, i'm using the xml element <bean/> and i want to convert my code to #Bean
spring-bean.xml
<bean id="myDao" class="com.my.dao.EmployeImplDB" init-method="init"></bean>
<bean class="com.my.service.EmployeImplMetier" id="myMetier">
<property name="dao" ref="myDao"></property>
</bean>
how to convert xml to annotation #Bean?
You can write this way
#Repository
class EmployeImplDB{}
#Service
EmployeImplMetier{
#Autowired
EmployeImplDB myDao;
}
#Repository signifies that your bean is a DAO class
#Autowired injects dao class EmployeImplDB in the Service class
Like this:
#Bean(name = "myDao", initMethod = "init")
public EmployeDao myDao() {
EmployeDao eidb = new EmployeImplDB();
return eidb;
}
#Bean(name = "myMetier")
public Metier employeImplDB(EmployeDao myDao) {
Metier metier= new EmployeImplMetier(myDao);
return metier;
}
Note: Presuming that name of EmployeImplDB superclass (interface) is EmployeeDB.
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;
}
}
I have a problem with creating two beans of the same class but different qualifier name. Basically One bean is created with the annotations #Repository and the other one is creating inside #Configuration class.
This is the class that we wont two instances with different datasources:
#Repository ("someDao")
public class SomeDaoImpl implements SomeDao {
private NamedParameterJdbcTemplate jdbcTemplate;
#Autowired
public void setDataSource(DataSource dataSource) {
jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}
}
And then we have a service like this:
#Service
public class SomeServiceImpl implements
SomeService {
#Resource(name = "someDao")
private SomeDao someDao;
#Resource(name = "someDaoAnotherDataSource")
private SomeDao someDaoAnotherDataSource;
}
My first bean is created by the annotation #Repository and the other one I declared in a Spring Configuration class:
#Configuration
#ComponentScan(basePackages = "mypackages")
public abstract class ApplicationRootConfiguration {
#Bean(name = "otherDataSource")
public DataSource otherDataSource() throws NamingException {
...
}
#Bean(name = "someDaoAnotherDataSource")
public SomeDao getSomeDaoAnotherDataSource(#Qualifier("otherDataSource")
DataSource dataSource) throws NamingException {
SomeDao dao = new SomeDaoImpl();
dao.setDataSource(dataSource);
return dao;
}
}
If I run my application, the property someDaoAnotherDataSource in SomeServiceImpl doesn't have my bean declared in the configuration class, it have the bean declared with the annotation Repository.
Also, if I running the same example in XML configuration it works:
<bean id="someDaoAnotherDataSource" class="SomeDaoImpl">
<property name="dataSource" ref="otherDataSource" />
</bean>
Any idea why is not autowiring the proper bean?
Thanks in advance.
Just a thought, instead of injecting the datasource into the method try the following
#Bean(name = "someDaoAnotherDataSource")
public SomeDao getSomeDaoAnotherDataSource() throws NamingException {
SomeDao dao = new SomeDaoImpl();
dao.setDataSource(otherDataSource());
return dao;
}
Although both should work.
Make sure that the name is correct in your #Resource annotation and instead of (or next to) specifing the name of the bean in the #Bean annotation, rename your method to the same.
#Bean(name = "someDaoAnotherDataSource")
public SomeDao someDaoAnotherDataSource() throws NamingException {
SomeDao dao = new SomeDaoImpl();
dao.setDataSource(otherDataSource());
return dao;
}
The name is basically an alias whereas the method name is used as the id of the bean. Could be that resolving isn't looking at aliases correctly. The same in xml would be
<bean id="getSomeDaoAnotherDataSource" name="someDaoAnotherDataSource" class="SomeDaoImpl">
<property name="dataSource" ref="otherDataSource" />
</bean>
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.
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>