Going Beyond Dependency Injection

Preview:

DESCRIPTION

Speaker: Mark Secrist Many developers who are learning the Spring Framework think of it as simply another mechanism for centralized dependency injection. While the framework does handle that responsibility quite well, the framework is so much more. In this session, we'll explore some of the building blocks and patterns used by the core framework as well as many of the other Spring projects. The result is that attendees will gain a better understanding of how to use the Spring Framework and learn how to build their own components that can leverage these same patterns. Topics we'll explore: - What is the benefit of centralized lifecycle management - Programming to interfaces - Leveraging the power of proxies - Using annotations - Understanding the template pattern Dependency injection is one very important part of what the Spring Framework does. However, it is also a collection of very key patterns that we'll explore. - Centralized lifecycle management - Examining the BeanFactoryPostProcessor - Examining the BeanPostProcessor - How to write your own BeanPostProcessor - Programming to interfaces - Benefits of programming to interfaces - loose coupling - Examples of how Spring leverages this mechanism - How to leverage in your own Spring applications - Leveraging the power of proxies - How proxies work in Spring - How Spring uses them - Writing your own proxy-based solution - Using annotations - Examples of how Spring uses annotations - Using your own annotations - Understanding the template pattern - Purpose of template pattern - How Spring uses templates - Creating your own template

Citation preview

© 2013 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Going Beyond Dependency Injection By Mark Secrist

A Bit About Me •  Developer 20+ years

–  C/C++ –  Java/JEE

•  Consultant/Evangelist for Java on HP –  Promoting Java & JEE stack on HP Hardware

•  Technical Trainer –  Core Spring –  Spring Web –  Groovy & Grails –  Gemfire –  Big Data, Hadoop and Pivotal HD

What We’re Going to Cover •  Overview of Spring Lifecycle •  Key Patterns used in Spring

–  Programming to Interfaces –  Proxy Power & AOP –  Templates

Goal: Understand how Spring leverages these patterns and learn how to take advantage of them yourself.

How We’ll Get There 1.  Introduce the concept

2.  Show examples in the Spring Framework

3.  Discuss ways you can take advantage

Overview of Spring Lifecycle

XML Configuration Instructions <beans>" <bean id=“transferService” class=“com.acme.TransferServiceImpl”>" <constructor-arg ref=“accountRepository” />" </bean>"" <bean id=“accountRepository” class=“com.acme.JdbcAccountRepository”>" <constructor-arg ref=“dataSource” />" </bean>"" <bean id=“dataSource” class=“org.apache.commons.dbcp.BasicDataSource”>"

" <property name=“driverClassName” value=“org.postgresql.Driver” />"" <property name=“URL” value=“jdbc:postgresql://localhost/transfer” />"" …"

</bean>"</beans>""

Creating and Using the Application // Create the application from the configuration"ApplicationContext context =" new ClassPathXmlApplicationContext(“application-config.xml”);""// Look up the application service interface"TransferService service = " (TransferService) context.getBean(“transferService”);""// Use the application"service.transfer(new MonetaryAmount(“300.00”), “1”, “2”);""

Using Java Configuration @Configuration"public class AppConfig {" " @Bean(“transferService)" public TransferService transferService() {"

"TransferService service = new TransferServiceImpl();""service.setRepository(repository());""return service;"

}" " " @Bean ! public AccountRepository repository() {" //..." } "}"

ApplicationContext context = new AnnotationConfigApplicationContext(" " " " AppConfig.class);"

Lifecycle of a Spring ApplicationContext

•  When a context is created the initialization phase completes

•  But what exactly happens in this phase?

// Create the application from the configuration"ApplicationContext context = new ClassPathXmlApplicationContext(" “application-config.xml”, " “test-infrastructure-config.xml”");"

Bean Initialization Steps

Bean Ready

For Use

Bean Definitions

Loaded

Post Process Bean

Definitions Instantiate

Beans

Setters Called

Load Bean Definitions

for-each bean ...

BPP BPP Initializer Bean Post Processors

Create and Initialize Beans

BPP BPP

Dependency Injection

Load Bean Definitions •  The Bean Definitions are read (ex, XML, Annotation or

JavaConfig) •  Bean definitions are loaded into the context’s BeanFactory

–  Each indexed under its id

•  Special BeanFactoryPostProcessor beans are invoked –  Can modify the definition of any bean

Bean Definitions Loaded

Post Process Bean

Definitions Load Bean Definitions

XML Style Bean Definition Loading

Application Context <beans> <bean id=“transferService” … <bean id=“accountRepository”… </beans>

application-config.xml

<beans> <bean id=“dataSource” … </beans>

test-infrastructure-config.xml transferService accountRepository

BeanFactory

BeanFactoryPostProcessors

postProcess(BeanFactory)

transferService accountRepository dataSource

Can modify the definition of any bean in the factory before any objects are created

The BeanFactoryPostProcessor •  Useful for applying transformations to groups of bean

definitions –  Before any objects are actually created

•  Several useful implementations are provided by the framework –  You can also write your own –  Implement the BeanFactoryPostProcessor public interface BeanFactoryPostProcessor { public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory); }

A Common Example <beans ...>" <context:property-placeholder location=“db-config.properties” />"" <bean id=“dataSource” class=“com.oracle.jdbc.pool.OracleDataSource”>" <property name=“URL” value=“${dbUrl}” />" <property name=“user” value=“${dbUserName}” />" </bean>"</beans> "

dbUrl=jdbc:oracle:..."dbUserName=moneytransfer-app"

<bean id=“dataSource” class=“com.oracle.jdbc.pool.OracleDataSource”>" <property name=“URL” value=“jdbc:oracle:...” />" <property name=“user” value=“moneytransfer-app” />" </bean>"

But Where’s The BeanFactoryPostProcessor?

•  The namespace is just an elegant way to hide the corresponding bean declaration

<bean class="org.springframework...PropertySourcesPlaceholderConfigurer"> <property name="location" value="db-config.properties"/>

</bean>

<context:property-placeholder location=“db-config.properties” />

Implements BeanFactoryPostProcessor

PropertySourcesPlaceHolderConfigurer was introduced in Spring 3.1. Prior to that, PropertyPlaceholderConfigurer was used instead

Instantiation and Initialization

Initializers Called

After Init

Bean Ready

For Use

Bean Definitions

Loaded

Post Process Bean

Definitions Instantiate

Beans

Setters Called

Create Beans Before

Init

Bean Post-Processor(s)

for-each bean

Bean Post Processing •  There are two types of bean post processors

–  Initializers •  Initialize the bean if instructed •  Activated by init-method or @PostConstruct

–  All the rest! •  Allow for additional richer configuration features •  May run before or after the initialize step

BPP BPP Initializer

Bean Post Processors After Init

Before Init

BeanPostProcessor: A Closer Look •  An important extension point in Spring

–  Can modify bean instances in any way –  Powerful enabling feature

•  Spring provides many implementations –  Not common to write your own (but you can)

public interface BeanPostProcessor { public Object postProcessAfterInitialization(Object bean, String beanName); public Object postProcessBeforeInitialization(Object bean,String beanName); }

Post-processed bean Original bean

Commonly Used Bean Post Processors •  Activated by <context:annotation-config> (or <context:component-scan>)

–  CommonAnnotationBeanPostProcessor – Handles JSR-250 common annotations (Ex @PostConstruct)

–  RequiredAnnotationBeanPostProcessor – Enforces @Required annotation semantics

–  AutowiredAnnotationBeanPostProcessor – Enables recognition of @Autowired annotation

–  ConfigurationClassPostProcessor – Enables Java Configuration support •  Others that can be configured manually

–  PersistenceAnnotationBeanPostProcessor – Enables use of @PersistenceContext in JPA DAO classes

–  PersistenceExceptionTranslationPostProcessor – Performs exception translation for classes annotated with @Repository

Configuration Lifecycle Summary

BeanFacPP

XML config

Annotation config

Bean detection

Bean instantiation and dependency injection BeanPP

@Component scanning

Instantiation & @Autowired

on constructor

Injection of @Autowired

methods & fields

Load xml definitions

Instantiation & constr. injection

Property injection

Java config

Read @Bean method

signatures Call @Bean method implementations

BeanFacPP → BeanFactoryPostProcessor BeanPP → BeanPostProcessor

Demo Time •  Basic configuration •  Lifecycle

Reminder: The BeanPostProcessor Phase

Initializers Called

After Init

Bean Ready

For Use

Bean Definitions

Loaded

Post Process Bean

Definitions Instantiate

Beans

Setters Called

Create Beans Before

Init

Bean Post-Processor(s)

for-each bean

Spring Uses BeanPostProcessors to: •  Perform initialization

–  @PostConstruct annotation enabled by CommonAnnotationBeanPostProcessor

•  Perform validation –  JSR 303 validation enabled by BeanValidationPostProcessor

•  Add behavior –  @Async annotation enabled by

AsyncAnnotationBeanPostProcessor

Writing a Custom BeanPostProcessor •  Problem: Spring MVC provides several ExceptionResolver

strategies enabled by default. Processing order is pre-defined. How do I change the order?

•  Solution: 1.  Manually configure the 3 resolvers and set the order

property 2.  Use a custom BeanPostProcessor to set the order

Pre-configured Exception Resolvers <mvc:annotation-driven /> ""<!-- With this configuration, three ExceptionResolvers are registered:" ExceptionHandlerExceptionResolver – ExceptionResolver for @Exception annotated methods" ResponseStatusExceptionResolver – ExceptionResolver enabling @ResponseStatus mappings" DefaultHandlerExceptionResolver – ExceptionResolver for mapping exceptions to HTTP status codes"-->""

•  Three ExceptionResolvers are automatically registered •  Order they are consulted by DispatcherServlet is pre-defined •  What if you wanted to change the order?

Implementing a BeanPostProcessor class ExceptionMappingBeanPostProcessor {" // Use this field to hold the list of resolvers by name and their desired order" private Properties exceptionResolvers; !" // Implement appropriate getter & setter "! public Object postProcessBeforeInitialization(Object bean, String beanName)"

" " "throws BeansException {" // Check if bean is an instance of ExceptionResolver" // If so, look to see if an order has been defined and assign" // Return the modified bean" "" }"}""

Custom BeanPostProcessor Configuration <mvc:annotation-driven /> ""<bean class="com.pivotal.springone.gbdi.ExceptionResolverOrderPostProcessor">! <property name="exceptionResolvers">! <value>"

"ExceptionHandlerExceptionResolver=2!"ResponseStatusExceptionResolver=3!"DefaultHandlerExceptionResolver=1!

</value>" </property>"</bean>""

Demo Time •  Spring MVC application with default ExceptionResolver

order •  Using a custom BeanPostProcessor

Additional Patterns Used in Spring Framework

•  Programming to Interfaces •  Proxies and AOP •  Templates

Programming to Interfaces

Example: Programming to Interfaces

public class TransferServiceImpl implements TransferService { private AccountRepository accountRepository; public void setAccountRepository(AccountRepository ar) { accountRepository = ar; } … }

public class JdbcAccountRepository implements AccountRepository {" …"}"

Depends on service interface; conceals complexity of implementation; allows for swapping out implementation

Implements a service interface

Benefits of Programming to Interfaces •  Loose Coupling

–  Enables a more pluggable architecture –  Provide out of the box components but support for user provided

implementations •  Improved Reuse

–  A component can often be used wherever interface is expected –  Write once, use multiple places

•  Improved Testability –  Ease of swapping a stub implementation for unit testing

Swapping out Implementations #1

For Jdbc

TransferServiceImpl

JdbcAccountRepository

Spring

(1) new JdbcAccountRepository(…); (2) new TransferServiceImpl(); (3) service.setAccountRepository(repository);

Swapping Out Implementations #2

TransferServiceImpl

JpaAccountRepository

(1) new JpaAccountRepository(…); (2) new TransferServiceImpl(); (3) service.setAccountRepository(repository);

For Jpa

Spring

Swapping Out Implementations #3

TransferServiceImpl

StubAccountRepository

(1) new StubAccountRepository(); (2) new TransferServiceImpl(); (3) service.setAccountRepository(repository);

For Unit Testing

Interfaces and Spring ApplicationContext // Create the application from the configuration"ApplicationContext context =" new ClassPathXmlApplicationContext(“application-config.xml”);""// Fetch a list of bean names of type BeanPostProcessor"String[] beanNamesOfType = " context.getBeanNamesForType(BeanPostProcessor.class);""// Fetch a list of beans of type BeanPostProcessor"Map<String,HandlerExceptionResolver> beansOfType = " context.getBeansOfType(HandlerExceptionResolver.class);""

BeanFactoryUtils provides ability to search nested definitions and ancestor BeanFactory

Programming to Interfaces in Spring •  Core Spring

–  BeanPostProcessor –  BeanFactoryPostProcessor –  PlatformTransactionManager –  Spring remoting (ex RmiProxyFactoryBean, HttpInvokerProxyFactoryBean)

•  Spring MVC –  ViewResolver –  HandlerMapping –  ExceptionResolver (we’ve already seen this one)

•  Spring Security –  AuthenticationManager –  FilterChain

Spring Security – the Big Picture

Security Context

Authentication

(Principal + Authorities)

Secured Resource

Authentication Manager

populates

thread of execution

obtains

AccessDecision Manager

delegates

Config Attributes

describes

consults protects Security Interceptor

Voters

polls

Web Security Filter Configuration

Web User

Servlet

Servlet Container

Spring ApplicationContext

Filter 2

Filter N

DelegatingFilterProxy

FilterChainProxy

Filter 1

Looking at Spring Security <!-- Define the appropriate security namespace and prefix -->"<beans>" <!-- Registers a chain of filters including FilterChainProxy -->" <security:http>" …" </security:http>"" " <!-- Registers the appropriate AuthenticationManager and supporting classes-->" <security:authentication-manager>" <security:authentication-provider>" <security:jdbc-user-service data-source-ref=“dataSource” />" </security:authentication-provider>" </security:authentication-manager>"</beans>""

Customizing the Authentication Process

Easy Customization

The UserDetails Interface •  Interface defines required properties •  Implementation can add additional properties

public interface UserDetails extends Serializable {" Collection<? extends GrantedAuthority> getAuthorities();" String getPassword();" String getUsername();" boolean isAccountNonExpired();" boolean isAccountNonLocked();" boolean isCredentialsNonExpired();" boolean isEnabled();"}"

The UserDetailsService Interface •  Interface defines the contract

•  Implementation is free to use any approach to satisfy the request –  Read from file –  JDBC Database calls –  Hibernate/JPA/MyBatis, etc

•  All the hard work happens here

public interface UserDetailsService { " UserDetails loadUserByUsername(String username) " throws UsernameNotFoundException;"}"

Configuring Custom Authentication •  Configure custom UserDetailsService implementation as a

Spring bean •  Configure AuthenticationProvider to reference it

<!-- Can also be discovered through component scanning -->"<bean id="userDetailsService" class="CustomUserDetailsService” ! p:dataSource-ref=”dataSource” />"<security:authentication-manager>" <security:authentication-provider " user-service-ref="userDetailsService" />"</security:authentication-manager>"

Demo Time •  Implementing custom UserDetails and UserDetailsService

Proxy Power

What is a Proxy? •  A stand-in for the real object

•  Takes full advantage of Programming to Interfaces

Proxy Usage in Spring •  FactoryBeans

–  RmiProxyFactoryBean –  MBeanProxyFactoryBean –  HttpInvokerProxyFactoryBean

•  Spring AOP –  Proxy style weaving using proxies

•  Transactions –  Really just implemented using Spring AOP mechanisms

•  Spring Data –  Exposed via special repository FactoryBean classes

Remoting and the ProxyFactoryBean •  Dynamic proxies generated by Spring communicate with remote

objects •  Simpler to use than traditional RMI stub •  Provides RMI marshalling/unmarshalling + Exception conversion

Basic ProxyFactoryBean Usage •  Define a factory bean to generate proxy

•  Inject it into the client

<bean id=“transferService” class=“org.springframework.remoting.rmi.RmiProxyFactoryBean”> <property name=“serviceInterface” value=“app.TransferService”/> <property name=“serviceUrl” value=“rmi://foo:1099/transferService”/> </bean>

<bean id=“tellerDesktopUI” class=“app.TellerDesktopUI”> <property name=“transferService” ref=“transferService”/> </bean>

TellerDesktopUI only depends on the TransferService interface

Spring AOP in a Nutshell •  Extract cross-cutting concerns into a module that can be

‘woven’ into core functionality before application execution •  Modules

–  AspectJ uses a separate syntax –  AspectJ also supports annotations on Java classes –  Spring AOP leverages AspectJ annotation style

•  Weaving –  Compile-time weaving (AspectJ) –  Load-time weaving (AspectJ) –  Proxy-based weaving (Spring AOP)

A Simple AOP Logging Example

public class SimpleCache implements Cache { private int cacheSize; private DataSource dataSource; public void setCacheSize(int size) { cacheSize = size; } public void setDataSource(DataSource ds) { dataSource = ds; } }

public interface Cache {" public void setCacheSize(int size);"}"

An AOP Example

"public class PropertyChangeTracker {" private Logger logger = Logger.getLogger(getClass());"" " public void trackChange() {" logger.info(“Property about to change…”); " }"}"

@Aspect

@Before(“execution(void set*(*))”)

•  Implemented as a simple Java class… with annotations

•  … and some additional Spring configuration

Spring AOP Configuraiton

<beans>" <aop:aspectj-autoproxy>" <aop:include name=“propertyChangeTracker” />" </aop:aspectj-autoproxy>"" <bean id=“propertyChangeTracker” class=“example.PropertyChangeTracker” />"</beans>"

Configures Spring to apply the @Aspect to your beans

aspects-config.xml

@Configuration"@EnableAspectJAutoProxy"public class AspectConfig {" @Bean(name=”propertyChangeTracker”)" public PropertyChangeTracker tracker() {" return new PropertyChangeTracker();" }"}" Using Java

Using XML

AspectConfig.java

How Aspects are Applied

<<interface>> Cache

setCacheSize()

2. Proxy implements target interface(s)

setCacheSize(2500)

PropertyChange Tracker (aspect)

Simple Cache

Spring AOP Proxy (this)

1. Spring creates a proxy 'weaving' aspect & target

4. Matching advice is executed

5. Target method is executed

Method Interceptor

3. All calls routed through proxy interceptor

Target  

JDK vs CGLib Proxies

•  JDK Proxy –  Interface based

SimpleCache Extra Logic

Spring Proxy

Cache

SimpleCache Extra Logic

Spring Proxy

SimpleCache

•  CGLib Proxy –  subclass based

Target   Target  

extends implements implements

Selecting the Target Methods •  Pointcut Expression

–  An expression used to select the target methods to intercept with AOP functionality

•  Examples

execution(* rewards.*.restaurant.*.*(..)) –  Any methods on any class in a package with one directory

between rewards and restaurant

execution(void send*(String)) –  Any method starting with send that takes a single String

parameter and has a void return type

execution(@javax.annotation.security.RolesAllowed void send*(..)) –  Any void method starting with send that is annotated

with the @RolesAllowed annotation

Spring Transactions in a Nutshell •  In the code

•  In the configuration

public class RewardNetworkImpl implements RewardNetwork {" @Transactional" public RewardConfirmation rewardAccountFor(Dining d) {" // atomic unit-of-work " }"}"

<tx:annotation-driven/> <bean id=“transactionManager” class=”org.springframework.jdbc.datasource.DataSourceTransactionManager”> <property name=“dataSource” ref=“dataSource”/> </bean> <jdbc:embedded-database id="dataSource"> … </jdbc:embedded-database>

Defines a BeanPostProcessor -proxies @Transactional beans

How the Proxy Works •  A BeanPostProcessor may wrap your

beans in a dynamic proxy –  adds behavior to your application

logic transparently

Giving Meaning to Your Annotations •  Problem: I want to selectively audit certain operations

within my application using a marker such as an annotation

•  Solution: 1.  Create an annotation to act as a marker 2.  Define AOP before advice to capture desired information 3.  Write a pointcut expression to select & apply advice

The Target Class public class JpaOrderRepository implements OrderRepository { "" public Order findByOrderId(long id) {" …" }"" @Auditable" public Order save(Order entity) {" ..." }"" @Auditable" public void delete(Order entity) {" ..." }"}"

public @interface Auditable {" // Just a simple interface definition – nothing else required"}"

Mark these methods as candidates to audit

The Advice & Pointcut Expression @Aspect"@Component"public class AuditingAdvice {! private Logger logger = Logger.getLogger(getClass());!" @Before("execution(@com.pivotal.springone.gbdi.Auditable * *(..))")" public void doAudit(JoinPoint jp) {!

"Object target = jp.getTarget();""logger.info("Audit on " + target.getClass().getSimpleName() + " for method " +

jp.getSignature().getName());" }"}"

Match all methods annotated with @Auditable

The Configuration

<aop:aspectj-autoproxy> <aop:include name=“auditingAdvice” </aop:aspectj-autoproxy> <bean id=“auditingAdvice” class=”com.pivotal.springone.AuditingAdvice” />

@Configuration "@EnableAspectJAutoProxy!public class AppConfig {" @Bean" public AuditingAdvice auditingAdvice() {" // Return instantiated and configured AuditingAdvice instance" }"}"

•  Using XML

•  Using JavaConfig

Demo Time •  Creating and using @Auditable with Spring AOP

Templates

Templates in Spring •  Objective

–  Define the outline or skeleton of an algorithm –  Hide away large amounts of boilerplate code

•  Accomplished by –  Providing convenience functions for simplified usage –  Providing Callback classes to expose specific processing

ability

Examples of Templates in Spring •  Core Spring

–  JdbcTemplate –  JmsTemplate –  RestTemplate

•  Spring Data –  GemfireTemplate –  JpaTemplate –  RedisTemplate –  PigTemplate

•  Others –  WebServiceTemplate (Spring Web Services) –  RabbitTemplate (Spring AMQP)

JdbcTemplate Example – convenience functions

•  Acquisition of the connection •  Participation in the transaction •  Execution of the statement •  Processing of the result set •  Handling any exceptions •  Release of the connection

•  Constructed with a JDBC DataSource

int count = template.queryForObject( “SELECT COUNT(*) FROM CUSTOMER”, Integer.class);

All handled by Spring

JdbcTemplate template = new JdbcTemplate(dataSource);

JdbcTemplate With a Callback Class

List results = jdbcTemplate.query(someSql, new RowMapper<Customer>() { public Customer mapRow(ResultSet rs, int row) throws SQLException { // map the current row to a Customer object } });

class JdbcTemplate { public List<Customer> query(String sql, RowMapper rowMapper) { try { // acquire connection // prepare statement // execute statement // for each row in the result set results.add(rowMapper.mapRow(rs, rowNumber)); return results; } catch (SQLException e) { // convert to root cause exception } finally { // release connection

} }

Summary of Callback Interfaces

•  RowMapper –  Best choice when each row of a ResultSet maps to a domain

object •  ResultSetExtractor

–  Best choice when multiple rows of a ResultSet map to a single object

•  RowCallbackHandler –  Best choice when no value should be returned from the

callback method for each row

Demo Time •  Review ResultSetExtractor usage for customized

UserDetailsService demo

Conclusion

In Summary •  Spring is MUCH more than just dependency injection •  Dependency Injection does provide centralized lifecycle, which

enables an easy way add and modify objects uniformly •  Some patterns used by Spring that you can also leverage

–  Programming to Interfaces Enhanced reuse, lose coupling, improved testability

–  Creating and using Proxies Adding incredible power declaratively to your Spring apps

–  Templates Hiding the boilerplate and exposing only what’s necessary

Spring Stack

DI AOP TX JMS JDBC

MVC Testing

ORM OXM Scheduling

JMX REST Caching Profiles Expression

Spring Framework

HATEOAS

JPA 2.0 JSF 2.0 JSR-250 JSR-330 JSR-303 JTA JDBC 4.1

Java EE 1.4+/SE5+

JMX 1.0+ WebSphere 6.1+

WebLogic 9+

GlassFish 2.1+

Tomcat 5+

OpenShift

Google App Eng.

Heroku

AWS Beanstalk

Cloud Foundry Spring Web Flow Spring Security

Spring Batch Spring Integration

Spring Security OAuth

Spring Social

Twitter LinkedIn Facebook

Spring Web Services

Spring AMQP

Spring Data

Redis HBase

MongoDB JDBC

JPA QueryDSL

Neo4j

GemFire

Solr Splunk

HDFS MapReduce Hive

Pig Cascading

Spring for Apache Hadoop

SI/Batch

Spring XD

Learn More. Stay Connected.

•  msecrist@gopivotal.com

•  Talk to us on Twitter: @springcentral •  Find Session replays on YouTube: spring.io/video

Recommended