Going Beyond Dependency Injection
-
Upload
spring-io -
Category
Technology
-
view
1.797 -
download
3
description
Transcript of Going Beyond Dependency Injection
© 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.
• Talk to us on Twitter: @springcentral • Find Session replays on YouTube: spring.io/video