this is the deck for my 3+ hour walking tour talk that I give as a workshop at various conferences. This talk introduces practically everything in Spring -- come into the talk unaware of the concepts or frameworks and leave with a working knowledge of all the frameworks, and of all the applications for the technologies.
2. About
SpringSource is the organization that develops the Spring
framework, the leading enterprise Java framework
SpringSource was acquired by VMware in 2009
VMware and SpringSource bring you to the cloud and
deliver on the mission of “build, run, manage”
• established partnerships with the major players in the business, including
Adobe, SalesForce, and Google to help deliver the best experience for
Spring users across multiple platforms
Leading contributor to projects like
Apache HTTPD and Apache Tomcat
2
3. About Josh Long
Spring Developer Advocate
twitter: @starbuxman
josh.long@springsource.com
3
7. Spring’s aim:
bring simplicity to java development
data
web tier
batch integration & access
& service tier mobile
processing messaging / NoSQL /
RIA
Big Data
The Spring framework
the cloud: lightweight traditional
WebSphere
CloudFoundry tc Server
JBoss AS
Google App Engine Tomcat
WebLogic
Amazon BeanStalk Jetty (on legacy versions, too!)
7
9. The Spring Framework
Framework Description
Spring Core The foundation
Spring @MVC the web leading framework (comes with the core framework)
Spring Security Extensible framework providing authentication, authorization
Spring Webflow An excellent web framework for building multi-page flows
Spring Web Services Contract-first, document–centric SOAP and XML web services
Spring Batch Powerful batch processing framework
Spring Integration Implements enterprise integration patterns
Spring BlazeDS Support for Adobe BlazeDS
Spring AMQP interface with AMQP message brokers, like RabbitMQ
Spring Data NoSQL options: HBase, MongoDB, Redis, Riak, CouchDB, Neo4J, etc.
Spring Social integrate Twitter, Facebook, Tripit, MySpace, LinkedIn, etc.
Spring Hadoop Provides a POJO-centric approach to building Hadoop applications
provides first-class support for service
Spring Mobile, Spring Android
creation and consumption for iPhone, Android
Spring GemFire Provides the easiest interface for the GemFire enterprise data grid technology
9
10. The Spring ApplicationContext
Spring Manages the beans you tell it to manage (Implicitly, Explicitly)
• 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
10
11. The Spring ApplicationContext
Annotations (component-scanning)
• best when you want Spring to sort it all out in the wash, no need for explicit configuration
Java Configuration
• type-safe, and explicit - all configuration is centralized. Provides a good birds-eye view of
your application
XML
• explicit - namespaces still provide the most punch in a lot of cases
All together
• use Java configuration for your regular third party beans (like a DataSource)
• XML namespaces for DSLs and higher level functionality (Spring Integration, Batch, etc.)
• annotations for your components (a @Service, or a Spring MVC @Controller)
11
12. The Spring ApplicationContext
public class Main {
public static void main(String [] args) throws Throwable {
ApplicationContext ctx =
new AnnotationConfigApplicationContext( ServicesConfiguration.class );
CustomerService serviceReference = ctx.getBean( CustomerService.class );
Customer customer = serviceReference.createCustomer( "Juergen", "Hoeller");
}
}
12
14. I want Database Access ... with Hibernate 4 Support
@Service
public class CustomerService {
public Customer createCustomer(String firstName,
String lastName,
Date signupDate) {
...
}
}
Not confidential. Tell everyone. 14
15. I want Database Access ... with Hibernate 4 Support
@Service
public class CustomerService {
@Inject
private SessionFactory sessionFactory;
public Customer createCustomer(String firstName,
String lastName,
Date signupDate) {
Customer customer = new Customer();
customer.setFirstName(firstName);
customer.setLastName(lastName);
customer.setSignupDate(signupDate);
sessionFactory.getCurrentSession().save(customer);
return customer;
}
}
Not confidential. Tell everyone. 15
16. I want Database Access ... with Hibernate 4 Support
@Service
public class CustomerService {
@Inject
private SessionFactory sessionFactory;
@Transactional
public Customer createCustomer(String firstName,
String lastName,
Date signupDate) {
Customer customer = new Customer();
customer.setFirstName(firstName);
customer.setLastName(lastName);
customer.setSignupDate(signupDate);
sessionFactory.getCurrentSession().save(customer);
return customer;
}
}
Not confidential. Tell everyone. 16
17. I want Declarative Cache Management...
@Service
public class CustomerService {
@Inject
private SessionFactory sessionFactory;
@Transactional
@Cacheable(“customers”)
public Customer createCustomer(String firstName,
String lastName,
Date signupDate) {
Customer customer = new Customer();
customer.setFirstName(firstName);
customer.setLastName(lastName);
customer.setSignupDate(signupDate);
sessionFactory.getCurrentSession().save(customer);
return customer;
}
}
Not confidential. Tell everyone. 17
18. I want a RESTful Endpoint...
package org.springsource.examples.spring31.web;
..
@Controller
public class CustomerController {
@Inject
private CustomerService customerService;
@RequestMapping(value = "/customer/{id}",
produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody Customer customerById(@PathVariable("id") Integer id) {
return customerService.getCustomerById(id);
}
...
}
Not confidential. Tell everyone. 18
20. ...But Where’d the SessionFactory come from?
Not confidential. Tell everyone. 20
21. A Quick Primer on Configuration in Spring 3.1
....
<beans>
<tx:annotation-driven transaction-manager = "txManager" />
<context:component-scan base-package = "org.springsource.examples.spring31.services" />
<context:property-placeholder properties = "config.properties" />
<bean id = "txManager"
class = "org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name = "sessionFactory" ref = "sessionFactory" />
</bean>
<bean id = "sessionFactory"
class = "org.springframework.orm.hibernate4.LocalSessionFactoryBean">
...
</bean>
</beans>
Not confidential. Tell everyone.
22. A Quick Primer on Configuration in Spring 3.1
....
<beans>
<tx:annotation-driven transaction-manager = "txManager" />
<context:component-scan base-package = "org.springsource.examples.spring31.services" />
<context:property-placeholder properties = "config.properties" />
<bean id = "txManager"
class = "org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name = "sessionFactory" ref = "sessionFactory" />
</bean>
<bean id = "sessionFactory"
class = "org.springframework.orm.hibernate4.LocalSessionFactoryBean">
...
</bean>
</beans>
Not confidential. Tell everyone.
23. A Quick Primer on Configuration in Spring 3.1
@Configuration
@PropertySource("/config.properties")
@EnableTransactionManagement
@ComponentScan(basePackageClasses = {CustomerService.class})
public class ServicesConfiguration {
@Bean
public PlatformTransactionManager txManager() throws Exception {
return new HibernateTransactionManager(this.sessionFactory());
}
@Bean
public SessionFactory sessionFactory() { ... }
}
Not confidential. Tell everyone.
24. A Quick Primer on Configuration in Spring 3.1
....
<beans>
<tx:annotation-driven transaction-manager = "txManager" />
<context:component-scan base-package = "org.springsource.examples.spring31.services" />
<context:property-placeholder properties = "config.properties" />
<bean id = "txManager"
class = "org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name = "sessionFactory" ref = "sessionFactory" />
</bean>
<bean id = "sessionFactory"
class = "org.springframework.orm.hibernate4.LocalSessionFactoryBean">
...
</bean>
</beans>
Not confidential. Tell everyone.
25. A Quick Primer on Configuration in Spring 3.1
@Configuration
@PropertySource("/config.properties")
@EnableTransactionManagement
@ComponentScan(basePackageClasses = {CustomerService.class})
public class ServicesConfiguration {
@Bean
public PlatformTransactionManager txManager() throws Exception {
return new HibernateTransactionManager(this.sessionFactory());
}
@Bean
public SessionFactory sessionFactory() { ... }
}
Not confidential. Tell everyone.
26. A Quick Primer on Configuration in Spring 3.1
....
<beans>
<tx:annotation-driven transaction-manager = "txManager" />
<context:component-scan base-package = "org.springsource.examples.spring31.services" />
<context:property-placeholder properties = "config.properties" />
<bean id = "txManager"
class = "org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name = "sessionFactory" ref = "sessionFactory" />
</bean>
<bean id = "sessionFactory"
class = "org.springframework.orm.hibernate4.LocalSessionFactoryBean">
...
</bean>
</beans>
Not confidential. Tell everyone.
27. A Quick Primer on Configuration in Spring 3.1
@Configuration
@PropertySource("/config.properties")
@EnableTransactionManagement
@ComponentScan(basePackageClasses = {CustomerService.class})
public class ServicesConfiguration {
@Bean
public PlatformTransactionManager txManager() throws Exception {
return new HibernateTransactionManager(this.sessionFactory());
}
@Bean
public SessionFactory sessionFactory() { ... }
}
Not confidential. Tell everyone.
28. A Quick Primer on Configuration in Spring 3.1
....
<beans>
<tx:annotation-driven transaction-manager = "txManager" />
<context:component-scan base-package = "org.springsource.examples.spring31.services" />
<context:property-placeholder properties = "config.properties" />
<bean id = "txManager"
class = "org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name = "sessionFactory" ref = "sessionFactory" />
</bean>
<bean id = "sessionFactory"
class = "org.springframework.orm.hibernate4.LocalSessionFactoryBean">
...
</bean>
</beans>
Not confidential. Tell everyone.
29. A Quick Primer on Configuration in Spring 3.1
@Configuration
@PropertySource("/config.properties")
@EnableTransactionManagement
@ComponentScan(basePackageClasses = {CustomerService.class})
public class ServicesConfiguration {
@Bean
public PlatformTransactionManager txManager() throws Exception {
return new HibernateTransactionManager(this.sessionFactory());
}
@Bean
public SessionFactory sessionFactory() { ... }
}
Not confidential. Tell everyone.
30. A Quick Primer on Configuration in Spring 3.1
....
<beans>
<tx:annotation-driven transaction-manager = "txManager" />
<context:component-scan base-package = "org.springsource.examples.spring31.services" />
<context:property-placeholder properties = "config.properties" />
<bean id = "txManager"
class = "org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name = "sessionFactory" ref = "sessionFactory" />
</bean>
<bean id = "sessionFactory"
class = "org.springframework.orm.hibernate4.LocalSessionFactoryBean">
...
</bean>
</beans>
Not confidential. Tell everyone.
31. A Quick Primer on Configuration in Spring 3.1
@Configuration
@PropertySource("/config.properties")
@EnableTransactionManagement
@ComponentScan(basePackageClasses = {CustomerService.class})
public class ServicesConfiguration {
@Bean
public PlatformTransactionManager txManager() throws Exception {
return new HibernateTransactionManager(this.sessionFactory());
}
@Bean
public SessionFactory sessionFactory() { ... }
}
Not confidential. Tell everyone.
32. A Quick Primer on Configuration in Spring 3.1
....
<beans>
<tx:annotation-driven transaction-manager = "txManager" />
<context:component-scan base-package = "org.springsource.examples.spring31.services" />
<context:property-placeholder properties = "config.properties" />
<bean id = "txManager"
class = "org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name = "sessionFactory" ref = "sessionFactory" />
</bean>
<bean id = "sessionFactory"
class = "org.springframework.orm.hibernate4.LocalSessionFactoryBean">
...
</bean>
</beans>
Not confidential. Tell everyone.
33. A Quick Primer on Configuration in Spring 3.1
@Configuration
@PropertySource("/config.properties")
@EnableTransactionManagement
@ComponentScan(basePackageClasses = {CustomerService.class})
public class ServicesConfiguration {
@Bean
public PlatformTransactionManager txManager() throws Exception {
return new HibernateTransactionManager(this.sessionFactory());
}
@Bean
public SessionFactory sessionFactory() { ... }
}
Not confidential. Tell everyone.
34. DEMO
introduce the tool chain
how to “setup” Spring
basic dependency injection
• annotations (JSR 250, JSR 330, native)
• xml
• java configuration
Not confidential. Tell everyone. 34
38. The Life of a Bean
Not confidential. Tell everyone. 38
39. 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.
Not confidential. Tell everyone. 39
40. 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
Not confidential. Tell everyone. 40
41. 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 given
Object remove(String name); scope
void registerDestructionCallback(String name, Runnable callback);
well known beans like the
Object resolveContextualObject(String key); HttpServletRequest ‘request’ for
‘request’ scope
String getConversationId();
}
null, or storage specific
‘conversation’ ID
Not confidential. Tell everyone. 41
42. DEMO
Demos:
• life cycle callbacks
• scopes
• using
• creating your own
Not confidential. Tell everyone. 42
44. 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
Not confidential. Tell everyone. 44
45. 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
Not confidential. Tell everyone. 45
46. 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 = “#{ .. }”
Not confidential. Tell everyone. 46
47. 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
Not confidential. Tell everyone. 47
48. Getting Beans from Strange Places
...
<beans ....>
In Development = “default”>
<beans profile
<ds:embedded-database id= "dataSource" type = “H2” />
</beans>
<beans profile = “cloud”>
In Production
<cloud:data-source id="dataSource"/>
</beans>
</beans>
Not confidential. Tell everyone. 48
51. Environment Configuration
Associating specific bean definitions with specific environments
• XML 'profile' attribute on <beans> element
• @Profile annotation on configuration classes
• @Profile annotation on individual component classes
Not confidential. Tell everyone. 50
52. Environment Configuration
Associating specific bean definitions with specific environments
• XML 'profile' attribute on <beans> element
• @Profile annotation on configuration classes
• @Profile annotation on individual component classes
Activating specific profiles by name
• e.g. through a system property
• -Dspring.profiles.active=development
• or other means outside of the deployment unit
• according to environment conventions
Not confidential. Tell everyone. 50
53. Environment Configuration
Associating specific bean definitions with specific environments
• XML 'profile' attribute on <beans> element
• @Profile annotation on configuration classes
• @Profile annotation on individual component classes
Activating specific profiles by name
• e.g. through a system property
• -Dspring.profiles.active=development
• or other means outside of the deployment unit
• according to environment conventions
Not confidential. Tell everyone. 50
54. Environment Configuration
Associating specific bean definitions with specific environments
• XML 'profile' attribute on <beans> element
• @Profile annotation on configuration classes
• @Profile annotation on individual component classes
Activating specific profiles by name
• e.g. through a system property
• -Dspring.profiles.active=development
• or other means outside of the deployment unit
• according to environment conventions
Ideally: no need to touch deployment unit across different stages/
environments
Not confidential. Tell everyone. 50
56. Environment Abstraction
Grouping bean definitions for activation in specific environments
• e.g. development, testing, production
• possibly different deployment environments
Custom resolution of placeholders
• dependent on the actual environment
• hierarchy of property sources
Not confidential. Tell everyone. 51
57. Environment Abstraction
Grouping bean definitions for activation in specific environments
• e.g. development, testing, production
• possibly different deployment environments
Custom resolution of placeholders
• dependent on the actual environment
• hierarchy of property sources
Not confidential. Tell everyone. 51
58. Environment Abstraction
Grouping bean definitions for activation in specific environments
• e.g. development, testing, production
• possibly different deployment environments
Custom resolution of placeholders
• dependent on the actual environment
• hierarchy of property sources
Injectable environment abstraction API
• org.springframework.core.env.Environment
Not confidential. Tell everyone. 51
59. Environment Abstraction
Grouping bean definitions for activation in specific environments
• e.g. development, testing, production
• possibly different deployment environments
Custom resolution of placeholders
• dependent on the actual environment
• hierarchy of property sources
Injectable environment abstraction API
• org.springframework.core.env.Environment
Unified property resolution SPI
• org.springframework.core.env.PropertyResolver
Not confidential. Tell everyone. 51
60. Getting Beans from Strange Places
An ApplicationContextInitializer
public interface ApplicationContextInitializer
<C extends ConfigurableApplicationContext> {
void initialize(C applicationContext);
}
Not confidential. Tell everyone. 52
62. Other Things Core Spring Supports
transparent service remoting
seamless JMX support, both consuming and exposing
transaction management
• (which we’ll look at shortly)
job scheduling
thread management
object to XML marshalling
Not confidential. Tell everyone. 54
63. Spring Roo
provides domain driven design and RAD for your enterprise Java
applications
Needs to be seen to be believed, so...
Not confidential. Tell everyone. 55
64. DEMO
Spring Roo
ALSO: come see my talk on Spring Roo applications!
Not confidential. Tell everyone. 56
65. The Cloud
Spring works reliably on many, many clouds.
Cloud Foundry is an ideal place for your Spring applications to run
• they’ll be well fed and cared for
• lots of nice services to play with (Redis, RabbitMQ, MySQL, PostgreSQL, MongoDB)
• there are nice Spring API integrations for all of those!
Not confidential. Tell everyone. 57
66. DEMO
Setting up a Redis-caching, PostgreSQL-using Spring app on MCF
ALSO: come see my talk on building Cloud Foundry applications!
Not confidential. Tell everyone. 58
69. Spring’s Transaction Support
Rooted at PlatformTransactionManager
• Many middleware services expose common notions about units of work:
• begin
• do work (N times)
• commit
• if error when committing, rollback
• end
• The devil’s in the details
• Hibernate’s got its Session API
• JTA has its own API (and server lock-in problems)
• JPA has its EntityManager API
• JDBC has the Connection and PreparedStatement APIs
• JMS has its Session API
Not confidential. Tell everyone. 61
70. Spring’s Transaction Support
PlatformTransactionManager encompasses common concerns
across transactional resources
package org.springframework.transaction;
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition)
throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
Not confidential. Tell everyone. 62
76. Cache Abstraction
CacheManager and Cache abstraction
• in org.springframework.cache
• which up until 3.0 just contained EhCache support
• particularly important with the rise of distributed caching
• not least of it all: in cloud environments
67
77. Cache Abstraction
CacheManager and Cache abstraction
• in org.springframework.cache
• which up until 3.0 just contained EhCache support
• particularly important with the rise of distributed caching
• not least of it all: in cloud environments
67
78. Cache Abstraction
CacheManager and Cache abstraction
• in org.springframework.cache
• which up until 3.0 just contained EhCache support
• particularly important with the rise of distributed caching
• not least of it all: in cloud environments
Backend adapters for EhCache, GemFire, Coherence, etc
• EhCache adapter shipping with Spring core
• JSR-107 a.k.a. JCache support coming in Spring 3.2
67
79. Cache Abstraction
CacheManager and Cache abstraction
• in org.springframework.cache
• which up until 3.0 just contained EhCache support
• particularly important with the rise of distributed caching
• not least of it all: in cloud environments
Backend adapters for EhCache, GemFire, Coherence, etc
• EhCache adapter shipping with Spring core
• JSR-107 a.k.a. JCache support coming in Spring 3.2
67
80. Cache Abstraction
CacheManager and Cache abstraction
• in org.springframework.cache
• which up until 3.0 just contained EhCache support
• particularly important with the rise of distributed caching
• not least of it all: in cloud environments
Backend adapters for EhCache, GemFire, Coherence, etc
• EhCache adapter shipping with Spring core
• JSR-107 a.k.a. JCache support coming in Spring 3.2
Specific cache setup per environment – through profiles?
• potentially even adapting to a runtime-provided service
67
89. JDBC Support with Spring
DataSourceTransactionManager
• implements transaction support for JDBC
JdbcTemplate
• provides convenient one-liner template methods for common JDBC calls
JDBC command objects (like SimpleJdbcInsert)
Not confidential. Tell everyone. 70
90. JdbcTemplate convenience
// inserts
RowMapper<Customer> customerRowMapper = new RowMapper<Customer>() {
public Customer mapRow(ResultSet resultSet, int i) throws SQLException {
long id = resultSet.getInt("id");
String firstName = resultSet.getString("first_name");
String lastName = resultSet.getString("last_name");
return new Customer(id, firstName, lastName);
}
};
}
// reads
Long id = 23L;
jdbcTemplate.queryForObject(
“select * from customers where id = ? “, customerRowMapper, id);
Not confidential. Tell everyone. 71
91. JDBC Inserts with SimpleJdbcInsert
Map<String, Object> args = new HashMap<String, Object>();
args.put("first_name", fn);
args.put("last_name", ln);
SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
simpleJdbcInsert.setTableName("customer");
simpleJdbcInsert.setColumnNames(new ArrayList<String>(args.keySet()));
simpleJdbcInsert.setGeneratedKeyName("id");
Number id = simpleJdbcInsert.executeAndReturnKey(args);
Not confidential. Tell everyone. 72
92. DEMO
• Looking at, and running, a JDBC-based client
Not confidential. Tell everyone.
94. JPA Support with Spring
JpaTransactionManager
• implements transaction support for JPA
LocalContainerEntityManagerFactoryBean
• installs support for using @EntityManager and @EntityManagerFactory to inject
EntityManager(Factory) references
EntityManager access is transparently thread-safe
Requires no XML
• no persistence.xml, or orm.xml
Not confidential. Tell everyone. 75
95. Configure JPA Support Easily
HibernateJpaVendorAdapter jpaVendorAdapter =
new HibernateJpaVendorAdapter();
jpaVendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean emfb =
new LocalContainerEntityManagerFactoryBean();
emfb.setDataSource(dataSource());
emfb.setPackagesToScan(Customer.class.getPackage().getName());
emfb.setJpaVendorAdapter(jpaVendorAdapter);
Not confidential. Tell everyone. 76
96. Consuming JPA from your Services
@PersistenceContext
private EntityManager entityManager;
@Transactional(readOnly = true)
public Customer getCustomerById(long id) {
return this.entityManager.find(Customer.class, id);
}
Not confidential. Tell everyone. 77
99. Hibernate Support with Spring
Supports Hibernate 3 and 4
Requires no XML
LocalSessionFactoryBuilder, LocalSessionFactoryBean
Supports thread-local based Hibernate Session access transparently
Not confidential. Tell everyone. 80
100. Easy to Use in Code
@Transactional(readOnly = true)
public List<Customer> getAllCustomers() {
Session session = sessionFactory.getCurrentSession();
List<Customer> customers =
session.createCriteria(Customer.class).list();
return customers;
}
Not confidential. Tell everyone. 81
101. DEMO
Demos:
• Looking at Spring 3.1’s refined XML-free and fluid Hibernate 4 support
Not confidential. Tell everyone.
107. Spring Batch
Supports Batch API...
• Jobs have Steps
• Steps have Readers, and optional Processors and Writers
• Readers read data
• Processors process data coming into them, optionally transforming it. Optional.
• Writers write data out
Not confidential. Tell everyone. 88
108. ItemReader
public interface ItemReader<T> {
T read() throws Exception,
UnexpectedInputException,
ParseException,
NonTransientResourceException;
}
Returns null at end of dataset
delegate Exception handling to framework
Not confidential. Tell everyone. 89
109. ItemProcessor (Optional)
public interface ItemProcessor<I, O> {
O process(I item) throws Exception;
}
Delegate Exception handling to framework
Not confidential. Tell everyone. 90
110. ItemWriter
public interface ItemWriter<T> {
void write(List<? extends T> items) throws Exception;
}
expects a “chunk”
delegate Exception handling to framework
Not confidential. Tell everyone. 91
114. Common Idioms in all of Spring’s Messaging Support
(Amqp|Jms)Template
• eliminates tedious resource acquisition, setup, management, and destruction
• provides easy one-liner template methods that facilitate sending, and receiving
messages
• receiving messages is synchronous
MessageListenerContainers
• provide a clean, POJO-centric, asynchronous way to receive messages
Plays nicely with the PlatformTransactionManager SPI impls
MessageConverters
• transparently transform message payloads into canonical data formats like JSON, XML
• MLCs, *Templates both support MessageConverters for sending and receiving
Lots of Options
• JMS, AMQP, Redis, GemFire
Not confidential. Tell everyone. 95
116. Anatomy of a JMS Application
Not confidential. Tell everyone. 97
117. Spring’s JMS support makes JMS easy
JmsTemplate reduces tedious boilerplate code to one liners
JMS MessageListenerContainer SPIs make it easy to
asynchronously respond to messages
• POJO centric
• Same idiom’s available across the entire framework
Not confidential. Tell everyone. 98
118. Easy to Configure
@Bean
public MessageConverter messageConverter() {
MarshallingMessageConverter marshallingMessageConverter =
new MarshallingMessageConverter();
marshallingMessageConverter.setMarshaller(this.oxmMarshaller());
marshallingMessageConverter.setTargetType(MessageType.TEXT);
marshallingMessageConverter.setUnmarshaller(this.oxmMarshaller());
return marshallingMessageConverter;
}
@Bean
public JmsTemplate jmsTemplate() throws Exception {
JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory());
jmsTemplate.setMessageConverter( messageConverter()); // optional
return jmsTemplate;
}
Not confidential. Tell everyone. 99
119. Easy to Use in Code
Customer customer = new Customer("Mario", "Gray");
String queue = "customers";
jmsTemplate.convertAndSend(queue, customer);
Customer ogCustomer =
(Customer) jmsTemplate.receiveAndConvert(queue);
Not confidential. Tell everyone. 100
120. DEMO
Demos:
• Sending and Receiving Data with Spring’s JMS support
Not confidential. Tell everyone.
122. AMQP is not the ORIGINAL “Cloud Scale Messaging”
....but close enough!
103
123. RabbitMQ – Messaging that Just Works
Robust
High-performance
Easy to use
AMQP LEADER
124. Why AMQP?
A Protocol, not an API
•A defined set of
messaging capabilities
called the AMQ model
•A network wire-level
protocol, AMQP
On commodity hardware
•10-25 thousand
messages per second is
routine *
•The NIC is usually the
bottleneck
* Non-persistent messages
17
125. Anatomy of an AQMP Application
Not confidential. Tell everyone. 106
142. AMQP Architecture
all_drinks
queue
.*
drink
drink.cold cold_drinks
queue
dri
nk.
ho hot_drinks
t
queue
21
143. AMQP Architecture
all_drinks
queue
.*
drink
drink.cold cold_drinks
queue
dri
nk.
ho hot_drinks
t
queue
Message Routing Keys:
1.drink.hot
2.drink.cold
3.drink.warm
21
144. AMQP Architecture
all_drinks
1 2 3
queue
.*
drink
drink.cold cold_drinks
2
queue
dri
nk.
ho hot_drinks
t
1
queue
Message Routing Keys:
1.drink.hot
2.drink.cold
3.drink.warm
21
145. Spring AMQP
Encapsulates low-level details
Producer Consumer
Simplifies sending and
receiving of messages
Amqp Listener
Template Container
Spring AMQP
AMQP
Not confidential. Tell everyone.
146. Spring’s AMQP support makes AMQP easy
AMQP is protocol centric
• numerous clients for any number of language bindings
AMQP surfaces more of the administration concerns over the
protocol
• easy to create queues, bindings, exchanges from client APIs
Not confidential. Tell everyone. 111
147. Spring’s AMQP support makes AMQP easy
AmqpTemplate
AMQP MessageListenerContainer SPIs make it easy to
asynchronously respond to messages
• POJO centric
AMQP’s server side constructs (queues, bindings, etc.) can be
manipulated from the client APIs
Not confidential. Tell everyone. 112
148. Easy to Configure
@Bean
public MessageConverter jsonMessageConverter() {
MarshallingMessageConverter marshallingMessageConverter =
new MarshallingMessageConverter();
marshallingMessageConverter.setMarshaller(this.oxmMarshaller());
marshallingMessageConverter.setUnmarshaller(this.oxmMarshaller());
return marshallingMessageConverter;
}
@Bean
public RabbitTemplate rabbitTemplate() {
RabbitTemplate rabbitTemplate = new
RabbitTemplate(connectionFactory());
rabbitTemplate.setMessageConverter(jsonMessageConverter());
return rabbitTemplate;
}
Not confidential. Tell everyone. 113
149. Easy to Configure
@Bean
public AmqpAdmin amqpAdmin() {
return new RabbitAdmin(this.connectionFactory());
}
@Bean
public Queue customerQueue() {
Queue q = new Queue(this.customersQueueAndExchangeName);
amqpAdmin().declareQueue(q);
return q;
}
@Bean
public DirectExchange customerExchange() {
DirectExchange directExchange = new DirectExchange(“customers”);
this.amqpAdmin().declareExchange(directExchange);
return directExchange;
}
@Bean
public Binding marketDataBinding() {
return BindingBuilder.bind(customerQueue())
.to(customerExchange())
.with(this.customersQueueAndExchangeName);
}
Not confidential. Tell everyone. 114
150. Easy to Use in Code
Customer customer = new Customer("Mario", "Gray");
amqpTemplate.convertAndSend( “exchange”, “routingkey”, customer);
Customer ogCustomer =
(Customer) amqpTemplate.receiveAndConvert(“queue”);
Not confidential. Tell everyone. 115
151. DEMO
Demos:
• Sending and receiving data with Spring’s AMQP support
Not confidential. Tell everyone.
153. What is Spring Integration
Generic framework for building messaging-based applications
Hides nuances of external systems (be they AMQP, JMS, email, FTP,
TCP, etc.): everything’s a Message
Not confidential. Tell everyone. 118
154. Declare channels
<channel id = “stocksChannel” />
Not confidential. Tell everyone. 119
155. Send Messages over JMS
<channel id = “stockChannel” />
<jms:outbound-channel-adapter
channel = “stockChannel”
destination-name=“stocks”
connection-factory = “connectionFactory”
/>
Not confidential. Tell everyone. 120
156. Connect Components with Channels
public class StockClientImpl {
@Value(“#{stocksChannel}”) private MessageChannel channel ;
@Autowired private MessagingTemplate messagingTemplate ;
public void publishStockUpdate ( String stock , double price ) {
Message msg = MessageBuilder
.withPayload(price)
.setHeader(“stock”, stock).build();
this.messagingTemplate.send( this.channel, msg ) ;
}
}
Not confidential. Tell everyone. 121
157. Being Notified of Files When They Appear
<file:inbound-channel-adapter
auto-create-directory="true"
channel="filesReceived"
directory="#{systemProperties['user.home']}/Desktop/in">
<int:poller fixed-rate="1000"/>
</file:inbound-channel-adapter>
<int:service-activator input-channel="filesReceived" ref="myPojo" />
@ServiceActivator
public class MyPojo {
public void myCustomFileCallback ( @Payload File fileReceived) {
// do something with the file
}
}
Not confidential. Tell everyone. 122
158. DEMO
• Reading file Data with Spring Integration
Not confidential. Tell everyone.
159. Spring Data
Not confidential. Tell everyone. 124
161. Spring Data Building Blocks
•Low level data access APIs
✓MongoTemplate, RedisTemplate ...
•Object Mapping (Java and GORM)
•Cross Store Persistence Programming model
•Generic Repository support
•Productivity support in Roo and Grails
126
163. NoSQL offers several data store categories
Key-Value Column Document Graph
Redis,
Riak
128
164. Spring Data Redis
Works with Redis
• super fast
• “data structure server” (maps, lists, sets, queue, etc.)
RedisTemplate reduces tedious boilerplate code to one liners
CacheManager implementation
• works with Spring 3.1’s CacheManager implementation
RedisMessageListenerContainer
• provides same queue / publish-subscribe features as with JMS and AMQP
Not confidential. Tell everyone. 129
165. Configuring Redis support
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new JedisConnectionFactory();
}
@Bean
public RedisTemplate<String, Object> redisTemplate()
throws Exception {
RedisTemplate<String, Object> ro = new RedisTemplate<String, Object>();
ro.setConnectionFactory(redisConnectionFactory());
return ro;
}
NOT CONFIDENTIAL -- TELL EVERYONE 130
167. DEMO
• Reimplementing the CustomerService interface in terms of Redis
• introduce Spring 3.1 caching support
• Introduce RedisCacheManager implementation
•
Not confidential. Tell everyone.
169. NoSQL offers several data store categories
Key-Value Column Document Graph
MongoDB
134
170. Spring Data MongoDB
works with MongoDB
provides obvious API integrations:
• MongoTemplate
• Mongo-backed MessageStore (Spring Integration)
Advanced API integrations, too:
• cross-store persistence
• MongoRepository (built on Spring Data JPA)
Not confidential. Tell everyone. 135
192. The Spring ApplicationContext
Spring Beans are Managed by An ApplicationContext
• whether you’re in an application server, a web server, in regular Java SE application, in
the cloud, Spring is initialized through an ApplicationContext
• In a Java SE application:
ApplicationContext ctx =
new GenericAnnotationApplicationContext( “com.foo.bar.my.package”);
• In a web application, you will configure an application context in your web.xml
<servlet>
<servlet-name>Spring Dispatcher Servlet</servlet-name>
<servlet-
class>org.springframework.web.servlet.DispatcherServlet</servlet-
class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/myAppContext*.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
147
193. The Spring ApplicationContext
Spring Beans are Managed by An ApplicationContext
• In Spring 3.1, you can also use Java configuration, negating the need for web.xml
public class SampleWebApplicationInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext sc) throws ServletException {
AnnotationConfigWebApplicationContext ac =
new AnnotationConfigWebApplicationContext();
ac.setServletContext(sc);
ac.scan( “a.package.full.of.services”, “a.package.full.of.controllers” );
sc.addServlet("spring", new DispatcherServlet(webContext));
}
}
148
194. Thin, Thick, Web, Mobile and Rich Clients: Web Core
Spring Dispatcher Servlet
• Objects don’t have to be web-specific.
• Spring web supports lower-level web machinery: ‘
• HttpRequestHandler (supports remoting: Caucho, Resin, JAX RPC)
• DelegatingFilterProxy.
• HandlerInterceptor wraps requests to HttpRequestHandlers
• ServletWrappingController lets you force requests to a servlet through the Spring Handler chain
• OncePerRequestFilter ensures that an action only occurs once, no matter how many filters are
applied. Provides a nice way to avoid duplicate filters
• Spring provides access to the Spring application context using
WebApplicationContextUtils, which has a static method to look up the context, even in
environments where Spring isn’t managing the web components
195. Thin, Thick, Web, Mobile and Rich Clients: Web Core
Spring provides the easiest way to integrate with your web
framework of choice
• Spring Faces for JSF 1 and 2
• Struts support for Struts 1
• Tapestry, Struts 2, Stripes, GWT, Wicket, Vaadin, Play framework, etc.
201. Thin, Thick, Web, Mobile and Rich Clients: REST
Spring MVC is basis for REST support
• Spring’s server side REST support is based on the standard controller model
RestTemplate
• provides dead simple, idiomatic RESTful services consumption
• can use Spring OXM, too.
• Spring Integration and Spring Social both build on the RestTemplate where possible.
JavaScript and HTML5 can consume JSON-data payloads
REST is the ultimate connectivity mechanism: everything can speak
HTTP.
202. Thin, Thick, Web, Mobile and Rich Clients: REST
Origin
• The term Representational State Transfer was introduced and defined in 2000 by Roy
Fielding in his doctoral dissertation.
His paper suggests these four design principles:
• Use HTTP methods explicitly.
• POST, GET, PUT, DELETE
• CRUD operations can be mapped to these existing methods
• Be stateless.
• State dependencies limit or restrict scalability
• Expose directory structure-like URIs.
• URI’s should be easily understood
• Transfer XML, JavaScript Object Notation (JSON), or both.
• Use XML or JSON to represent data objects or attributes
CONFIDENTIAL
157
203. Thin, Thick, Web, Mobile and Rich Clients: RestTemplate
Google search example
RestTemplate restTemplate = new RestTemplate();
String url = "https://ajax.googleapis.com/ajax/services/search/web?v=1.0&q={query}";
String result = restTemplate.getForObject(url, String.class, "SpringSource");
Multiple parameters
RestTemplate restTemplate = new RestTemplate();
String url = "http://example.com/hotels/{hotel}/bookings/{booking}";
String result = restTemplate.getForObject(url, String.class, "42", “21”);
CONFIDENTIAL
158
204. Thin, Thick, Web, Mobile and Rich Clients: RestTemplate
RestTemplate class is the heart the client-side story
• Entry points for the six main HTTP methods
• DELETE - delete(...)
• GET - getForObject(...)
• HEAD - headForHeaders(...)
• OPTIONS - optionsForAllow(...)
• POST - postForLocation(...)
• PUT - put(...)
• any HTTP operation - exchange(...) and execute(...)
CONFIDENTIAL
159
205. Thin, Thick, Web, Mobile and Rich Clients: RestTemplate
Http Client
• The HttpComponents HttpClient is a native HTTP client
Message Converters
• MappingJacksonHttpMessageConverter - object to JSON marshaling supported via
the Jackson JSON Processor
• MarshallingXmlMessageConverter - converts objects to XML using Spring OXM
• SyndFeedHttpMessageConverter - RSS and Atom feeds supported via the Android
ROME Feed Reader
CONFIDENTIAL
160
206. Thin, Thick, Web, Mobile and Rich Clients: REST with Spring MVC
RestCustomerController - server
@Controller @RequestMapping(headers = "Accept=application/json, application/xml")
public class RestCustomerController {
@Autowired private CustomerService cs;
@RequestMapping(value = "/customer/{cid}", method = RequestMethod.POST)
@ResponseBody public Customer updateCustomer(@RequestBody Customer c) {
return cs.updateCustomer( c.getId(), c.getFirstName(), c.getLastName());
}
WebConfig - server
@EnableWebMvc
@Import(Config.class)
@Configuration
public class WebConfig
extends WebMvcConfigurerAdapter {}
client
Customer customer1 = restTemplate.getForEntity(
url + "customer/{customerId}",
Customer.class, c.getId()).getBody();
log.info("fetched customer " + customer1.toString());
161
207. DEMO
Demos:
• Spring REST service
• Spring REST client
Not confidential. Tell everyone.
209. Thin, Thick, Web, Mobile and Rich Clients: Mobile
Best strategy? Develop Native
• Fallback to client-optimized web applications
Spring MVC 3.1 mobile client-specific content negotiation and
rendering
• for other devices
• (there are other devices besides Android??)
164
210. Thin, Thick, Web, Mobile and Rich Clients: Mobile
WebConfig - server
! @Bean
public ViewResolver viewResolver() {
UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
viewResolver.setViewClass(TilesView.class);
return viewResolver;
}
@Bean
public TilesConfigurer tilesConfigurer() {
TilesConfigurer configurer = new TilesConfigurer();
configurer.setDefinitions(new String[]{
"/WEB-INF/layouts/tiles.xml",
"/WEB-INF/views/**/tiles.xml"
});
configurer.setCheckRefresh(true);
return configurer;
}
@Override
public void configureInterceptors(InterceptorConfigurer configurer) {
configurer.addInterceptor(new DeviceResolverHandlerInterceptor());
}
165
211. DEMO
Demos:
• Mobile clients using client specific rendering
Not confidential. Tell everyone.
213. Thin, Thick, Web, Mobile and Rich Clients: Mobile
Spring REST is ideal for mobile devices
Spring MVC 3.1 mobile client-specific content
negotiation and rendering
• for other devices
Spring Android
• RestTemplate
168
218. Thin, Thick, Web, Mobile and Rich Clients: Flex
Spring Flex
• Dead-simple to expose Spring beans as Flex services
• Developed with support from Adobe
• But it still has strengths:
• form driven apps
• video, 2D and 3D graphics, sound
• Adobe AIR
• blazing fast communication
• server side push
• Spring ActionScript is a cool framework “sponsored” by SpringSource
220. Thin, Thick, Web, Mobile and Rich Clients: RIA with Flex
Demos:
• exposing Spring services through BlazeDS
• consuming it from a Flex client
221. Thin, Thick, Web, Mobile and Rich Clients: GWT
Google Web Toolkit
• Lots of popular options
• We’ll look at building a simple example by simple delegating as
appropriate
• Server-side: standard DispatcherServlet
223. DEMO
Demos:
• building a simple GWT client that consumes services in Spring
Not confidential. Tell everyone.
224. Another Strategy....
HTML5 all the way!
• HTML5 on the desktop browser interface
• HTML5 + PhoneGap on the client
• RESTful services on the server side to connect it all
I NEED AN HTM
here!!!!
227. Spring Social
Extension to Spring Framework to enable connectivity with
Software-as-a-Service providers
Features...
• An extensible connection framework
• A connect controller
• Java API bindings
• A sign-in controller
http://www.springsource.org/spring-social
182
228. Spring Social Projects
Spring Social Core
Spring Social Facebook
Spring Social Twitter
Spring Social LinkedIn
Spring Social TripIt
Spring Social GitHub
Spring Social Gowalla
Spring Social Samples
• Includes Showcase, Quickstart, Movies, Canvas, Twitter4J, Popup
183
229. Key Steps to Socializing an Application
Configure Spring Social beans
• Connection Factory Locator and Connection Factories
• Connection Repository
• Connect Controller
• API Bindings
Create connection status views
Inject/use API bindings
184
230. Configuration: ConnectionFactoryLocator
@Bean
@Scope(value="singleton", proxyMode=ScopedProxyMode.INTERFACES)
public ConnectionFactoryLocator connectionFactoryLocator() {
ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();
registry.addConnectionFactory(
new TwitterConnectionFactory(
environment.getProperty("twitter.consumerKey"),
environment.getProperty("twitter.consumerSecret")));
registry.addConnectionFactory(
new FacebookConnectionFactory(
environment.getProperty("facebook.clientId"),
environment.getProperty("facebook.clientSecret")));
return registry;
}
185
231. Configuration: ConnectionFactoryLocator
@Bean
@Scope(value="singleton", proxyMode=ScopedProxyMode.INTERFACES)
public ConnectionFactoryLocator connectionFactoryLocator() {
ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();
registry.addConnectionFactory(
new TwitterConnectionFactory(
environment.getProperty("twitter.consumerKey"),
environment.getProperty("twitter.consumerSecret")));
registry.addConnectionFactory(
new FacebookConnectionFactory(
environment.getProperty("facebook.clientId"),
environment.getProperty("facebook.clientSecret")));
return registry;
}
185
232. Configuration: ConnectionFactoryLocator
@Bean
@Scope(value="singleton", proxyMode=ScopedProxyMode.INTERFACES)
public ConnectionFactoryLocator connectionFactoryLocator() {
ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();
registry.addConnectionFactory(
new TwitterConnectionFactory(
environment.getProperty("twitter.consumerKey"),
environment.getProperty("twitter.consumerSecret")));
registry.addConnectionFactory(
new FacebookConnectionFactory(
environment.getProperty("facebook.clientId"),
environment.getProperty("facebook.clientSecret")));
return registry;
}
185
233. Configuration: ConnectionFactoryLocator
@Bean
@Scope(value="singleton", proxyMode=ScopedProxyMode.INTERFACES)
public ConnectionFactoryLocator connectionFactoryLocator() {
ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();
registry.addConnectionFactory(
new TwitterConnectionFactory(
environment.getProperty("twitter.consumerKey"),
environment.getProperty("twitter.consumerSecret")));
registry.addConnectionFactory(
new FacebookConnectionFactory(
environment.getProperty("facebook.clientId"),
environment.getProperty("facebook.clientSecret")));
return registry;
}
185
234. Configuration: Connection Repository
@Bean
@Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
public ConnectionRepository connectionRepository() {
Authentication authentication = SecurityContextHolder.getContext().
getAuthentication();
if (authentication == null) {
throw new IllegalStateException(
"Unable to get a ConnectionRepository: no user signed in");
}
return usersConnectionRepository().createConnectionRepository(
authentication.getName());
}
186
235. Configuration: Connection Repository
@Bean
@Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
public ConnectionRepository connectionRepository() {
Authentication authentication = SecurityContextHolder.getContext().
getAuthentication();
if (authentication == null) {
throw new IllegalStateException(
"Unable to get a ConnectionRepository: no user signed in");
}
return usersConnectionRepository().createConnectionRepository(
authentication.getName());
}
@Bean
@Scope(value="singleton", proxyMode=ScopedProxyMode.INTERFACES)
public UsersConnectionRepository usersConnectionRepository() {
return new JdbcUsersConnectionRepository(
dataSource,
connectionFactoryLocator(),
Encryptors.noOpText());
}
186
236. Configuration: ConnectController
@Bean
public ConnectController connectController() {
return new ConnectController(connectionFactoryLocator(),
connectionRepository());
}
187
237. Configuration: ConnectController
@Bean
public ConnectController connectController() {
return new ConnectController(connectionFactoryLocator(),
connectionRepository());
}
187
238. Configuration: ConnectController
@Bean
public ConnectController connectController() {
return new ConnectController(connectionFactoryLocator(),
connectionRepository());
}
187
239. Configuration: API Bindings
@Bean
@Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
public Facebook facebook() {
Connection<Facebook> facebook =
connectionRepository().findPrimaryConnection(Facebook.class);
return facebook != null ? facebook.getApi() : new FacebookTemplate();
}
@Bean
@Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
public Twitter twitter() {
Connection<Twitter> twitter =
connectionRepository().findPrimaryConnection(Twitter.class);
return twitter != null ? twitter.getApi() : new TwitterTemplate();
}
188
240. Configuration: API Bindings
@Bean
@Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
public Facebook facebook() {
Connection<Facebook> facebook =
connectionRepository().findPrimaryConnection(Facebook.class);
return facebook != null ? facebook.getApi() : new FacebookTemplate();
}
@Bean
@Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
public Twitter twitter() {
Connection<Twitter> twitter =
connectionRepository().findPrimaryConnection(Twitter.class);
return twitter != null ? twitter.getApi() : new TwitterTemplate();
}
188
241. Configuration: API Bindings
@Bean
@Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
public Facebook facebook() {
Connection<Facebook> facebook =
connectionRepository().findPrimaryConnection(Facebook.class);
return facebook != null ? facebook.getApi() : new FacebookTemplate();
}
@Bean
@Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
public Twitter twitter() {
Connection<Twitter> twitter =
connectionRepository().findPrimaryConnection(Twitter.class);
return twitter != null ? twitter.getApi() : new TwitterTemplate();
}
188
242. Configuration: API Bindings
@Bean
@Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
public Facebook facebook() {
Connection<Facebook> facebook =
connectionRepository().findPrimaryConnection(Facebook.class);
return facebook != null ? facebook.getApi() : new FacebookTemplate();
}
@Bean
@Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
public Twitter twitter() {
Connection<Twitter> twitter =
connectionRepository().findPrimaryConnection(Twitter.class);
return twitter != null ? twitter.getApi() : new TwitterTemplate();
}
188
243. Injecting and Using the API Bindings
@Controller
public class TwitterTimelineController {
private final Twitter twitter;
@Inject
public TwitterTimelineController(Twitter twitter) {
this.twitter = twitter;
}
@RequestMapping(value="/twitter/tweet",
method=RequestMethod.POST)
public String postTweet(String message) {
twitter.timelineOperations().updateStatus(message);
return "redirect:/twitter";
}
}
189
244. Injecting and Using the API Bindings
@Controller
public class TwitterTimelineController {
private final Twitter twitter;
@Inject
public TwitterTimelineController(Twitter twitter) {
this.twitter = twitter;
}
@RequestMapping(value="/twitter/tweet",
method=RequestMethod.POST)
public String postTweet(String message) {
twitter.timelineOperations().updateStatus(message);
return "redirect:/twitter";
}
}
189
245. Injecting and Using the API Bindings
@Controller
public class TwitterTimelineController {
private final Twitter twitter;
@Inject
public TwitterTimelineController(Twitter twitter) {
this.twitter = twitter;
}
@RequestMapping(value="/twitter/tweet",
method=RequestMethod.POST)
public String postTweet(String message) {
twitter.timelineOperations().updateStatus(message);
return "redirect:/twitter";
}
}
189
246. ConnectController Endpoints
GET /connect
• Displays connection status for all providers
GET /connect/{provider}
• Displays connection status for a given provider
POST /connect/{provider}
• Initiates the authorization flow, redirecting to the provider
GET /connect/{provider}?oauth_token={token}
• Handles an OAuth 1 callback
GET /connect/{provider}?code={authorization code}
• Handles an OAuth 2 callback
DELETE /connect/{provider}
• Removes all connections for a user to the given provider
DELETE /connect/{provider}/{provider user ID}
• Removes a specific connection for the user to the given provider
190
247. ConnectController Flow
Your Application
ConnectController
Service Provider
(Twitter, Facebook, etc)
191
Editor's Notes
\n
\n\n
Hello, thank you or having me. Im pleased to have the opportunity to introduce you today to Spring and the SpringSource Tool Suite \n\nMy anem is Josh Long. I serve as the developer advocate for the Spring framework. I&#x2019;ve used it in earnest and advocated it for many years now. i&#x2019;m an author on 3 books on the technology, as well as a comitter to many of the Spring projects. Additionally, I take community activism very seriously and do my best to participate in the community. Sometimes this means answering question on Twitter, or in the forums, or helping contribute to the InfoQ.com and Artima.com communities\n
\n
\n
\n
these different framerworks let u tackle any problem youre likely to want to solve today \n- we support javee1.4 + 1.5 + 1.6; \n\nsits above target platform \nruns in cloud \n\n
\n
there are lots of frameworks to solve lots of problems\nthey all use the same pojo metaphor\nlets review some ofthem ... \nnaturally, the best part is that you can pick and choose - architecture a la carte! these are just lbiraris you can add to your applications, after all \n
this is the heart of Spring, and DI and IOC. the rest is learning about application of DI/IOC\n
this is the heart of Spring, and DI and IOC. the rest is learning about application of DI/IOC\n
this is the heart of Spring, and DI and IOC. the rest is learning about application of DI/IOC\n
\n
\n
\n
\n
\n
\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
the toolchain is STS, java compiler (no startup scripts required!) \nintroduce Spring Roo\nintroduce the Appcontexts\nintroduce the various Di configuration types \n\n
\n
Spring has the world view of all the objects in your object graph, and it gives you full control over that world viw\n\nYou can intercept object creation and prescribe changes to how things are built\n\nyou have low level mechanisms like BPPs and BFPPs which allow you to veto, override or merely observe the creation of objects\n\nu have AOP to lalow u to treat things like mehtod invocation as events\n
the toolchain is STS, java compiler (no startup scripts required!) \nintroduce Spring Roo\nintroduce the Appcontexts\nintroduce the various Di configuration types \n\n
\n
this is the heart of Spring, and DI and IOC. the rest is learning about application of DI/IOC\n
this is the heart of Spring, and DI and IOC. the rest is learning about application of DI/IOC\n
this is the heart of Spring, and DI and IOC. the rest is learning about application of DI/IOC\n
the toolchain is STS, java compiler (no startup scripts required!) \nintroduce Spring Roo\nintroduce the Appcontexts\nintroduce the various Di configuration types \n\n
\n
sometims, there are values that u cant get at using the main 3 types\n\nor, sometimes you have an object whose creation needs to be a) resuable and b) dynamic, based on permutations of certain dependencies. \n
this is the heart of Spring, and DI and IOC. the rest is learning about application of DI/IOC\n
this is the heart of Spring, and DI and IOC. the rest is learning about application of DI/IOC\n
this is the heart of Spring, and DI and IOC. the rest is learning about application of DI/IOC\n
\n\n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
this is the heart of Spring, and DI and IOC. the rest is learning about application of DI/IOC\n
\n\n
\n
\n
\n\n
\n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
\n
\n
\n
\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
\n
\n
\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
\n
Example of what can happen if you run processes more than correct number of times.\n
A better approach is decompose the war into a set of services.\nYou can do that either by nouns or by verbs.\n\n
\n
\n
\n
\n
\n
\n
\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
\n
\n
\n
\n
\n
\n
\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
\n
\n
One very popular open-source, message broker is RabbitMQ.\nIt designed to be robust, have high performance and be easy to use.\n\n
An interesting feature of RabbitMQ is that it implements a standard messaging protocol called AMQP.\nThis is quite different than JMS where each JMS implementation had its own java client libraries.\nAMQP is an efficient wire level protocol and is supported by multiple message brokers.\nThere are clients in multiple languages.\n\n
\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
The AMQP messaging model is a little different to JMS, for example.\n\nProducers write a message to an exchange\nConsumers read from a queue that is bound to exchange.\n\nWhether a message written to an exchange ends up in queue depends on the type of the exchange.\nThere are a few different types of exchange.\n\nOne standard type is the fanout exchange.\nA fanout exchange writes a message to all of the queues that are bound to it.\n\n
There is also a direct exchange.\nProducers write a message along with a routing key.\nQueues are bound to the exchange with a binding.\nif a message&#x2019;s routing key matches the binding then the message is written to that queue.\n\n
There is also a direct exchange.\nProducers write a message along with a routing key.\nQueues are bound to the exchange with a binding.\nif a message&#x2019;s routing key matches the binding then the message is written to that queue.\n\n
There is also a direct exchange.\nProducers write a message along with a routing key.\nQueues are bound to the exchange with a binding.\nif a message&#x2019;s routing key matches the binding then the message is written to that queue.\n\n
There is also a direct exchange.\nProducers write a message along with a routing key.\nQueues are bound to the exchange with a binding.\nif a message&#x2019;s routing key matches the binding then the message is written to that queue.\n\n
There is also a direct exchange.\nProducers write a message along with a routing key.\nQueues are bound to the exchange with a binding.\nif a message&#x2019;s routing key matches the binding then the message is written to that queue.\n\n
There is also a direct exchange.\nProducers write a message along with a routing key.\nQueues are bound to the exchange with a binding.\nif a message&#x2019;s routing key matches the binding then the message is written to that queue.\n\n
There is also a direct exchange.\nProducers write a message along with a routing key.\nQueues are bound to the exchange with a binding.\nif a message&#x2019;s routing key matches the binding then the message is written to that queue.\n\n
There is also a direct exchange.\nProducers write a message along with a routing key.\nQueues are bound to the exchange with a binding.\nif a message&#x2019;s routing key matches the binding then the message is written to that queue.\n\n
There is also a direct exchange.\nProducers write a message along with a routing key.\nQueues are bound to the exchange with a binding.\nif a message&#x2019;s routing key matches the binding then the message is written to that queue.\n\n
There is also a direct exchange.\nProducers write a message along with a routing key.\nQueues are bound to the exchange with a binding.\nif a message&#x2019;s routing key matches the binding then the message is written to that queue.\n\n
There is also a direct exchange.\nProducers write a message along with a routing key.\nQueues are bound to the exchange with a binding.\nif a message&#x2019;s routing key matches the binding then the message is written to that queue.\n\n
There are also topic exchanges, which basically implement pub/sub.\nHere the binding is can contain wildcards that are used to match against the message&#x2019;s routing key\n
There are also topic exchanges, which basically implement pub/sub.\nHere the binding is can contain wildcards that are used to match against the message&#x2019;s routing key\n
There are also topic exchanges, which basically implement pub/sub.\nHere the binding is can contain wildcards that are used to match against the message&#x2019;s routing key\n
There are also topic exchanges, which basically implement pub/sub.\nHere the binding is can contain wildcards that are used to match against the message&#x2019;s routing key\n
There are also topic exchanges, which basically implement pub/sub.\nHere the binding is can contain wildcards that are used to match against the message&#x2019;s routing key\n
There are also topic exchanges, which basically implement pub/sub.\nHere the binding is can contain wildcards that are used to match against the message&#x2019;s routing key\n
There are also topic exchanges, which basically implement pub/sub.\nHere the binding is can contain wildcards that are used to match against the message&#x2019;s routing key\n
There are also topic exchanges, which basically implement pub/sub.\nHere the binding is can contain wildcards that are used to match against the message&#x2019;s routing key\n
There are also topic exchanges, which basically implement pub/sub.\nHere the binding is can contain wildcards that are used to match against the message&#x2019;s routing key\n
There are also topic exchanges, which basically implement pub/sub.\nHere the binding is can contain wildcards that are used to match against the message&#x2019;s routing key\n
There are also topic exchanges, which basically implement pub/sub.\nHere the binding is can contain wildcards that are used to match against the message&#x2019;s routing key\n
There are also topic exchanges, which basically implement pub/sub.\nHere the binding is can contain wildcards that are used to match against the message&#x2019;s routing key\n
Spring AMQP is a project, which provides wrapper classes that simplify the development of messaging applications.\n
\n
\n
\n
\n
\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
\n
\n
\n
\n
\n
\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
\n
\n
\n
\n
\n
\n
\n
\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
\n
\n
\n
\n
\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pieces are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
\n
\n
\n
\n
\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
\n
\n
\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
\n
\n
\n
\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
another example of the fact that often the client side model won&#x2019;t represent the server side model \n\n
\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n
another example of the fact that often the client side model won&#x2019;t represent the server side model \n\n
talk about how convenient the messaging support is, then roll back and start looking at how u might do the same thing manually. Explain that many of the pices are already there, and then seguqe into a discussion about the core Spring APIs. Lets imagine we&#x2019;re going to build ourselves a file system poller to notify us of when something&#x2019;s happened on the file system\n\n