Wiring dependencies with Spring

Now that we have talked about interfaces, let’s take a look at how to use interfaces in our SpringGreetings application. So far, we don’t have a single interface. Why? Right now we don’t know how the application will evolve, and interfaces aren’t exactly necessary at this point. But we can start thinking about how we would add interfaces by making guesses and assumptions.

Refactoring SpringGreetings application to add interfaces

The only areas in an application where it makes sense to add interfaces are in the Service and Dao layers. It really doesn’t make sense to create interfaces for controllers, domain objects, web forms, or utility classes. So, let’s look at the possibility of making interfaces for GreetingService and GreetingDao.

GreetingService.java

Why would we need an interface for this class? Might there be more than one implementation of this class? Not that we know of. We could create something like this:

public interface GreetingService { }
 
public class DefaultGreetingService implements GreetingService { }

This would be a valid solution if we really want to create an interface just in case we might need it later. But, I don’t believe in creating things that are not necessary. So, let’s leave GreetingService as is for now. We can always refactor it later!

GreetingDao.java

Now, this is a little bit more interesting. I can already imagine having an interface here because GreetingDao might be implemented in a couple different ways. We could implement data access logic with Hibernate, or with another tool like IBatis, or even using a file system. Here is how it could evolve:

public interface GreetingDao { }
 
public class HibernateGreetingDao implements GreetingDao { }
 
public class IBatisHibernateGreetingDao implements GreetingDao { }
 
public class XmlFileGreetingDao implements GreetingDao { }

However this could also go a different way. We may find that we are writing many classes with similar methods, to add, delete, and search. GreetingDao could be a class similar to future classes UserDao, and ColorDao. So we might want to do something like this instead.

public interface GenericCrudDao {
   public void add(Object obj);
   public void delete(Object obj);
   public void findById(String id);
}
 
public class GreetingDao implements GenericCrudDao {
   public void add(Greeting g){ ... }
    ....
}
 
public class UserDao implements GenericCrudDao { 
   ....
}
 
public class ColorDao implements GenericCrudDao { 
   ....
}

Or, we could combine the two to create something like the following:

public class HibernateGreetingDao implements GreetingDao, GenericCrudDao { }

Let’s not make it too complicated just yet. Those are just some ideas to start off with. Now let’s just rename the class GreetingDao to HibernateGreetingDao and convert GreetingDao from a class into an interface.



GreetingDao.java
package com.bitbybit.dao;
 
import java.util.List;
import com.bitbybit.domain.Greeting;
import org.springframework.stereotype.Repository;
 
@Repository
public interface GreetingDao {
 
	public List<Greeting> getAllGreetings();
 
	public void addGreeting(Greeting greeting);
 
}


HibernateGreetingDao.java
package com.bitbybit.dao;
 
import java.util.List;
import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.bitbybit.domain.Greeting;
 
@Repository("hibernateGreetingDao")
public class HibernateGreetingDao implements GreetingDao {
 
	protected static Logger logger = Logger.getLogger("service");
 
	@Autowired
	private SessionFactory sessionFactory;
 
	public List<Greeting> getAllGreetings() {
		Session session = sessionFactory.getCurrentSession();		
		Query q = session.createQuery("select g from Greeting g order by id desc");
		List<Greeting> greetingList = q.list(); 
	        return greetingList;			
	}
 
	public void addGreeting(Greeting greeting) {
		Session session = sessionFactory.getCurrentSession();	
		session.save(greeting);
	}
 
}


GreetingService.java
package com.bitbybit.service;
 
import java.util.List;
import org.apache.log4j.Logger;
import com.bitbybit.dao.GreetingDao;
import com.bitbybit.domain.Greeting;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
@Service
@Transactional
public class GreetingService {
 
	protected static Logger logger = Logger.getLogger("GreetingService");
 
	@Autowired
	@Qualifier(value="hibernateGreetingDao")
	private GreetingDao greetingDao;
 
	public List<Greeting> getAllGreetings() {	
		return greetingDao.getAllGreetings();	
	}
 
	public void addGreeting(Greeting greeting) {	
		greetingDao.addGreeting(greeting);	
	}
 
}

Autowiring dependencies

So you see, we have managed to configure our dependencies using @Autowire notation (no xml!). GreetingService was able to obtain the dependency GreetingDao. But, we still have the qualifier “hibernateGreetingDao” directly in the code which is sort of a dead giveaway. We didn’t want classes to know anything about which dependencies we are using. If we have 200 dependencies like this, we want to easily switch back and forth between “hibernateGreetingDao” and “ibatisGreetingDao” if necessary. Autowiring is good for some things. But it is not great in all cases and can be quite messy at times. It also prevents us from configuring our beans in one central location, which has always been one of the core features of Spring. Don’t get me wrong. Autowiring is ok, just be careful with it.

Configuring dependencies with xml

Xml configuration is sometimes a great option. The downside is of course, that xml is not always as easy to maintain, refactor, and read as java code. But when beans are configured externally in a configuration file, it is possible to swap class implementations at application runtime which is very powerful. Here is how to configure the xml for the GreetingService’s dependency on GreetingDao (HibernateGreetingDao implementation, to be specific):

applicationContext.xml
<?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"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	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
			http://www.springframework.org/schema/mvc 
			http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
 
	<context:annotation-config />
 
	<context:component-scan base-package="com.bitbybit" />
 
	<mvc:annotation-driven /> 
 
	<import resource="datasource-context.xml" />
	<import resource="security-context.xml" />
 
	<bean id="greetingDao" class="com.bitbybit.dao.HibernateGreetingDao" /> 
 
</beans>

And to access the dependency in the GreetingService class, you just have to use the @Resource annotation, which is not the same thing as autowiring. That just locates the resource that is configured in the spring container via xml.

GreetingService.java
package com.bitbybit.service;
 
import java.util.List;
import javax.annotation.Resource;
import org.apache.log4j.Logger;
import com.bitbybit.dao.GreetingDao;
import com.bitbybit.domain.Greeting;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
@Service
@Transactional
public class GreetingService {
 
	protected static Logger logger = Logger.getLogger("GreetingService");
 
	@Resource(name="greetingDao")
	private GreetingDao greetingDao;
	public void setGreetingDao(GreetingDao greetingDao){
		this.greetingDao = greetingDao;
	}
 
	public List<Greeting> getAllGreetings() {	
		return greetingDao.getAllGreetings();
	}
 
	public void addGreeting(Greeting greeting) {
		greetingDao.addGreeting(greeting);
	}
 
}

Configuring dependencies with Java

0 Comments

Post a Comment

(required):