Spring declare component in xml - java

I am mostly using #Autowired and #Component annotations in my project. However, I am going to use DataSource class for database actions.
So, I use this is in my dispatcher-servlet.xml :
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/market"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</bean>
In my dao class, My setter for the dataSource is :
#Autowired
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
However this is not doing the trick. My jdbcTemplateObject is null.
If I dont use "context:component scan ..." and use classical spring beans instead, without utilizing #Autowired annotation, all works good.
I can use my database. However, I dont want to declare all the beans one by one in my xml file. As the project grows, it is not going to be practical. How can I solve this problem ? Is it possible to declare dataSource in my dispatcher-servlet.xml as component, so #Autowired works on dataSource ?

When you use #Autowired on fields Spring will look for dependencies and inject them right there there is no point if setter method here.
You do not need to worry about how spring is going to inject the dependency. It will take care of complete life cycle.
For more on Spring's Dependecy Injection visit this link.

You have annotated the field with #Autowired which tells spring to inject the dependency directly into the field. If you really want to use the setter annotate the setter with #Autowired instead of the field.
#Autowired
public void setDataSource(DataSource ds) { ... }
However I strongly suggest to not create a JdbcTemplate for each bean that needs one (it is quite heavy to create). The JdbcTemplate is a thread-safe object, once constructed. So instead of creating a new one for each bean that needs one (in the setDataSource method) just create a single JdbcTemplateand inject that.
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
Then in your dao.
#Autowired
private JdbcTemplate jdbcTemplate;
Or what I like to do..
private final JdbcTemplate jdbcTemplate;
#Autowired
public YourRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate=jdbcTemplate;
}
This way you cannot construct an illegal object, whereas with setter based injection you could. While maintaining the possibility to inject one for testing purposes.
Another note, the DriverManagerDataSource is nice for testing but not for production usage, for that use a real connection pool like HikariCP or Tomcat JDBC.

Related

Does datasource need to be in prototype scope in spring jdbc

When we using spring jdbc , first we define a dataSource bean and inject it when creating jdbcTemplate object . What I want to know is do we need to define this dataSource in prototype scope. Unless there is only one dataSource object for whole application . I think this affects to reduce application performance.
Here is how I have defined dataSouce inside spring configuration file.
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/testdb" />
<property name="username" value="root" />
<property name="password" value="123" />
</bean>
In my DAO class I have autowired dataSOurce as below.
#Repository
public class RecordDAOImpl {
JdbcTemplate jdbcTemplate = null;
#Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
}
Let me know what is the best way to define dataSource for spring mvc web application.
What I want to know is do we need to define this dataSource in prototype scope
No we don't need. I guess it wouldn't be good idea, we can use some kind of connection pool datasource and singleton scope bean.
We can also have multiple databases and provide for each own datasource singleton scoped, there is not any problem with that.
Let me know what is the best way to define dataSource for spring mvc web application.
There is nothing wrong with defining your data Sources in xml files (although many devs seem to avoid xml). I like to do it using java config, since I feel like its easier to read.
Depending on driver and database it would look more or less like that:
#Configuration
class DatasourceConfig {
#Bean
DataSource datasource() {
PGPoolingDataSource dataSource = new PGPoolingDataSource();
dataSource.setPassword("pass");
dataSource.setPortNumber(123);
dataSource.setUser("user");
dataSource.setMaxConnections(10);
return dataSource;
}
}

JUnit using HyperSQL to test DAO classes

I did some research on how to test my DAO layer using HyperSQL and I found this question: https://softwareengineering.stackexchange.com/questions/219362/how-to-test-the-data-access-layer
How do I import DBConnection because I tried using hypersql jar and it did not work. In the question from the link I saw this db.url=jdbc:hsqldb:file:src/test/resources/testData;shutdown=true; but I do not know how to use it.
Using JDBC and Spring, in your application you'd be creating a DataSource object, and using that object to create a JdbcTemplate object, which is what you're using to run your JDBC queries. Similar to this example. So in order to use the HSql database, you'd need to change the values used to setup the DataSource bean but only for your unit tests.
Depending on how you're using Spring (annotations, xml config), there's a few ways of doing it. You'll need to create a new configuration bean, or configuration xml file, and then reference it in your unit tests.
For XML, copy over your spring context xml file, and change the DataSource values to something like:
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:file:src/test/resources/testData;shutdown=true;"/>
<property name="username" value="SA"/>
<property name="password" value=""/>
You'll then need to reference this new context config in your unit test. Something like:
#RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "classpath:/test-config.xml"
#ContextConfiguration("/test-config.xml")
public class DAOTests {
#Autowired
private DatabaseDAO dao;
}
With annotations, you'll need to make a new configuration class (you should have one already, a class annotated with #Configuration) and return the appropriate DataSource. Something like this:
#Bean
public DataSource hsqlDataSource(){
return DataSourceBuilder
.create()
.driverClassName("org.hsql.jdbcDriver")
.url("jdbc:hsqldb:file:src/test/resources/testData;shutdown=true;")
.username("SA")
.password("");
.build();
}
You can setup a profile for your configuration (using #Profile("test") annotation), and then specify which profile you want to use in your unit test (#ActiveProfiles("test")). More information here.
Alternatively, you could use the Spring EmbeddedDatabaseBuilder if you're just trying to do a simple DAO Test. There's a tutorial here. It sets you up with a HSql in memory database (as opposed to a file based one), which is very convenient for setting up / tearing down. Just add the bean to your configuration class, and your DAO should pick it up if Spring is injecting the DataSource for you. Example below taken from here
#Bean
public DataSource dataSource() {
// no need shutdown, EmbeddedDatabaseFactoryBean will take care of this
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("db/setup_script.sql")
.build();
}
There's a bit to Spring configuration management. I haven't covered it in much detail in this answer, but look up a few examples and it will start to make sense.

Spring jdbctemplate best way

The spring.xml
<bean id="jdbcTemp" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="portalDataSource" />
</bean>
In class
#Repository
public class DBUtil{
private static final long serialVersionUID = -6203751104015962909L;
#Autowired
JdbcTemplate jdbcTemp;
private static Logger log = Logger.getLogger("scmLogger");
#Transactional(readOnly=true)
public List<Map<String, Object>> getData(String qry, Object[] pAttr){
log.debug("DBUtil.getData() qry "+qry);
List<Map<String, Object>> vList = new ArrayList<Map<String,Object>>();
vList = jdbcTemp.queryForList(qry, pAttr);
return vList;
}
I would like to know if this "jdbcTemplate" is a singleton i.e a single instance in my application. Is this the best way to use or any other way which will be better. Please suggest.
Regards
Adeeb
Though i am not a Spring pro, yes this jdbcTemplate is a singleton. Every bean managed by Spring is singleton unless specified otherwise. And there is nothing wrong with this usage.
When you define a bean in Spring, it has a singleton scope by default.
In your case, you are not defining a different scope so it's singleton.
http://www.tutorialspoint.com/spring/spring_bean_scopes.htm
Yes by default all beans in spring are singleton to make sure you can specify it in bean tag
<bean id="jdbcTemp" class="org.springframework.jdbc.core.JdbcTemplate" scope="singleton">
<property name="dataSource" ref="portalDataSource" />
</bean>
in your class you are auto wiring it, and its the best way to do it. make sure your id in xml and instance variable name is same, in your code its correct jdbcTemp

#Inject and #Autowired not working whereas injecting with setter works

I used #Autowired hundreds of time but today I don't get it, neither #Autowired nor #Inject work in a new project I just created, I get the famous error
Invalid property 'jdbcTemplate' of bean class [com.xxx.SomeDAO]: Bean
property 'jdbcTemplate' is not writable or has an invalid setter
method. Does the parameter type of the setter match the return type of the getter?
When I add a setter for jdbcTemplate in SomeDAO, it works...
applicationContext.xml:
...
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="com.xxx.SomeDAO" class="com.xxx.SomeDAO">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
...
SomeDAO.java:
import org.springframework.jdbc.core.JdbcTemplate;
import javax.inject.Inject;
//import org.springframework.beans.factory.annotation.Autowired;
public class SomeDAO {
#Inject // Doesn't work
//#Autowired // Doesn't work either
private JdbcTemplate jdbcTemplate;
...
/* Works if I add this setter
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}*/
}
What could prevent the injection through the annotation? Thanks!
It is not possible to use field-injection when the bean is created with the XML-context the way you have provided it. Your class is not part of any component-scanning and therefore the annotations does not kick in. Therefore, I can see at least the following options:
1. Use a setter as per your example and remove the #Inject
This is the simplest approach since you got the code and XML prepared. However, this means that your DAO must expose an unnecessary setter-method.
2. Use a constructor that sets your jdbcTemplate field
This is according to me a better alternative but it means that you need to rewrite the XML like this:
<bean id="com.xxx.SomeDAO" class="com.xxx.SomeDAO">
<constructor-arg ref="jdbcTemplate"/>
</bean>
And, your constructor like this:
public class SomeDAO {
private final JdbcTemplate jdbcTemplate;
public SomeDAO(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}
3. Add component-scanning and use #Autowired (or #Inject)
I think that this is the best approach if you fully want to utilize the beauty of Spring's dependency injection capabilities. Add the following to your XML-context:
<context:component-scan base-package="com.xxx"/>
And then the code you previously provided should work. However, you should probably consider avoiding field-injection in favour of constructor-injection. The opinions differ on this matter but I find the code harder to test when field-injection is used.
Constructor injection looks like this:
// The component scanner will find this annotation and create
// the bean (and inject the dependencies)
#Component
public class SomeDAO {
private final JdbcTemplate jdbcTemplate;
#Autowired // enables constructor-injection
public SomeDAO(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}
I personally prefer alternative #3 since it is clean, Java-based (practically no XML required) which also means that it is refactoring friendly, there is no field magic happening and the constructor-based approach makes the code testable and does not expose any unnecessary setter-methods.
A good starting point to learn more about this is the excellent Spring Documentation. There you can find a great explanation for all of the above!

how can get the datasource configuration for spring from persistence.xml?

I need a spring datasource like:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="<driver>"/>
<property name="url" value="<url>" />
<property name="username" value="<user>" />
<property name="password" value="<pass>" />
</bean>
I need to obtain driver, url, user, pass from persistence.xml.
Tanks a lot!
Here is my snippet for doign the same, you will obviously have to use your BasicDataSource instead of the ComboPooledDataSource I use. But they are pretty much the same, replace getDriverClass() with driverClassName, apparently.
#Autowired
private ComboPooledDataSource dataSource;
public String myMethod() {
return dataSource.getDriverClass());
}
Do you want to print it, or use it in your application for connecting to the dB?
If later one is the case, then, create a bean for sessionFactory, set hibernateProperties for the same where you can inject datasource as well.
In java code, autowire sessionFactory object (or set it using a setter method) and call getCurrentSession method for the same.
For getting various attributes, use chained getter methods to return datasource and extract all the details.
Let me know if you face any issue or need more details for the same.

Categories

Resources