MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...
MongoDB for Java Devs with Spring Data - MongoPhilly 2011
1. SpringSource and MongoDB
Chris Richardson
Author of POJOs in Action
Founder of CloudFoundry.com
Chris.Richardson@SpringSource.Com
@crichardson
2. Presentation Goal
How SpringSource is
making it easier for
Java and Grails
developers to build
MongoDB applications
Slide 2
3. About Chris
• Grew up in England and live in Oakland, CA
• Over 25+ years of software development
experience including 14 years of Java
• Speaker at JavaOne, SpringOne, NFJS,
JavaPolis, Spring Experience, etc.
• Organize the Oakland JUG and the Groovy
Grails meetup
http://www.theregister.co.uk/2009/08/19/springsource_cloud_foundry/
Slide 3
4. Agenda
Introduction to Spring
Spring Data and MongoDB
Introduction to Grails
Using Grails with MongoDB
Slide 4
5. The Spring framework
Rapid evolution
! Spring 1.0 – March 2004
! Spring 2.0 – October 2006
! Spring 2.5 – December 2007
! Spring 3.0 – December 2009
! …
! Complete backward compatibility
De facto standard programming
model for enterprise Java
Two million+ developers
Slide 5
6. The Spring framework ecosystem
Framework Description
Spring framework The foundation
Spring.NET .NET port of the Spring framework
Spring Security (a.k.a. Acegi) Extensible framework providing authentication,
authorization and instance-level security
Spring Web Flow An excellent framework for building multi-page flows
Spring Web Services Contract-first, document–centric SOAP web services
Spring Dynamic Modules for OSGI Deploy Spring applications on OSGI
Spring Batch Powerful batch processing framework
Spring Integration Implements enterprise integration patterns
Spring BlazeDS integration Support for Adobe BlazeDS
Spring AMQP AMQP messaging, i.e. RabbitMQ
Spring Gemfire Simplify Gemfire application development
…
Slide 6
7. Spring programming model
Dependency Injection:
resolves inter-component Benefits:
dependencies, • Improved developer
metadata-driven productivity
• Higher quality code
• Portability across
application servers
POJO
Aspect-Oriented
Programming:
Portable Service modular
Abstractions: implementation of
Transactions, data cross cutting
access, … concerns
Slide 7
8. Portable service abstractions
Portable service
abstractions
insulate developer Business
Logic
from low-level
programming Infrastructure code
Less code Spring
Simpler code Transactions
Security
Data access
Increased
…
productivity
Portable code Runtime Environment
Slide 8
9. Spring JDBC example
@Repository
class ActorDaoImpl implements ActorDao {
SimpleJdbcTemplate hides
@Autowired the low-level, messy
private SimpleJdbcTemplate simpleJdbcTemplate; details of using JDBC
public Actor findActor(String specialty, int age) {
String sql = "select id, first_name, last_name from T_ACTOR" +
" where specialty = ? and age = ?";
RowMapper<Actor> mapper = new RowMapper<Actor>() {
public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
Actor actor = new Actor();
actor.setId(rs.getLong("id"));
actor.setFirstName(rs.getString("first_name"));
actor.setLastName(rs.getString("last_name"));
return actor;
}
};
return simpleJdbcTemplate.queryForObject(sql, mapper, specialty, age);
}
Slide 9
10. Externalized database configuration
@Configuration
public class AppConfig {
private @Value("#{jdbcProperties.url}") String jdbcUrl;
private @Value("#{jdbcProperties.username}") String username;
private @Value("#{jdbcProperties.password}") String password;
@Bean
public SimpleJdbcTemplate jdbcTemplate() {
return new SimpleJdbcTemplate (dataSource());
}
@Bean
public DataSource dataSource() {
return new DriverManagerDataSource(jdbcUrl, username, password);
}
}
Reads DB
configuration
<context:component-scan base-package="..."/> from file
<util:properties id="jdbcProperties" location="…/jdbc.properties"/>
Slide 10
11. Spring DataAccessException
Base class for
exceptions thrown by DataAccess
Exception
DAOs
Consistent exception Concurrency
Failure
Exception
...
handling across
Hibernate, JPA, JDBC, Optimistic
LockingFailure
etc. Exception Pessimistic
LockingFailure
Exception
Unchecked exception
Extensible exception CannotSerialize
mapping: CannotAcquire
LockException
Transaction
Exception
SqlExceptionTranslator
11
12. Agenda
Introduction to the Spring framework
Spring Data and MongoDB
Introduction to Grails
Using Grails with MongoDB
Slide 12
13. Spring Data Project Goals
Bring classic Spring value propositions
to a wide range of NoSQL databases:
! Productivity
! Programming model consistency: E.g.
<NoSQL>Template classes
! “Portability”
Many entry points to use
! Auto-generated repository implementations
! Opinionated APIs (Think JdbcTemplate)
! Object Mapping (Java and GORM)
! Cross Store Persistence Programming model
! Productivity support in Roo and Grails
Slide 13
14. MongoDB API usage patterns
Create and store Mongo singleton
Externalized server details
Inserts/Updates
! Map application POJO " DBObject
! mongo.getDatabase(…).getCollection(…)
! Partial document updates
Queries
! mongo.getDatabase(…).getCollection(…)
! Iterate through Cursor
! Map DBObject " application POJO
# Higher-level than JDBC but still repetitive,
…
Slide 14
15. Spring Data - MongoDB
MongoTemplate
Generic repository implementation
Querydsl integration
Cross-store persistence
Slide 15
17. Example entity
public class Restaurant {
private String id;
private String name;
private List<MenuItem> menuItems;
public Restaurant() {
} public class MenuItem {
private String name;
public Restaurant(String name) { private double price;
this.name = name;
… public MenuItem() {
} }
public String getName() { return name; } public MenuItem(String name,
double price) {
this.name = name;
public void setName(String name) {
this.price = price;
this.name = name;
} }
…getters and setters… …getters and setters…
Slide 17
18. Example data access code
@Repository
public class RestaurantRepository {
@Autowired
private MongoTemplate mongoTemplate;
public static final String RESTAURANTS_COLLECTION = "restaurants2";
public void add(Restaurant restaurant) {
mongoTemplate.save(RESTAURANTS_COLLECTION, restaurant);
}
public List<Restaurant> findRestaurantsByName(String restaurantName) {
return mongoTemplate.find(RESTAURANTS_COLLECTION,
new Query(where("name").is(restaurantName)),
Restaurant.class);
}
Slide 18
20. Spring MongoDB Example - Config
@Configuration public class MongoDbExampleConfig {
private @Value("#{mongoDbProperties.databaseName}") String mongoDbDatabase;
private @Value("#{mongoDbProperties.host}") String mongoDbHost;
@Bean public Mongo mongo() throws Exception { Singleton
return new Mongo(mongoDbHost);
}
@Bean public MongoTemplate mongoTemplate(Mongo mongo) {
return new MongoTemplate(mongo, mongoDbDatabase);
}…
<beans>
<context:annotation-config/>
External Config
<context:component-scan
base-package="net.chrisrichardson.mongodb.example"/>
mongodb.properties: <util:properties id="mongoDbProperties"
location="mongodb.properties"/>
databaseName=demo1
</beans>
host=192.168.253.150
Slide 20
21. Spring MongoDB Example Test
public class MongoDbExampleTest {
@Autowired private RestaurantRepository restaurantRepository;
@Test public void test() {
Restaurant ajanta = makeAjantaRestaurant();
restaurantRepository.add(ajanta);
List<Restaurant> results =
restaurantRepository.findRestaurantsByName("Ajanta");
assertRestaurantFound(ajanta, results);
}
private Restaurant makeAjantaRestaurant() {
Restaurant ajanta = new Restaurant("Ajanta");
ajanta.add(new MenuItem("Tandoori Portobello Mushrooms", 5.50));
ajanta.add(new MenuItem("Duck Curry Kerala", 15.00));
return ajanta;
}
…
Slide 21
22. Update example
@Repository
public class RestaurantRepository {
public void addMenuItem(String restaurantId,
MenuItem newMenuItem) {
DBObject dbo = new BasicDBObject();
mongoTemplate.getConverter().write(newMenuItem, dbo);
mongoTemplate.updateFirst(RESTAURANTS_COLLECTION,
new Query(where("_id").is(new ObjectId(restaurantId))),
new Update().push("menuItems", dbo));
}
Atomic, in-place update of document
Slide 22
23. Callbacks – access driver API with
exception translation
@Test
public void testDbCallback() { Exceptions are
Restaurant ajanta = makeAjantaRestaurant(); translated
restaurantRepository.add(ajanta);
assertCollectionExists("restaurants2");
}
private Void assertCollectionExists(final String collectionName) {
return mongoTemplate.execute(new DbCallback<Void>(){
@Override
public Void doInDB(DB db) {
Set<String> collectionNames = db.getCollectionNames();
Assert.assertTrue("Missing from " +
collectionNames,
collectionNames.contains(collectionName));
return null;
}});
}
Slide 23
24. Generic Mongo Repositories
Generic Repositories support
! Basic CRUD methods
! Dynamic finders
! Pagination and sorting
You define interface that extends
Repository interface
Spring Data generates Mongo-specific
implementation at runtime
Slide 24
25. Example Mongo Generic Repository
public class Person {
private ObjectId id;
private String firstname;
private String lastname;
… getters and setters
}
interface PersonRepository
extends MongoRepository<Person, ObjectId> {
List<Person> findByLastname(String lastName);
}
Person p = new Person("John", "Doe");
personRepository.save(p);
Person p2 = personRepository.findOne(p.getId());
List<Person> johnDoes = personRepository.findByLastname("Doe");
assertEquals(1, johnDoes.size());
Slide 25
26. Example Mongo Repository config
<bean>
<mongo:repositories
base-package="net.chrisrichardson.mongodb.example.mongorepository"
mongo-template-ref="mongoTemplate" />
</beans>
Scans classpath looking for
subtypes of MongoRepository
in the base package
Slide 26
27. Richer mapping Annotations define mapping:
@Document, @Id, @Indexed,
@PersistanceConstructor,
@Document @CompoundIndex, @DBRef,
public class Person { @GeoSpatialIndexed, @Value
@Id Map fields instead of properties "
private ObjectId id; no getters or setters required
private String firstname;
Non-default constructor
@Indexed
private String lastname; Index generation
@PersistenceConstructor
public Person(String firstname, String lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
….
}
Slide 27
28. Richer mapping configuration
@Configuration
public class MongoExampleConfig extends AbstractMongoConfiguration
{
…
@Override
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongo(),
mongoDbDatabase, null,
mappingMongoConverter());
}
@Override
public String getMappingBasePackage() {
return Person.class.getPackage().getName();
}
}
Slide 28
29. Support for the QueryDSL project
Generated from Type-safe
domain model class composable queries
QPerson person = QPerson.person;
Predicate predicate =
person.homeAddress.street1.eq("1 High Street")
.and(person.firstname.eq("John"))
List<Person> people = personRepository.findAll(predicate);
assertEquals(1, people.size());
assertPersonEquals(p, people.get(0));
Slide 29
30. Cross-store/polyglot persistence
Person person = new Person(…);
@Entity
public class Person { entityManager.persist(person);
// In Database
@Id private Long id; Person p2 = entityManager.find(…)
private String firstname;
private String lastname;
// In MongoDB
@RelatedDocument private Address address;
{ "_id" : ObjectId(”….."),
"_entity_id" : NumberLong(1),
"_entity_class" : "net.. Person",
"_entity_field_name" : "address",
"zip" : "94611", "street1" : "1 High Street", …}
Slide 30
31. Spring MongoDB – Future Ideas
MongoTemplate
! Support common map-reduce operations
from Mongo Cookbook
! GridFS integration
Tighter integration with Spring MVC
for activity monitoring
! See current example code on github
Slide 31
32. Agenda
Introduction to Spring
Spring Data and MongoDB
Introduction to Grails
Using Grails with MongoDB
Slide 32
33. Grails
Open-source web application framework
Uses Groovy – dynamic programming language
for the JVM
Builds on mature frameworks such as Spring
Slide 33
34. GORM = Grails Object Relational Mapping
Uses convention over configuration
! Defaults for which classes to persist
! Defaults for their O/R mapping
Leverages the meta-object protocol
! Adds persistence methods and properties to
domain classes
! No equivalent of Hibernate Session
! Avoids the need for dependency injection
! Eliminates many DAO cookie-cutter methods
Slide 34
35. Database access made easy
customer
class Customer { <<table>>
String name id <<pk>>
} version
name
Customer c = new Customer("John Doe")
if (!c.save())
fail "validation failed: ${c.errors}" GORM adds
Methods and
Customer c2 = Customer.get(c.id) properties to class
at runtime
c2.delete()
assertNull Customer.get(c.id)
def customers = Customer.findAllByName(“Fred”)
Slide 35
36. Relationships don’t have to be difficult
customer
class Customer { <<table>>
String name id <<pk>>
static hasMany = [ accounts : Account] version
} name
class Account {
account
static belongsTo = [customer: Customer] <<table>>
double balance
id <<pk>>
} version
customer <<fk>>
Customer c = <…> balance
Account a = new Account(…)
c.addToAccounts(a)
assertSame c, a.customer
assertTrue c.accounts.contains(a)
Slide 36
37. When the defaults aren’t right
class Customer {
static transients = ["networth"]
static mapping = {
id column: 'customer_id' crc_customer
<<table>>
table 'crc_customer'
columns { customer_id <<pk>>
version
name column: 'customer_name' customer_name
}
}
def getNetworth() { …}
…
}
Slide 37
38. Agenda
Introduction to Spring
Spring Data and MongoDB
Introduction to Grails
Using Grails with MongoDB
Slide 38
39. GORM for MongoDB
Extends GORM to support MongoDB
Announced Nov 2010
Currently 1.0M5
Builds on
! Spring Data for MongoDB
! Spring Data Mapping
Slide 39
40. GORM/MongoDB example
grails uninstall-plugin hibernate
grails install-plugin mongodb
class Customer {
String name Unchanged
Address address
static hasMany = [ accounts : Account]
static embedded = ['address']
} class Address {
String street
class Account { String city
static belongsTo = [customer: Customer] String state
double balance String zip
} }
DataSource.groovy
mongo {
host = "localhost"
}
Slide 40
42. Cloud Foundry supports Mongo
MongoDB is one of the provided services
" Deploy your MongoDB applications in
seconds
Slide 42
43. Summary
Polyglot persistence is here to stay
Spring Data is here to help you
GORM let’s you use the familiar and
powerful GORM API with MongoDB
Deploy your Mongo application on
CloudFoundry.com
More info at
! http://www.springframework.org/spring-data
! http://www.cloudfoundry.com/
Slide 43
44. Next steps
Checkout Spring Data
Consider contributing
Deploy on CloudFoundry.com
My contact information
chris.richardson@springsource.com
Twitter: @crichardson
Slide 44