Advantages of Spring (when used for dependency injection):
- separates configuration from the code. Thus the wiring of the application can be modified without recompiling, in theory. Not sure how often this happens in practice.
... and the cons:
- Xml config files are easy to get wrong (no compile time checks obviously)
- Annotations spread through out the code are not terribly visible
- Error messages thrown by the framework can be cryptic at times
There is a simpler alternative. Do away with the Spring container and inject the dependencies manually. All that is needed is a class to inject the dependency, a context which creates the appropriate dependency, and a bit of application code to wire the two together.- Annotations spread through out the code are not terribly visible
- Error messages thrown by the framework can be cryptic at times
A DbReader uses a constructor-injected datasource to retrieve database results.
class DbReader{ DataSource dataSource; DbReader (DataSource dataSource){ this.dataSource= dataSource; } public Object fetch(){ //use the data source to execute a database query }
A Context holds a reference to a data source (mock or real)
class Context { DataSource dataSource; static Context liveContext(){ //get production db data source DataSource dataSource = ...; return new Context(dataSource); } static Context mockContext(){ // get in memory test db data source (or mock) DataSource dataSource = ...; return new Context(dataSource); } Context(DataSource dataSource){ this.dataSource = dataSource; } DataSource getDataSource(){ return dataSource; } }
Project classes inject the datasource associated with a live context in the DbReader constructor.
public static void main(String args[]){ Context ctx = Context.liveContext(); //fetch data from a prod database Object result = new DbReader(ctx.getDataSource()).fetch(); }
while integration tests inject a mock datasource from a mock context.:
@Test public void Test(){ Context ctx = Context.mockContext(); //fetch data from a mock or in-memory db Object result = new DbReader(ctx.getDataSource()).fetch(); //assert that result is as expected... }
Simple, easy to understand (and to debug), compile-time checks in place, no messing around with xml configuration files (or annotations).
...and it's even simpler with the Unsprung project which can help generate the Context class above from a Spring configuration file.
No comments:
Post a Comment