We use Spring's @Configurable (along with regular new operator) which works like a charm. No more anemic domain models. Finally, this is much more object oriented design, isn't it:
Person person = new Person(firstname, lastname);
// weird
peopleService.save(person);
// good (save is @Transactional)
person.save();
Mail mail = new Mail(to, subject, body);
// weird
mailService.send(mail);
// good (send is @Transactional)
mail.send();
We haven't done any performance comparison though. So far, we simply haven't felt the need to do so.
EDIT: that's how the person class would look like:
@Configurable("person")
public class Person {
private IPersonDAO _personDAO;
private String _firstname;
private String _lastname;
// SNIP: some constructors, getters and setters
@Transactional(rollbackFor = DataAccessException.class)
public void save() {
_personDAO.save(this);
}
@Transactional(readOnly = true)
public List<Role> searchRoles(Company company) void{
return _personDAO.searchRoles(this, company);
}
// it's getting more interesting for more complex methods
@Transactional(rollbackFor = DataAccessException.class)
public void resignAllRoles(Company company) {
for (Role role : searchRoles(company)) {
role.resign();
}
}
}
// the implementation now looks like this
personService.getPerson(id).resignAllRoles(company);
// instead of this
roleService.resignAll(personService.searchRoles(personService.getPerson(id), company));
And that's the Spring config:
<context:spring-configured />
<bean id="person" class="org.example.model.Person" lazy-init="true">
<property name="personDAO" ref="personDAO" />
</bean>
Note: as you see, there are still services around, e.g. to search for objects (personService.getPerson(id)) but all methods that operate on a passed object (e.g. a person) are moved to that class itself (i.e. person.save() instead of personService.save(person)). The method itself stays the same and works with any underlying data access layer (pure JDBC, Hibernate, JPA, ...). It has simply moved where it belongs.