1. Tailoring Spring for Custom Usage
• Josh Long, SpringSource, a division of VMware
1
Thursday, January 24, 13
2. About Josh Long (龙
之春)
Spring Developer Advocate
twitter: @starbuxman
weibo: @springsource
josh.long@springsource.com
2
Thursday, January 24, 13
3. Agenda
Explore the value of a framework
Exploit some of the lesser known, but powerful, extension
hooks in the core Spring framework
QA
3
Thursday, January 24, 13
4. Spring’s aim:
bring simplicity to java development
data
web tier integration
batch access
& service tier & mobile
processing / NoSQL /
RIA messaging
Big Data
The Spring framework
the cloud: lightweight traditional
CloudFoundry WebSphere
tc Server
VMForce JBoss AS
Tomcat
Google App Engine WebLogic
Jetty
Amazon Web Services (on legacy versions, too!)
4
Thursday, January 24, 13
5. The Spring ApplicationContext
• Spring Manages the beans you tell it to manage
– use annotations (JSR 250, JSR 330, native)
– XML
– Java configuration
– component scanning
• You can of course use all of them! Mix ‘n match
• All configuration styles tell the ApplicationContext how to
manage your beans
5
Thursday, January 24, 13
6. Spring, a walking tour
• Demos:
– introduce the tool chain
– how to “setup” Spring
– basic dependency injection
• annotations (JSR 250, JSR 330, native)
• xml
• java configuration
6
Thursday, January 24, 13
12. The Open/Closed Principle
"software entities (classes, modules, functions, etc.) should
be open for extension, but closed for modification”
-Bob Martin
12
Thursday, January 24, 13
13. Working with Lots of Beans
• One way to selectively augment beans at the lower level:
– BeanPostProcessor
• are regular beans and are run after the configured beans have
been created, but before the context is finished setting up
– BeanFactoryPostProcessor
• is run before any of the beans definitions are realized
• comes before BPP
• A more natural alternative is Spring’s AOP support
– built on top of AspectJ
– provides a very convenient, powerful way to solve cross
cutting problems
13
Thursday, January 24, 13
14. Spring, a walking tour
• Demos:
– Bean*PostProcessor
– AspectJ
14
Thursday, January 24, 13
15. Life Cycles
• Life Cycles for different folks
– “safe and consistent” - use the interfaces
• InitializingBean, DisposableBean
• correspond to init-method and destroy-method attributes
– Simple and component-centric : use the annotations
• @PostConstruct, @PreDestroy
• correspond to init-method and destroy-method attributes
– More power: SmartLifecycle
• gives you the ability to dynamically start and stop beans in a
certain order as well as to query whether the bean’s been
started or not.
15
Thursday, January 24, 13
16. Scopes
• Spring beans have scopes
– default: singleton
– can be:
• prototype
• HTTP session
• HTTP request
• HTTP application (servlet, basically)
• “step” in Spring batch
• thread-local
• Spring Web Flow “flow” scoped
• Spring Web Flow “conversation scoped”
• Spring Web Flow “view” scoped (in JSF)
• Activiti BPMN2 process-scoped
16
Thursday, January 24, 13
17. Scopes
– Implement o.s.beans.factory.config.Scope
– register the scope with a
o.s.beans.factory.config.CustomScopeConfigurer
public interface Scope {
Object get(String name, ObjectFactory<?> objectFactory);
Object remove(String name);
void registerDestructionCallback(String name, Runnable callback);
Object resolveContextualObject(String key);
String getConversationId();
}
17
Thursday, January 24, 13
18. Scopes
– Implement o.s.beans.factory.config.Scope
– register the scope with a
o.s.beans.factory.config.CustomScopeConfigurer
public interface Scope {
Object get(String name, ObjectFactory<?> objectFactory); map-like lookup
of beans in a
Object remove(String name); given scope
void registerDestructionCallback(String name, Runnable callback);
Object resolveContextualObject(String key);
String getConversationId();
}
17
Thursday, January 24, 13
19. Scopes
– Implement o.s.beans.factory.config.Scope
– register the scope with a
o.s.beans.factory.config.CustomScopeConfigurer
public interface Scope {
Object get(String name, ObjectFactory<?> objectFactory); map-like lookup
of beans in a
Object remove(String name); given scope
void registerDestructionCallback(String name, Runnable callback);
Object resolveContextualObject(String key); well known beans like the
HttpServletRequest ‘request’ for
String getConversationId(); ‘request’ scope
}
17
Thursday, January 24, 13
20. Scopes
– Implement o.s.beans.factory.config.Scope
– register the scope with a
o.s.beans.factory.config.CustomScopeConfigurer
public interface Scope {
Object get(String name, ObjectFactory<?> objectFactory); map-like lookup
of beans in a
Object remove(String name); given scope
void registerDestructionCallback(String name, Runnable callback);
Object resolveContextualObject(String key); well known beans like the
HttpServletRequest ‘request’ for
String getConversationId(); ‘request’ scope
}
null, or storage specific
‘conversation’ ID
17
Thursday, January 24, 13
21. Spring, a walking tour
• Demos:
– life cycle callbacks
– scopes
• using
• creating your own
18
Thursday, January 24, 13
22. Getting Beans from Strange Places
• FactoryBeans
• Spring Expression Language
– convenient way to get at values and inject them
• Spring environment specific beans (profiles)
– introduced in Spring 3.1
– make it easy to conditionally define an object based on
some sort of runtime condition
19
Thursday, January 24, 13
23. Getting Beans from Strange Places
• FactoryBeans
– interface that’s used to provide a reusable definition of how
to create a complicated object with many dependencies
– Related: Java configuration, and builders
• prefer both over FactoryBeans where possible
20
Thursday, January 24, 13
24. Getting Beans from Strange Places
• Spring Expression Language
– convenient way to get at values and inject them
– Andy Clement’s a genius
– like the Unified JSF EL, on steroids
– Can be used in Java, XML
• @Value(“#{ ... }”) or value = “#{ .. }”
21
Thursday, January 24, 13
25. Getting Beans from Strange Places
• Spring profiles
• @Profile(“production”) @Configuration ...
• <beans profile = ‘production’> ... </beans>
– Use System properties or simply specify the active profile on
the environment
– Use ApplicationContextInitializer in web applications
22
Thursday, January 24, 13
26. Getting Beans from Strange Places
• An ApplicationContextInitializer
public interface ApplicationContextInitializer
<C extends ConfigurableApplicationContext> {
void initialize(C applicationContext);
}
23
Thursday, January 24, 13
28. Proxies!
CustomerService cs = new CustomerService();
cs...
ProxyFactory pf = new ProxyFaxctory();
pf.setTarget( cs );
pf.addAdvice(new MethodInterceptor(){
public Object invoke(MethodInvocation mi) {
// ...
}
} );
return (CustomerService) pf.getObject() ;
25
Thursday, January 24, 13
29. Using Spring’s Resources
• Spring supports out of the box ClassPathResource,
FileResource system, etc.
• Writing your own Resource implementations
public interface Resource extends InputStreamSource {
boolean exists();
boolean isReadable();
boolean isOpen();
URL getURL() throws IOException;
URI getURI() throws IOException;
File getFile() throws IOException;
long contentLength() throws IOException;
long lastModified() throws IOException;
Resource createRelative(String relativePath) throws IOException;
String getFilename();
String getDescription();
}
26
Thursday, January 24, 13
30. Object to XML Marshallers
• Easy to add your own Marshaller (and Unmarshaller)
public interface Marshaller {
boolean supports(Class<?> clazz);
void marshal(Object graph, Result result)
throws IOException, XmlMappingException;
}
27
Thursday, January 24, 13
31. Object to XML Marshallers
• Demos:
– a custom object-to-XML marshaller
28
Thursday, January 24, 13
32. REST
• Spring MVC for the server
@RequestMapping( value = “/crm/customers/{id}” ,
method =HttpMethod.GET)
public @ResponseBody Customer lookupCustomerById(
@PathVariable(“id”) long customerId ) {
...
return customer;
}
29
Thursday, January 24, 13
33. REST
• RestTemplate for the client (Android, SE, web
applications, etc.)
RestTemplate rt = new RestTemplate() ;
String url = “http://mysvc.cloudfoundry.com/crm/customer/{id}”;
Customer customer = rt.getForObject( url, Customer.class, 22);
30
Thursday, January 24, 13
34. REST
• Both need o.s.http.converter.HttpMessageConverters
• Spring supports:
– object-to-XML (JAXB as well as any Spring OXM impl)
– object-to-JSON
– binary data (o.s.resource.Resource references or byte[])
– ATOM/RSS
– images
• Easy to add your own
31
Thursday, January 24, 13
35. Registering a custom HttpMessageConverter
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(
List<HttpMessageConverter<?>> converters) {
}
}
32
Thursday, January 24, 13
36. REST
• Demos:
– Writing and using a customer HttpMessageConverter
33
Thursday, January 24, 13
37. Transactions
• Spring supports declarative transaction management
– @EnableTransactionManagement or
<tx:annotation-driven/>
• PlatformTransactionManager implementations used to
manage transactions
– lots of options out of the box:
• AMQP, JMS, JTA, JDBC, JDO, JPA, WebLogic-specific,
WebSphere-specific, OC4J-specific, etc.
34
Thursday, January 24, 13
38. Transactions
• PlatformTransactionManager abstracts the notion
of a transactional “unit of work.”
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition)
throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
35
Thursday, January 24, 13
39. Caching
• CacheManager’s maintain Caches.
– CacheManagers are like ‘connections’
– Caches are like regions of a cache
public interface CacheManager { public interface Cache {
Cache getCache(String name);
Collection<String> getCacheNames(); interface ValueWrapper {
} Object get();
}
String getName();
Object getNativeCache();
ValueWrapper get(Object key);
void put(Object key, Object value);
void evict(Object key);
void clear();
}
36
Thursday, January 24, 13
40. Writing a custom View and View Resolver
37
Thursday, January 24, 13
41. Writing a custom View and View Resolver
• Easy to add your own View
– supported views out of the box: FreeMarker, Velocity,
Excel, PDFs, JasperReports, XSLT, Jackson, JSTL, etc.
– Lots of contributions from the open source community:
• Thymeleaf
http://www.thymeleaf.org/
• Mustache by Sean Scanlon
https://github.com/sps/mustache-spring-view
38
Thursday, January 24, 13
42. Writing a custom View and View Resolver
public interface ViewResolver {
View resolveViewName(String viewName, Locale locale)
throws Exception;
}
39
Thursday, January 24, 13
43. Writing a custom View and View Resolver
public interface View {
String RESPONSE_STATUS_ATTRIBUTE =
View.class.getName() + ".responseStatus";
String getContentType();
void render(Map<String, ?> model,
HttpServletRequest request,
HttpServletResponse response) throws Exception;
}
40
Thursday, January 24, 13
44. Writing a custom View and View Resolver
@Bean
public ViewResolver myCustomViewResolver(){
...
} if ‘detectAllViewResolvers’ is
true, all ViewResolvers types
will be registered.
@Bean
public MyCustomViewResolver viewResolver()
{
...
}
41
Thursday, January 24, 13
45. Writing a custom View and View Resolver
@Bean
public ViewResolver myCustomViewResolver(){
...
} if ‘detectAllViewResolvers’ is
true, all ViewResolvers types
will be registered.
@Bean
public MyCustomViewResolver viewResolver()
{
... if ‘detectAllViewResolvers’ is
false, it’ll lookup a bean by a
} well known name
41
Thursday, January 24, 13
46. Writing a custom View and View Resolver
• Demo: writing a custom view/view resolver
42
Thursday, January 24, 13
47. A Custom NameSpace
public class ASimpleParser extends AbstractSingleBeanDefinitionParser {
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
String exchangeName = element.getAttribute(NAME_ATTRIBUTE);
builder.addConstructorArgValue(new TypedStringValue(exchangeName));
Element bindings = DomUtils.getChildElementByTagName(element, BINDINGS_ELE);
if (bindings != null) { }
NamespaceUtils.addConstructorArgBooleanValueIfAttributeDefined(builder, element, DURABLE_ATTRIBUTE, true);
...
}
43
Thursday, January 24, 13
49. Writing Adapters in Spring Integration
• MessageSource for inbound adapters
• MessageHandler for outbound adapters
MessageSource MessageHandler
45
Thursday, January 24, 13
50. Writing Adapters in Spring Integration
• Inbound channel adapter “receives” message from
external system inward relative to Spring Integration code
package org.springframework.integration.core;
public interface MessageSource<T> {
org.springframework.integration.Message<T> receive();
}
<int:channel id = “in” />
<int:inbound-channel-adapter
channel = “in” ref = “myCustomMessageSource” >
<int:cron-trigger ... />
</int:inbound-channel-adapter>
46
Thursday, January 24, 13
51. Writing Adapters in Spring Integration
• Outbound channel adapter “publishes” message from Spring
Integration outward relative to Spring Integration code
package org.springframework.integration.core;
public interface MessageHandler {
void handleMessage(
org.springframework.integration.Message<?> message)
throws org.springframework.integration.MessagingException;
}
<int:channel id = “out” />
<int:outbound-channel-adapter
channel = “out” ref = “myCustomMessageHandler” />
47
Thursday, January 24, 13
52. Spring Integration File System Adapters
• Spring Integration provides rich file system adapters
– FTP, SFTP, FTPS, files in general
– But... what about SMB/CIFS?
48
Thursday, January 24, 13
53. Writing Readers and Writers in Spring Batch
• ItemReader for inbound adapters
• ItemWriters for outbound adapters
49
Thursday, January 24, 13