Tuesday, May 21, 2013

Spring bean overriding between projects


Spring bean overriding between projects

Our application is split into two layers. There is the core layer (a layer that is common between multiple projects) and there is the customer/customization layer (layer that is customized per customer). What is needed is to enable the customer layer to override the core dao repository. This means that if in the core there is a dao:
@Repository
public class UserHibernateDao extends GenericHibernateDao<User> implements UserDao {
  public User getUser(){
       return findUniqueByNamedQuery("User.findUserById",id);
  }
}
The customer layer wants to change the getUser method in the core application layer to:
@Repository
public class UserHibernateDaoEx extends UserHibernateDao<User> implements UserDao {
  @Override
  public User getUser(){
       return findUniqueByNamedQuery("User.findUserExById",id);
  }
}
The question is how to override the functionality in spring so that the customer layer bean will be injected into the core classes.
The core classes can use one of the following annotations to inject to UserDao to its classed:
@Autowire, @Resource, @Inject
A summary of the differences between them is as follows (http://blogs.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/):
@Autowired and @Inject
1.     Matches by Type
2.     Restricts by Qualifiers
3.     Matches by Name

@Resource
1.     Matches by Name
2.     Matches by Type
3.     Restricts by Qualifiers (ignored if match is found by name)

The problem is as follows. Client code is as follows:
@Resource
Private UserDao useDao;
The spring component uses the @Repository annotation for the definition. This annotation is used without a name, so the default name is for the core: userHibernateDao and for the customer: userHibernateDaoEx. When spring tries to inject into userDao using the @Resource, it does not find any component by the name of userDao. Spring then searches by type of UserDao, and finds two implementations and cannot inject the component. By giving the same name to both components spring will complain that there are two components with the same id.
The solution is to use an undocumented feature of spring. You cannot define two components with the same id in the same xml file. But if you can define two beans with the same id in two different xml files, the second bean (depends on the order of the files) will be the one that spring uses.
So in the customer layer, instead of using the @Repository annotation on the inherited dao, it needs to be defined in an xml file.
Summary:
We have found a way for the customer layer to inherit and override a spring bean that has been defined in the core layer in such a way that the new bean definied in the customer layer will be used by the core layer itself and the overridden functionality from the customer layer.


No comments:

Post a Comment