Chapter one. Springing into action. This chapter covers. • Spring’s bean container • Exploring Spring’s core modules • The greater Spring ecosystem • What’s new in Spring
1.1 Simplifying Java development Spring simplifies Java development:
• Lightweight and minimally invasive development with POJOs
• Loose coupling through DI and interface orientation
• Declarative programming through aspects and common conventions
• Eliminating boilerplate code with aspects and templates
1.1.2 Injecting dependencies HOW DI WORKS. Listing 1.2 Consider Knight class:
A DamselRescuingKnight can only embark on RescueDamselQuests.
package com.springinaction.knights;
public class DamselRescuingKnight implements Knight { private RescueDamselQuest quest;
public DamselRescuingKnight() { this.quest = new RescueDamselQuest(); }
public void embarkOnQuest() { quest.embark();}}
- This makes a DamselRescuingKnight tightly coupled to a Rescue – DamselQuest.
No unit testing can be accomplished: can’t assert that the quest’s embark() method is called when the knight’s embarkOnQuest() method is called.
Tightly coupled code exhibits “whack-a-mole” bug behavior (fixing one bug results new bugs). On the other hand, …, classes need to know about each other somehow.
Coupling is necessary but should be carefully managed. With DI, objects are given their dependencies at creation time by some third party that coordinates each object in the system.
Listing 1.3 A BraveKnight is flexible enough to take on any Quest he’s given. (Note: BraveKnight, unlike DamselRescuingKnight, doesn’t create his own quest. Instead, he’s given a quest at construction time as a constructor argument).
package com.springinaction.knights;
public class BraveKnight implements Knight { private Quest quest;
public BraveKnight(Quest quest) { this.quest = quest; } public void embarkOnQuest() { quest.embark();}}
Quest is injected (~ construction injection). Quest in a an interface, so BK can embark on any other Quest implementation he’s given. Also to test BraveKnight you can inject it with a mock Quest.
INJECTING A QUEST INTO A KNIGHT Listing 1.5 SlayDragonQuest is a Quest to be injected into BraveKnight.
package com.springinaction.knights; import java.io.PrintStream; public class SlayDragonQuest implements Quest { private PrintStream stream;
public SlayDragonQuest(PrintStream stream) { this.stream = stream; } // notice that rather than lean on System.out .println() like many small getting-started Java samples, SlayDragonQuest more generically asks for a PrintStream through its constructor.// end of comment.
public void embark() { stream.println(“Embarking on quest to slay the dragon!”);}}
How can we give SlayDragonQuest to BraveKnight? And PrintStream to SlayDragonQuest? The act of creating associations between application components is commonly referred to as wiring.
Listing 1.6 XML based configuration (wiring). Injecting a SlayDragonQuest into a BraveKnight:
Note: SlayDragonQuest bean declaration uses the Spring Expression Language to pass System.out.
Listing 1.7 Java-based configuration (alternative to XML shown in listing 1.6).
package com.springinaction.knights.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.springinaction.knights.BraveKnight; import com.springinaction.knights.Knight; import com.springinaction.knights.Quest; import com.springinaction.knights.SlayDragonQuest;
@Configuration public class KnightConfig {
@Bean public Knight knight() { return new BraveKnight(quest()); }
@Bean public Quest quest() { return new SlayDragonQuest(System.out);}}
Benefits of DI : Dependent classes (BK and SDQ) do not know how their dependencies come to be. Spring manages them through configuration. This makes possible to change those dependencies.
SEEING IT WORK Application context loads bean definitions and wires them together.
Listing 1.8 main() creates the Spring application context based on the knights.xml file:
package com.springinaction.knights; import org.springframework.context.support.ClassPathXmlApplicationContext;
public class KnightMain { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“META-INF/spring/knight.xml”); // Loading context
Knight knight = context.getBean(Knight.class); // Get the knight bean knight.embarkOnQuest(); // Use it context.close();}}
Note: knights.xml file knows what the implementations are (BraveKnight and SlayDragonQuest as shown in 1.6).
1.1.3 Applying aspects.
Aspect-oriented programming (AOP) enables you to capture functionality that’s used throughout your application in reusable components. In more detail: Components in system tend to carry responsibilities beyond their core functionality. Logging is prime example. By spreading these concerns across multiple components: • The code that implements the system-wide concerns is duplicated across multiple components. • Your components are littered with code that isn’t alligned with their core functionality. In short, aspects ensure that POJO’s remain plain. AOP modularizes services: this results components are more cohesive (focus on their own specific concerns), completely ignorant of any system services (logging, transaction management, security & so on). Illustrated (without AOP):
Illustrated with AOP:
Listing 1.9 Simplified – Minstrel class that serves as logger to previously shown Knight.class.
package com.springinaction.knights; import java.io.PrintStream;
public class Minstrel { private PrintStream stream;
public Minstrel(PrintStream stream) { this.stream = stream; }
public void singBeforeQuest() { stream.println(“Quest started!”); } public void singAfterQuest() { stream.println(“Quest finished!”);}}
Note: Listing 1.10 illustrates the wrong way of doing things. We omit that for brevity. And proceed to next listing which shows correct way of doing things. Listing 1.11 Declaring the Minstrel as an aspect using XML file. Updated knights.xml:
Declaring Minstrel (~ M.) as an aspect:
- Declare M. as bean .
- Refer to that bean in aop:aspect.
- Declare (using aop:before) before embarkOnQuest() singBeforeQuest() is called. ~ before advice.
- Declare (using aop:before) after embarkOnQuest() singAfterQuest() is called. ~ after advice.
- pointcut-ref attribute refers to a pointcut named embark.
Important:
- Minstrel is still a POJO.
- Minstrel can be applied to BraveKnight, however latter remains unaware of Minstrel existence.
1.1.4 Eliminating boilerplate code with templates Listing 1.12 shows verbose example of JDBC connection, where “the small bit of code that’s specific to querying for an employee is buried in a heap of JDBC ceremony”. Listing 1.13 Templates let your code focus on the task at hand.
public Employee getEmployeeById(long id) { return jdbcTemplate.queryForObject( “select id, firstname, lastname, salary " + // Query “from employee where id=?”, new RowMapper() { public Employee mapRow(ResultSet rs, int rowNum) throws SQLException { Employee employee = new Employee(); employee.setId(rs.getLong(“id”)); employee.setFirstName(rs.getString(“firstname”)); employee.setLastName(rs.getString(“lastname”)); employee.setSalary(rs.getBigDecimal(“salary”)); return employee; } }, id); // Query parameter. }
This version of getEmployeeById() is acutely focused on getting employee from DB. By now author has shown:
- POJO-oriented development
- DI
- Aspects
- Templates
- Bean configuration and aspects in XML based configuration. Ahead Spring container – where you app beans reside.
1.2 Containing your beans In spring app objects live in container (~ c.). Container:
- Creates objects (~ o.)
- Wires o.
- Configures o.
- Manages o. life cycle (from «new» to «finalize»). Spring’s container uses DI to manage the components that make up an application.
Spring has two distinct container implementations:
- Bean factories (org.springframework.beans.factory.BeanFactory) ~ low level.
- Application contexts (org.springframework.context.ApplicationContext)
1.2.1 Working with an application context (~ctxt.) Application context flavors: • AnnotationConfigApplicationContext • AnnotationConfigWebApplicationContext • ClassPathXmlApplicationContext • FileSystemXmlApplicationContext • XmlWebApplicationContext
A) Loading ctxt. using FileSystemXmlApplicationContext:
ApplicationContext context = new FileSystemXmlApplicationContext(“c:/knight.xml”);
B) Similarly ClassPathXmlApplicationContext:
ApplicationContext context = new ClassPathXmlApplicationContext(“knight.xml”);
The difference between these two is that B) look for knight.xml anywhere (including JAR files).
C) Using AnnotationConfigApplicationContext:
ApplicationContext context = new AnnotationConfigApplicationContext( com.springinaction.knights.config.KnightConfig.class);
Note: above KnightConfig.class is configuration class.
1.2.2 A bean’s life
Figure 1.5 shows steps bean factory performs:
- Spring instantiates the bean.
- Spring injects values and bean references into the bean’s properties.
- If the bean implements BeanNameAware,Spring passes the bean’s ID to the setBeanName() method.