SpringInAction CraigWalls
SpringInAction CraigWalls
Framework
Agenda
What is Spring?
Loose coupling with Dependency Injection
Declarative programming with AOP
Eliminating Boilerplate with templates
What is Spring?
What is Spring?
Open source
Apache licensed
An application server
Strategies
Spring 1.0
Spring 2.0
Spring 2.5
Spring 3.0
Spring Web
Flow
BlazeDS
Integration
Spring-WS
Spring Security
Spring-DM
dmServer
Bundlor
tcServer
Spring Batch
Spring Integration
Spring LDAP
Spring IDE / STS
Spring Rich Client
Spring .NET
Spring BeanDoc
Groovy/Grails
Spring community
Forum: http://forum.springframework.org
Issues: http://jira.springframework.org
Extensions:
http://www.springframework.org/extensions
Loose Coupling
with
Dependency
Injection
tool.use();
}
}
tool.use();
}
}
Any better?
tool.use();
} catch (NamingException e) {
} finally {
if(ctx != null) {
try {ctx.close(); }
catch (Exception e) {}
}
}
}
}
Or maybe this...
Dependency injection
DI in Spring
Several options
XML
Annotation-driven
Java-based configuration
XML-based wiring
<bean id="screwdriver"
class="com.habuma.tools.PhillipsScrewdriver" />
<bean id="mechanic"
class="com.habuma.mechanic.AutoMechanic">
<constructor-arg ref="screwdriver" />
</bean>
<bean id="screwdriver"
class="com.habuma.tools.PhillipsScrewdriver" />
<bean id="mechanic"
class="com.habuma.mechanic.AutoMechanic">
<property name="tool" ref="screwdriver" />
</bean>
Annotation-based wiring
<context:component-scan
base-package="com.habuma.mechanic" />
Java-based configuration
@Configuration
public class AutoShopConfig {
@Bean
public Tool screwdriver() {
return new PhillipsScrewdriver();
}
@Bean
public Mechanic mechanic() {
return new AutoMechanic(screwdriver());
}
}
Declarative
Programming
with AOP
Aspects
Spring AOP
Comes in 3 forms
XML-based
Annotation-based
Native AspectJ
AOP Terms
Aspect
Advice
Pointcut
Joinpoint
Logging aspect
public class LoggingAspect {
private static final Logger LOGGER =
Logger.getLogger(LoggingAspect.class);
public logBefore() {
LOGGER.info("Starting withdrawal");
}
public logAfterSuccess() {
LOGGER.info("Withdrawal complete");
}
public logFailure() {
LOGGER.info("Withdrawal failed");
}
}
XML-based AOP
<bean id="loggingAspect"
class="LoggingAspect" />
<aop:config>
<aop:aspect ref="loggingAspect">
<aop:before
pointcut="execution(* *.withdrawCash(..))"
method="logBefore" />
<aop:after-returning
pointcut="execution(* *.withdrawCash(..))"
method="logBefore" />
<aop:after-throwing
pointcut="execution(* *.withdrawCash(..))"
method="logBefore" />
</aop:aspect>
</aop:config>
Annotation-based AOP
@Aspect
public class LoggingAspect {
private static final Logger LOGGER =
Logger.getLogger(LoggingAspect.class);
@Pointcut("execution(* *.withdrawCash(..))")
public void withdrawal() {}
@Before("withdrawal()")
public logBefore() {
LOGGER.info("Starting withdrawal");
}
@AfterReturning("withdrawal()")
public logAfterSuccess() {
LOGGER.info("Withdrawal complete");
}
@AfterThrowing("withdrawal()")
public logFailure() {
LOGGER.info("Withdrawal failed");
}
}
<aop:aspectj-autoproxy />
Annotating transactions
<tx:annotation-driven />
@Transactional(propagation=Propagation.REQUIRED)
public void withdrawCash(double amount) {
updateChecking(amount);
machineBalance -= amount;
insertMachine(machineBalance);
}
@Transactional(propagation=Propagation.SUPPORTS, readOnly=true)
public double inquireBalance(String acctNo) {
// ...
}
Eliminating
Boilerplate
with
Templates
Boilerplate
Exists everywhere
JDBC
JNDI
JMS
...all over JEE...
Recognize this?
public void addSpitter(Spitter spitter) {
Connection conn = null;
PreparedStatement stmt = null;
try {
conn = dataSource.getConnection();
stmt = conn.prepareStatement(SQL_INSERT_SPITTER);
stmt.setString(1, spitter.getUsername());
stmt.setString(2, spitter.getPassword());
stmt.setString(3, spitter.getFullName());
stmt.execute();
} catch (SQLException e) {
// do something...not sure what, though
} finally {
try {
if (stmt != null) {
stmt.close();
}
if (conn != null) {
stmt.close();
}
} catch (SQLException e) {
// I'm even less sure about what to do here
}
}
}
} finally {
if(ctx != null) {
try {
ctx.close();
} catch (NamingException ne) {}
}
}
} finally {
try {
if(session != null) { session.close(); }
if(conn != null) { conn.close(); }
} catch (JMSException ex) {}
}
ConnectionFactory cf =
JDBC template
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<constructor-arg ref="dataSource" />
</bean>
<bean id="spitterDao"
class="com.habuma.spitter.persistence.SimpleJdbcTemplateSpitterDao">
<property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>
Spring-flavored JNDI
<jee:jndi-lookup id="dataSource"
jndi-name="jdbc/SpitterDatasource"
resource-ref="true" />
Spring-flavored JNDI
<bean id="jmsTemplate"
class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory" />
</bean>
Summary
Spring...