Looking back at the history of Spring
framework you will find out that the number of ways you can implement
dependency injection is growing in every release. If you've been
working with this framework for more than a month you'll probably
find nothing interesting in this retrospective article. Nothing
hopefully except the last example in Scala, language that
accidentally works great with Spring.
First there was XML [full source]:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd ">
<bean id="foo" class="com.blogspot.nurkiewicz.Foo">
<property name="bar" ref="bar"/>
<property name="jdbcOperations" ref="jdbcTemplate"/>
</bean>
<bean id="bar" class="com.blogspot.nurkiewicz.Bar" init-method="init"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="org.h2.Driver"/>
<property name="url" value="jdbc:h2:mem:"/>
<property name="username" value="sa"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
</beans>
This simple application only fetches H2 database server time and prints it with full formatting:
public class Foo {
private Bar bar;
private JdbcOperations jdbcOperations;
public String serverTime() {
return bar.format(
jdbcOperations.queryForObject("SELECT now()", Date.class)
);
}
public void setBar(Bar bar) {
this.bar = bar;
}
public void setJdbcOperations(JdbcOperations jdbcOperations) {
this.jdbcOperations = jdbcOperations;
}
}
public class Bar {
private FastDateFormat dateFormat;
public void init() {
dateFormat = FastDateFormat.getDateTimeInstance(FULL, FULL);
}
public String format(Date date) {
return dateFormat.format(date);
}
}
There is something disturbing about
this code. First of all there is surprisingly a lot of XML. It is
still less compared to similar EJB 2.1 application (with minor
changes this code runs on Spring 1.2.6 dating back to 2006), but
it just feels wrong. The public setters are even more disturbing –
why are we forced to expose the ability to override object
dependencies at any time and by anyone? By the way I never really
understood why Spring does not allow injecting dependencies directly
to private fields when <property> tag is used since it is
possible with...
Annotations [full source]
Java 5 and Spring 2.5 brought support
for annotation-driven dependency injection:
<context:annotation-config/> <!-- or even: --> <context:component-scan base-package="com.blogspot.nurkiewicz"/>
Take the first line and you no longer
have to define <property> tags in your XML, only <bean>s.
The framework will pick up standard @Resource annotations. Replace it
with the second line and you don't even have to specify beans in your
XML at all:
@Service
public class Foo {
@Resource
private Bar bar;
@Resource
private JdbcOperations jdbcOperations;
public String serverTime() {
return bar.format(
jdbcOperations.queryForObject("SELECT now()", Date.class)
);
}
}
@Service
public class Bar {
private FastDateFormat dateFormat;
@PostConstruct
public void init() {
dateFormat = FastDateFormat.getDateTimeInstance(FULL, FULL);
}
public String format(Date date) {
return dateFormat.format(date);
}
}
Of course you are not impressed! Nihil
novi. Also we still have to live with XML because we have no
control over 3rd party classes (like data source and JdbcTemplate),
hence we can't annotate them. But Spring 3.0 introduced:
@Configuration [full source]
I've been already exploring the
@Configuration/@Bean
support, so this time please focus on how we start the application
context. Do you see any reference to the XML file? The
applicationContext.xml descriptor is gone completely:
@ComponentScan("com.blogspot.nurkiewicz")
public class Bootstrap {
private static final Logger log = LoggerFactory.getLogger(Bootstrap.class);
@Bean
public DataSource dataSource() {
final BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:");
dataSource.setUsername("sa");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
public static void main(String[] args) {
final AbstractApplicationContext applicationContext = new AnnotationConfigApplicationContext(Bootstrap.class);
final Foo foo = applicationContext.getBean(Foo.class);
log.info(foo.serverTime());
applicationContext.close();
}
}
As you can see Spring came quite a long
road from XML-heavy to XML-free framework. But the most exciting part
is that you can you use whichever style you prefer or even mix them.
You can take legacy Spring application and start using annotations or
switch to XML for god knows what reasons here or there.
One technique I haven't mentioned is
constructor injection. It has some great benefits (see Dependency
Injection with constructors?), like ability to mark
dependencies as final and forbidding to create uninitialized objects:
@Service
public class Foo {
private final Bar bar;
private final JdbcOperations jdbcOperations;
@Autowired
public Foo(Bar bar, JdbcOperations jdbcOperations) {
this.bar = bar;
this.jdbcOperations = jdbcOperations;
}
//...
}
I would love constructor injection,
however once again I feel a bit disappointed. Each and every object
dependency requires (a) constructor parameter, (b) final field and
(c) assignment operation in constructor. We end up with ten lines of
code that don't do anything yet. This chatty code overcomes all the
advantages. Of course no object should have more than (put your
number here) dependencies – and thanks to constructor injection
you immediately see that the
object has too many – but still I find this code introducing too
much ceremony.
Spring constructor injection with Scala [full source]
One feature of Scala fits perfectly into Spring framework: each argument of any Scala object by default creates final field named the same as this argument. What does this mean in our case? Look at Foo class translated to Scala:
@Service
class Foo @Autowired() (bar: Bar, jdbcOperations: JdbcOperations) {
def serverTime() = bar.format(jdbcOperations.queryForObject("SELECT now()", classOf[Date]))
}
Seriously?
But... how? Before we dive into advantages of Scala here, look at the
equivalent Java code as generated by Java decompiler:
@Service
public class Foo implements ScalaObject
{
private final Bar bar;
private final JdbcOperations jdbcOperations;
@Autowired
public Foo(Bar bar, JdbcOperations jdbcOperations)
{
this.bar = bar;
this.jdbcOperations = jdbcOperations;
}
public String serverTime()
{
return this.bar.format(this.jdbcOperations.queryForObject("SELECT now()", Date.class));
}
}
Almost exactly the same code as we
would have written in Java. With all the advantages: dependencies are
final making our services truly immutable and stateless; dependencies
are private and not exposed to the outside world; literally no extra
code to manage dependencies: just add constructor argument, Scala
will take care of the rest.
To wrap things up – you have a wide
range of possibilities. From XML, through Java code to Scala. The
last approach is actually very tempting as it saves you from all the
boilerplate and allows you to focus on business functionality. The
full source code
is available under my GitHub repository, each step is tagged so you
can compare and choose whichever approach you like the most.









Actually you can inject with constructor to beans, and it should be available pre 2.0 era.
ReplyDeleteIn XML you could always use
Spring never promoted constructor injection in favor to setter based one. At least it was my feeling back then
yey, google protected us from malicious spring XML by removing all the tags.
ReplyDeleteThe missing fragment
< constructor-arg ref="dao" />
You are correct, look at the very first code sample, it uses constructor-arg and it works on Spring 1.2.6.
ReplyDeleteNevertheless both constructor-arg XML tag and using @Autowired feel a bit clumsy compared to Scala.
"By the way I never really understood why Spring does not allow injecting dependencies directly to private fields when tag..." That's easy: You can, as long as you're dealing with a "property" as the JavaBean specification defined it. Since the default BeanInfo doesn't, though, you would need to define your own, which essentially nobody does.
ReplyDeleteSpring, as you noted, extended things past the JavaBeans spec in other places, but they tried hard to follow the published specifications when they could. (Including the @Resource method that you referenced, which went through the JSR process.)
Of course Scala is much nicer than Java, and Spring is flexible enough to work very nicely in both languages. So using both together is a double-win. (Though Scala's got support at the language level that reduces the need that people working in Java have, such as dynamic mixing in of traits.)
Nice post. Indeed Spring framework made development of Java related project lot easier. I have recently using spring security and found that its an excellent library for all common needs which an enterprise of web application needs. It has outofbox support for authentication, authorization, session management and security. documented about LDAP authentication using spring security , you may find useful.
ReplyDelete