inside spring.io: a production spring reference application
DESCRIPTION
Speaker: Brian Clozel Core Spring Track Come take a look inside the newly open-sourced reference application that powers the http://spring.io site, including: Idiomatic use of Spring Boot Taking advantage of Spring Framework 4 features A tour of our JavaScript frontend using cujoJS's curl, Bower and Gulp for a clean and modular design Zero-downtime deployment to Cloud Foundry using blue/green deployments And more, with plenty of time for Q&ATRANSCRIPT
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
Inside spring.io: a Production Spring Reference Application
Brian Clozel - @brianclozel
Chris Beams at SpringOne 2013
Carl Sagan smiling at you
Now, seizing planets
And me!
…and, well, me.!
Brian Clozel !
• Spring Framework committer • Sagan developer • Bad at Photoshop
@brianclozel
The Plan!!
1. Open sourcing spring.io 2. Evolving spring.io 3. What’s next?
Open sourcing spring.io
Why did we open source Sagan?!!
• The Example/Sample App problem • The Reference App problem • We’re committed to Open Source
Enter Sagan application
Sagan: Blog
Sagan: Spring portfolio
Sagan: Spring guides
Sagan: search
Billions and billions of visitors
Available on GitHub!!• github.com/spring-io/sagan • BSD3-license • Master branch == running in production
Project Layout
Writing blog posts!!
• spring.io/blog • Project Sagan: open sourcing spring.io • Project Sagan: zero downtime deployments • Project Sagan: client side architecture • Project Sagan: upgrading to JDK 8
Embedded documentation
Partial/total rewrites!
• Getting started experience… • JDK8 features • Code architecture • Client side architecture
sagan-client
Build integration with Gradle 1/2
!// install NPM dependencies!task npmInstall(type:Exec) {! inputs.files "package.json", "bower.json"! outputs.dir "node_modules"! commandLine 'npm', 'install'!}!// run the Gulp.js build!task npmBuild(dependsOn: npmInstall, type:Exec) {! inputs.dir "src"! inputs.file "gulpfile.js"! outputs.dir "dist"! commandLine 'npm', 'run', 'build'!}
Build integration with Gradle 2/2
apply plugin: 'java'!// create a webjar to be served by the sagan-site module!jar {! from 'dist'! eachFile { ! details -> details.path = ! details.path.startsWith('META-INF') ?: 'static/'+details.path! }!}!!jar.dependsOn npmBuild
Modular JavaScript application
// using curl.js as a module loader!curl.config({! packages: {! app: { location: 'app'}! },! paths: {! jquery: 'lib/jquery/jquery.min',!! gmaps: {location: 'lib/gmaps/gmaps', config:cjsConfig }, ! }!});!!// Promises-based API for executing callbacks!curl(['app', 'jquery']).then(start, fail);
Gulp, a streaming build system
Gulp, a streaming build system
// concatenate and minify CSS files!gulp.task('minify-css', function() {! return gulp.src('src/css/*.css')! .pipe(cssmin({root: 'src/css'}))! .pipe(gulp.dest('./dist/css'));!});!!// tasks run in parallel!gulp.task('build', [‘minify-css', 'bower-files'], function(){ });
Gulp, a streaming build system
// using cram and uglify to concatenate and minify!gulp.task(‘build-modules', function() {! return cram(paths.run, opts).into("run.js")! .pipe(sourcemaps.init())! .pipe(uglify())! .pipe(sourcemaps.write("./"))! .pipe(gulp.dest('./dist/'));!})!
Early feedback for Spring Framework!
• Changed our opinion on Resource Handling • Real client side experience
• « Project Sagan: client-side architecture » • « JavaScript modularity, without the buzzwords »
Resource Handling in Spring 4.1 • Rossen Stoyanchev & Brian Clozel • Tomorrow 8:30AM
Spring Boot, in production > 1 year
“Spring Boot lets you pair-program with the Spring team. Josh Long, @starbuxman
Evolving spring.io
Writing code: JDK8
!List<String> projectVersions = project.getProjectReleases().stream()! .map(ProjectRelease::getVersion)! .collect(Collectors.toList());
Writing code: autoconfiguration
!@EnableAutoConfiguration // <- THIS!!@Configuration!@ComponentScan!public class AppConfiguration {!!}
(indirect use of) @Conditional
!@Conditional(CustomCondition.class)!@Configuration!public class AppConfiguration {!!}
Boot Actuators
!curl spring.io/info!!curl spring.io/autoconfig!!curl spring.io/health!!curl spring.io/beans!!* some endpoints are protected!
Remote shell with CRaSH
Distributed team!
HipChat +3rd party integrations
Issues management: waffle.io
Embracing continuous deployment• From first deploy live, SpringOne2GX 2013 • 100+ deploys last 3 months
Green/Blue deployments
Sagan Blue
instances
CF Router
(golang)
Sagan Green
instances
Green/Blue: Session management?!
• PWS default: sticky sessions • CF java-buildpack: session replication with Redis • No Sessions :-)
Green/Blue: DB schema updates?!
• Sagan: FlywayDB • Divide and conquer (read-only flags) • DB Store that fits your needs
General Advice: 12factor.net!
• codebase • dependencies • config • concurrency • logs • …
What’s next?
Sagan - services architecture
45
sagan-site
hosted on
GET http://spring.io
search
- get raw guides - render blogsElephantSQL
Sagan guides…
…are asciidoctor documents
Marketplace services
New Relic Java Agent
New Relic dashboard
Monitoring / Map
Sagan error rate
Application errors
Top transactions
First fix: using our CDN
Profiling threads
Template engine cache… disabled
An easy fix!
Monitoring transactions
Search transactions
Checking external services
Spring guides transactions
Search improvement: change service
Guides improvement: shared cache
Guides improvement: cache strategy
What do you think?
What I’ve learned!
• With small or distributed teams: • time spent on managing issues is important • contributor/developer experience is a top priority
• Always learn with monitoring, profiling • In cloud environments:
• you can throw resources at problems • or use the marketplace (scale better, save money)
Sagan is!
• An reference app • An open source project • A space for discussion and experiments • A JDK8, Spring 4, Spring Boot, critical app in production
Thanks!
@brianclozel