From abba0d63feae9c6e53e777a85765c5db70588070 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 13 Mar 2014 13:15:33 -0700 Subject: [PATCH 1/4] Add documentation tool-chain Generate html, pdf and epub documentation using asciidoctor+docbook. See gh-295 --- spring-boot-docs/pom.xml | 216 ++++++- spring-boot-docs/src/main/asciidoc/.gitignore | 2 + spring-boot-docs/src/main/asciidoc/Guardfile | 20 + .../src/main/asciidoc/index-docinfo.xml | 13 + spring-boot-docs/src/main/asciidoc/index.adoc | 34 + .../src/main/docbook/css/highlight.css | 35 + .../src/main/docbook/css/manual-multipage.css | 9 + .../main/docbook/css/manual-singlepage.css | 6 + .../src/main/docbook/css/manual.css | 313 +++++++++ .../src/main/docbook/images/background.png | Bin 0 -> 10947 bytes .../src/main/docbook/images/caution.png | Bin 0 -> 2099 bytes .../src/main/docbook/images/important.png | Bin 0 -> 2085 bytes .../src/main/docbook/images/logo.png | Bin 0 -> 46269 bytes .../src/main/docbook/images/note.png | Bin 0 -> 2257 bytes .../src/main/docbook/images/tip.png | Bin 0 -> 931 bytes .../src/main/docbook/images/warning.png | Bin 0 -> 2130 bytes .../src/main/docbook/xsl/common.xsl | 44 ++ .../src/main/docbook/xsl/epub.xsl | 30 + .../src/main/docbook/xsl/html-multipage.xsl | 73 +++ .../src/main/docbook/xsl/html-singlepage.xsl | 30 + .../src/main/docbook/xsl/html.xsl | 117 ++++ spring-boot-docs/src/main/docbook/xsl/pdf.xsl | 608 ++++++++++++++++++ .../src/main/docbook/xsl/xslthl-config.xml | 20 + .../main/docbook/xsl/xslthl/asciidoc-hl.xml | 41 ++ .../src/main/docbook/xsl/xslthl/bourne-hl.xml | 95 +++ .../src/main/docbook/xsl/xslthl/c-hl.xml | 117 ++++ .../src/main/docbook/xsl/xslthl/cpp-hl.xml | 151 +++++ .../src/main/docbook/xsl/xslthl/csharp-hl.xml | 194 ++++++ .../src/main/docbook/xsl/xslthl/css-hl.xml | 176 +++++ .../src/main/docbook/xsl/xslthl/html-hl.xml | 122 ++++ .../src/main/docbook/xsl/xslthl/ini-hl.xml | 45 ++ .../src/main/docbook/xsl/xslthl/java-hl.xml | 117 ++++ .../main/docbook/xsl/xslthl/javascript-hl.xml | 147 +++++ .../src/main/docbook/xsl/xslthl/perl-hl.xml | 120 ++++ .../src/main/docbook/xsl/xslthl/php-hl.xml | 154 +++++ .../src/main/docbook/xsl/xslthl/python-hl.xml | 100 +++ .../src/main/docbook/xsl/xslthl/ruby-hl.xml | 109 ++++ .../main/docbook/xsl/xslthl/sql2003-hl.xml | 565 ++++++++++++++++ 38 files changed, 3818 insertions(+), 5 deletions(-) create mode 100644 spring-boot-docs/src/main/asciidoc/.gitignore create mode 100644 spring-boot-docs/src/main/asciidoc/Guardfile create mode 100644 spring-boot-docs/src/main/asciidoc/index-docinfo.xml create mode 100644 spring-boot-docs/src/main/asciidoc/index.adoc create mode 100644 spring-boot-docs/src/main/docbook/css/highlight.css create mode 100644 spring-boot-docs/src/main/docbook/css/manual-multipage.css create mode 100644 spring-boot-docs/src/main/docbook/css/manual-singlepage.css create mode 100644 spring-boot-docs/src/main/docbook/css/manual.css create mode 100644 spring-boot-docs/src/main/docbook/images/background.png create mode 100644 spring-boot-docs/src/main/docbook/images/caution.png create mode 100644 spring-boot-docs/src/main/docbook/images/important.png create mode 100644 spring-boot-docs/src/main/docbook/images/logo.png create mode 100644 spring-boot-docs/src/main/docbook/images/note.png create mode 100644 spring-boot-docs/src/main/docbook/images/tip.png create mode 100644 spring-boot-docs/src/main/docbook/images/warning.png create mode 100644 spring-boot-docs/src/main/docbook/xsl/common.xsl create mode 100644 spring-boot-docs/src/main/docbook/xsl/epub.xsl create mode 100644 spring-boot-docs/src/main/docbook/xsl/html-multipage.xsl create mode 100644 spring-boot-docs/src/main/docbook/xsl/html-singlepage.xsl create mode 100644 spring-boot-docs/src/main/docbook/xsl/html.xsl create mode 100644 spring-boot-docs/src/main/docbook/xsl/pdf.xsl create mode 100644 spring-boot-docs/src/main/docbook/xsl/xslthl-config.xml create mode 100644 spring-boot-docs/src/main/docbook/xsl/xslthl/asciidoc-hl.xml create mode 100644 spring-boot-docs/src/main/docbook/xsl/xslthl/bourne-hl.xml create mode 100644 spring-boot-docs/src/main/docbook/xsl/xslthl/c-hl.xml create mode 100644 spring-boot-docs/src/main/docbook/xsl/xslthl/cpp-hl.xml create mode 100644 spring-boot-docs/src/main/docbook/xsl/xslthl/csharp-hl.xml create mode 100644 spring-boot-docs/src/main/docbook/xsl/xslthl/css-hl.xml create mode 100644 spring-boot-docs/src/main/docbook/xsl/xslthl/html-hl.xml create mode 100644 spring-boot-docs/src/main/docbook/xsl/xslthl/ini-hl.xml create mode 100644 spring-boot-docs/src/main/docbook/xsl/xslthl/java-hl.xml create mode 100644 spring-boot-docs/src/main/docbook/xsl/xslthl/javascript-hl.xml create mode 100644 spring-boot-docs/src/main/docbook/xsl/xslthl/perl-hl.xml create mode 100644 spring-boot-docs/src/main/docbook/xsl/xslthl/php-hl.xml create mode 100644 spring-boot-docs/src/main/docbook/xsl/xslthl/python-hl.xml create mode 100644 spring-boot-docs/src/main/docbook/xsl/xslthl/ruby-hl.xml create mode 100644 spring-boot-docs/src/main/docbook/xsl/xslthl/sql2003-hl.xml diff --git a/spring-boot-docs/pom.xml b/spring-boot-docs/pom.xml index a7fa6d362d6..b6df30060f7 100644 --- a/spring-boot-docs/pom.xml +++ b/spring-boot-docs/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.springframework.boot @@ -41,7 +42,6 @@ - org.apache.maven.plugins maven-javadoc-plugin @@ -65,9 +65,183 @@ + + org.asciidoctor + asciidoctor-maven-plugin + 0.1.4 + + + generate-docbook + generate-resources + + process-asciidoc + + + index.adoc + docbook5 + book + + true + ${project.version} + ${project.version} + ${spring-boot-repo} + ${github-tag} + + + + + + + com.agilejava.docbkx + docbkx-maven-plugin + 2.0.15 + + ${basedir}/target/generated-docs + index.xml + true + false + ${basedir}/src/main/docbook/xsl/pdf.xsl + 1 + 1 + ${basedir}/src/main/docbook/xsl/xslthl-config.xml + + + + net.sf.xslthl + xslthl + 2.1.0 + + + net.sf.docbook + docbook-xml + 5.0-all + resources + zip + runtime + + + + + html-single + + generate-html + + generate-resources + + ${basedir}/src/main/docbook/xsl/html-singlepage.xsl + ${basedir}/target/docbook/htmlsingle + + + + + + + + + + + + + + + + + + + html + + generate-html + + generate-resources + + ${basedir}/src/main/docbook/xsl/html-multipage.xsl + ${basedir}/target/docbook/html + true + + + + + + + + + + + + + + + + + + + pdf + + generate-pdf + + generate-resources + + ${basedir}/src/main/docbook/xsl/pdf.xsl + ${basedir}/target/docbook/pdf + + + + + + + + + + + + epub + + generate-epub3 + + generate-resources + + ${basedir}/src/main/docbook/xsl/epub.xsl + ${basedir}/target/docbook/epub + + + + + + + + + + + + org.apache.maven.plugins maven-antrun-plugin + + + ant-contrib + ant-contrib + 1.0b3 + + + ant + ant + + + + + org.apache.ant + ant-nodeps + 1.8.1 + + + org.tigris.antelope + antelopetasks + 3.2.10 + + package-and-attach-docs-zip @@ -77,10 +251,42 @@ - - + + + - + + + + + setup-maven-properties + validate + + run + + + true + + + + + + + + + + + + + diff --git a/spring-boot-docs/src/main/asciidoc/.gitignore b/spring-boot-docs/src/main/asciidoc/.gitignore new file mode 100644 index 00000000000..bbc3411176c --- /dev/null +++ b/spring-boot-docs/src/main/asciidoc/.gitignore @@ -0,0 +1,2 @@ +*.html +*.css diff --git a/spring-boot-docs/src/main/asciidoc/Guardfile b/spring-boot-docs/src/main/asciidoc/Guardfile new file mode 100644 index 00000000000..bdd4d729819 --- /dev/null +++ b/spring-boot-docs/src/main/asciidoc/Guardfile @@ -0,0 +1,20 @@ +require 'asciidoctor' +require 'erb' + +guard 'shell' do + watch(/.*\.adoc$/) {|m| + Asciidoctor.render_file('index.adoc', \ + :in_place => true, \ + :safe => Asciidoctor::SafeMode::UNSAFE, \ + :attributes=> { \ + 'source-highlighter' => 'prettify', \ + 'icons' => 'font', \ + 'linkcss'=> 'true', \ + 'copycss' => 'true', \ + 'doctype' => 'book'}) + } +end + +guard 'livereload' do + watch(%r{^.+\.(css|js|html)$}) +end diff --git a/spring-boot-docs/src/main/asciidoc/index-docinfo.xml b/spring-boot-docs/src/main/asciidoc/index-docinfo.xml new file mode 100644 index 00000000000..408aa7af6b3 --- /dev/null +++ b/spring-boot-docs/src/main/asciidoc/index-docinfo.xml @@ -0,0 +1,13 @@ +Spring Boot +{spring-boot-version} + + 2013-2014 + + + + Copies of this document may be made for your own use and for distribution to + others, provided that you do not charge any fee for such copies and further + provided that each copy contains this Copyright Notice, whether distributed in + print or electronically. + + diff --git a/spring-boot-docs/src/main/asciidoc/index.adoc b/spring-boot-docs/src/main/asciidoc/index.adoc new file mode 100644 index 00000000000..82f12e55392 --- /dev/null +++ b/spring-boot-docs/src/main/asciidoc/index.adoc @@ -0,0 +1,34 @@ += Spring Boot Reference Guide +Phillip Webb; Dave Syer; +:doctype: book +:toc: +:toclevels: 4 +:source-highlighter: prettify +:numbered: +:icons: font +:spring-boot-repo: snapshot +:github-tag: master +:spring-boot-docs-version: current +:github-repo: spring-projects/spring-boot +:github-raw: http://raw.github.com/{github-repo}/{github-tag} +:github-code: http://github.com/{github-repo}/tree/{github-tag} +:sc-ext: java +:sc-spring-boot: {github-code}/spring-boot/src/main/java/org/springframework/boot +:sc-spring-boot-autoconfigure: {github-code}/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure +:sc-spring-boot-actuator: {github-code}/spring-boot-actuator/src/main/java/org/springframework/boot/actuate +:sc-spring-boot-cli: {github-code}/spring-boot-cli/src/main/java/org/springframework/boot/cli +:dc-ext: html +:dc-root: http://docs.spring.io/spring-boot/docs/{spring-boot-docs-version}/api +:dc-spring-boot: {dc-root}/org/springframework/boot +:dc-spring-boot-autoconfigure: {dc-root}/org/springframework/boot/autoconfigure +:dc-spring-boot-actuator: {dc-root}/org/springframework/boot/actuate +:spring-reference: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle +:spring-data-javadoc: http://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa +:spring-data-commons-javadoc: http://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data +:spring-data-mongo-javadoc: http://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb +// ====================================================================================== + += Spring Boot +== Reference Documentation + +// ====================================================================================== diff --git a/spring-boot-docs/src/main/docbook/css/highlight.css b/spring-boot-docs/src/main/docbook/css/highlight.css new file mode 100644 index 00000000000..ffefef72de8 --- /dev/null +++ b/spring-boot-docs/src/main/docbook/css/highlight.css @@ -0,0 +1,35 @@ +/* + code highlight CSS resemblign the Eclipse IDE default color schema + @author Costin Leau +*/ + +.hl-keyword { + color: #7F0055; + font-weight: bold; +} + +.hl-comment { + color: #3F5F5F; + font-style: italic; +} + +.hl-multiline-comment { + color: #3F5FBF; + font-style: italic; +} + +.hl-tag { + color: #3F7F7F; +} + +.hl-attribute { + color: #7F007F; +} + +.hl-value { + color: #2A00FF; +} + +.hl-string { + color: #2A00FF; +} \ No newline at end of file diff --git a/spring-boot-docs/src/main/docbook/css/manual-multipage.css b/spring-boot-docs/src/main/docbook/css/manual-multipage.css new file mode 100644 index 00000000000..0c484531c5c --- /dev/null +++ b/spring-boot-docs/src/main/docbook/css/manual-multipage.css @@ -0,0 +1,9 @@ +@IMPORT url("manual.css"); + +body.firstpage { + background: url("../images/background.png") no-repeat center top; +} + +div.part h1 { + border-top: none; +} diff --git a/spring-boot-docs/src/main/docbook/css/manual-singlepage.css b/spring-boot-docs/src/main/docbook/css/manual-singlepage.css new file mode 100644 index 00000000000..4a7fd14002c --- /dev/null +++ b/spring-boot-docs/src/main/docbook/css/manual-singlepage.css @@ -0,0 +1,6 @@ +@IMPORT url("manual.css"); + +body { + background: url("../images/background.png") no-repeat center top; +} + diff --git a/spring-boot-docs/src/main/docbook/css/manual.css b/spring-boot-docs/src/main/docbook/css/manual.css new file mode 100644 index 00000000000..7170c737ec4 --- /dev/null +++ b/spring-boot-docs/src/main/docbook/css/manual.css @@ -0,0 +1,313 @@ +@IMPORT url("highlight.css"); + +html { + padding: 0pt; + margin: 0pt; +} + +body { + color: #333333; + margin: 15px 30px; + font-family: Helvetica, Arial, Freesans, Clean, Sans-serif; + line-height: 1.6; + -webkit-font-smoothing: antialiased; +} + +code { + font-size: 16px; + font-family: Consolas, "Liberation Mono", Courier, monospace; + color: #6D180B; +} + +:not(pre) > code { + background-color: #F2F2F2; + border: 1px solid #CCCCCC; + border-radius: 4px; + padding: 1px 3px 0; + text-shadow: none; + white-space: nowrap; +} + +body>*:first-child { + margin-top: 0 !important; +} + +div { + margin: 0pt; +} + +hr { + border: 1px solid #CCCCCC; + background: #CCCCCC; +} + +h1,h2,h3,h4,h5,h6 { + color: #000000; + cursor: text; + font-weight: bold; + margin: 30px 0 10px; + padding: 0; +} + +h1,h2,h3 { + margin: 40px 0 10px; +} + +h1 { + margin: 70px 0 30px; + padding-top: 20px; +} + +div.part h1 { + border-top: 1px dotted #CCCCCC; +} + +h1,h1 code { + font-size: 32px; +} + +h2,h2 code { + font-size: 24px; +} + +h3,h3 code { + font-size: 20px; +} + +h4,h1 code,h5,h5 code,h6,h6 code { + font-size: 18px; +} + +div.book,div.chapter,div.appendix,div.part,div.preface { + min-width: 300px; + max-width: 1200px; + margin: 0 auto; +} + +p.releaseinfo { + font-weight: bold; + margin-bottom: 40px; + margin-top: 40px; +} + +div.authorgroup { + line-height: 1; +} + +p.copyright { + line-height: 1; + margin-bottom: -5px; +} + +.legalnotice p { + font-style: italic; + font-size: 14px; + line-height: 1; +} + +div.titlepage+p,div.titlepage+p { + margin-top: 0; +} + +pre { + line-height: 1.0; + color: black; +} + +a { + color: #4183C4; + text-decoration: none; +} + +p { + margin: 15px 0; + text-align: left; +} + +ul,ol { + padding-left: 30px; +} + +li p { + margin: 0; +} + +div.table { + margin: 1em; + padding: 0.5em; + text-align: center; +} + +div.table table, div.informaltable table { + display: table; + width: 100%; +} + +div.table td { + padding-left: 7px; + padding-right: 7px; +} + +.sidebar { + line-height: 1.4; + padding: 0 20px; + background-color: #F8F8F8; + border: 1px solid #CCCCCC; + border-radius: 3px 3px 3px 3px; +} + +.sidebar p.title { + color: #6D180B; +} + +pre.programlisting, pre.screen { + font-size: 15px; + padding: 6px 10px; + background-color: #F8F8F8; + border: 1px solid #CCCCCC; + border-radius: 3px 3px 3px 3px; + clear: both; + overflow: auto; + line-height: 1.4; + font-family: Consolas,"Liberation Mono",Courier,monospace; +} + +table { + border-collapse: collapse; + border-spacing: 0; + border: 1px solid #DDDDDD !important; + border-radius: 4px !important; + border-collapse: separate !important; + line-height: 1.6; +} + +table thead { + background: #F5F5F5; +} + +table tr { + border: none; + border-bottom: none; +} + +table th { + font-weight: bold; +} + +table th,table td { + border: none !important; + padding: 6px 13px; +} + +table tr:nth-child(2n) { + background-color: #F8F8F8; +} + +td p { + margin: 0 0 15px 0; +} + +div.table-contents td p { + margin: 0; +} + +div.important *,div.note *,div.tip *,div.warning *,div.navheader *,div.navfooter *,div.calloutlist * { + border: none !important; + background: none !important; + margin: 0; +} + +div.important p,div.note p,div.tip p,div.warning p { + color: #6F6F6F; + line-height: 1.6; +} + +div.important code,div.note code,div.tip code,div.warning code { + background-color: #F2F2F2 !important; + border: 1px solid #CCCCCC !important; + border-radius: 4px !important; + padding: 1px 3px 0 !important; + text-shadow: none !important; + white-space: nowrap !important; +} + + +.note th,.tip th,.warning th { + display: none; +} + +.note tr:first-child td,.tip tr:first-child td,.warning tr:first-child td { + border-right: 1px solid #CCCCCC !important; + padding-top: 10px; +} + + +div.calloutlist p, div.calloutlist td { + padding: 0; + margin: 0; +} + +div.calloutlist > table > tbody > tr > td:first-child { + padding-left: 10px; + width: 30px !important; +} + +div.important,div.note,div.tip,div.warning { + margin-left: 0px !important; + margin-right: 20px !important; + margin-top: 20px; + margin-bottom: 20px; + padding-top: 10px; + padding-bottom: 10px; +} + +div.toc { + line-height: 1.2; +} + +dl,dt { + margin-top: 1px; + margin-bottom: 0; +} + +div.toc > dl > dt { + font-size: 32px; + font-weight: bold; + margin: 30px 0 10px 0; + display: block; +} + +div.toc > dl > dd > dl > dt { + font-size: 24px; + font-weight: bold; + margin: 20px 0 10px 0; + display: block; +} + +div.toc > dl > dd > dl > dd > dl > dt { + font-weight: bold; + font-size: 20px; + margin: 10px 0 0 0; +} + +tbody.footnotes * { + border: none !important; +} + +div.footnote p { + margin: 0; + line-height: 1; +} + +div.footnote p sup { + margin-right: 6px; + vertical-align: middle; +} + +div.navheader { + border-bottom: 1px solid #CCCCCC; +} + +div.navfooter { + border-top: 1px solid #CCCCCC; +} diff --git a/spring-boot-docs/src/main/docbook/images/background.png b/spring-boot-docs/src/main/docbook/images/background.png new file mode 100644 index 0000000000000000000000000000000000000000..d4195e5b32cd5f878652c5195bd674a5a6304855 GIT binary patch literal 10947 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 literal 0 HcmV?d00001 diff --git a/spring-boot-docs/src/main/docbook/images/caution.png b/spring-boot-docs/src/main/docbook/images/caution.png new file mode 100644 index 0000000000000000000000000000000000000000..8a5e4fca039d0247dcf55ae0e719cdb457509422 GIT binary patch literal 2099 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 literal 0 HcmV?d00001 diff --git a/spring-boot-docs/src/main/docbook/images/logo.png b/spring-boot-docs/src/main/docbook/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..45f1978f3fde3661dc2d4131c7faa0c120188c5d GIT binary patch literal 46269 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%0ArS<p+tPz$YS|THxa0u-ohR#2Mkj!=(ogswU!H> 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 literal 0 HcmV?d00001 diff --git a/spring-boot-docs/src/main/docbook/images/note.png b/spring-boot-docs/src/main/docbook/images/note.png new file mode 100644 index 0000000000000000000000000000000000000000..88d997b17cfe703280d3a33e3f7c285a4ce6c8a6 GIT binary patch literal 2257 zcmbVOc~}!?8jt0%wJO?rR6vCx90KN;$uT)dKypElKnRgUJaCwd5Fm%i5JI?F5NZ{L zHB!K;6~%M$V1?>pq28#7tClK{yXb1Wwu?(E7V(JeM8)nOZvWVMX6F08ci!Lcy`N`3 zRmMkqPWG8hB9T1hF%lKAdbyuT9>n{*eLWY6#T%Du@g&n~JQuNGq$r&!4Flu`Bpp*> zh%RqUHzpvFJTmlZEv{9>@llh3hPZWTc7vHflSqO{yBR^VFdRt3()C6mdFU^lWI(SI zk~M4vs4$DM41J8lf+acP)u|5Q7d9H%x_Cd^XHyaDX=#nXqQj zt>&vFvNyJflaQQ&<7Pgco|~IX%Vp9`mUKGA-Zp( zOJtG50yzv2=0Xrx46(Qj83@V53@*$QjdQ#U%j3e3l*8gOAt(xhqztY^3`s$@h$SN! zBqG*0R&KQ7h!Mrc?dl1;Z?K%-#qz}#48ctnwaJt{-T}%C6K=9*n9P7U2?jzG2&y-_ z1)=T&y^dFcS@bqcC$pFgz^e@N_3!Y2&4rmVrc?^b{#WF$vAX{!YjnaHy1PC8t6j!L zL=U>RZ=0Vuyd59RNX(3d7!LK(`xl6rBPrw5(!bs96XC4+vN`n!pkNhnvKs;x&pmV! z^p5t4F5vmbc<*Tg!?VGlB>@XnzNdTWfhvE25$e1Mo;VNrFPPX7U z(3k?AET0>c;EQjdF;|7qmM;id8Z2DH;$?xdi*jLQS;UTmTiQ;84~KpVQTS}!1G7>???1T1M8Y2Y^v{gyWH4>vrEALt zW@fUDlD9Q{=doHaIiz}LsVtu#Tf|>gNSPn)uUj7xxbS*QsNLaH+;@qq1yM5)eX8Xer{FRzM~ z7xK|ff|w#cs13!6!+4oAeiqo&#|^o&-HT^JJ+1KLT73G&i2y$6Z`@c^KzV`9OsHC8!WcLRbRl_HObYx+233S$HvBP zx5xC8NE3$Tk|?#kKW%jS#1E2l4~Dm9y?iNEMtGE`{31iwDR0{;frQ`P~3kjC$lu_eqZs}wAR(baf^>n-dr`hd)oUmm$gnF zbD^_eYPM#zynGxf-a!tS6u8|n_+WHspz~^faii1kX{e03c}{&}W2fu+^!IEjlU-

MvJZJ$)LTqJA+@mbLxmkyPc#tU=W5xPJ%q2sZXv`v(Ui?>!8Tjh_mSOc$O+ zW<-$ZjJfV@LAsB%Biz5w(;fXV?CW1TB9(ujH2(XqZD*&_2O2L-EZJ~mTUSoq*g)q^ zQ!j3qa>DzQ*dH!xN(0O3n$-7HmkYk_eQXG-gI*K|{dncP!DXswNa?P_Z}nzo#*v#J zQ5S9ROsaZ%ZqC6y?VF!Q1^;o|wu*kH=E=`8B``9)uFtN|s?>Xw*7?*`wfqP}<_A~q zd8VVPq*k-7ZPhbSEogsT%F|x0xuT7xdRv7>Rev?4wv{qrDN}+xS$8V5!!ga&#Y1*BgqL?&c}jPc zG_JlfMSD5I%DQQcHXTbGWQtKpeL6yAB|UI5CQ=~#`}=c}Um;E%R)9u^qI0>&GHQ-g zOm;DCkym+{WF$}@UWrV1mtnTPtu!WtY$r7BOpo|N_#mqWGhK#KR0MD7eW*yPaY&xBTRfcG-E5p&`2dq z875XFdy+3GStd(wD_Mg`dys8Xd_houJju_&*4)mZt2Tk1H)DTRJY^_lf>>*ZU2Th5 zWQ3Ly{;kf91GM2s4Vfv8a-fcsXpb+4t> zmM%11X*>M&PQZNVdARf4d*2x!aq1>jOzQ?>>R)(Ok;sOJ)7jfk$Fdif23? z-}3V78&9qod*O;uGk%fEW^;|k`Lo>bOq2iF72o-IGb2gTw+4B~#iYz(oL}sS7|$R2 zDGfrR{|@~AQJ&v(#4u|ZtJP}t520N48P!$8U;|Vfuq=8>E$w`o2Jf`%eqhqbr%IH1zV?O3uDWqKZId-wMQ*MFefpD5X*w@ zok{kNA?%%$F{M!OUcE^^x{~(wkHK|_*9Yg`KNS88FaVH_sda1Xfs6nE002ovPDHLk FV1jwin)(0$ literal 0 HcmV?d00001 diff --git a/spring-boot-docs/src/main/docbook/images/warning.png b/spring-boot-docs/src/main/docbook/images/warning.png new file mode 100644 index 0000000000000000000000000000000000000000..0d5b5244605adbb7ab05a1549746a9c35490f95b GIT binary patch literal 2130 zcmbVNYg7|w8V(4q($)50y>JmGlLW#g$xLn}Vd2Si)}#|ptPAQp3Bp-3!-lL0;i^LY?;i#f0m5s49g z3h?3rDQg~EDPlm?FKkgKIcWEK-3X6YU0uzs7H|nq84s39r2!5;pF?SI$QqXy^Ko1x zV~zpENvp@<_Bsd`5MabC#3rvCq&$5dg43yGR zAdy0-rWjC#a1N_+kzUMY#pmogD7!DP(9dEKr3c5ngvUq_6>}Y+w-a81v=eSXnIi_+ zI?U>D1q2C!0zHox#XXKH+@|&rPT*OF5yvY$5J|)WwLqnU)c-5;=UChSlQkaY3@^|g z|J5#YBB}=i+n3Ex9bS$P?xJSKLk)-HHII@;3qG#TG^!+aj>0QkO~7kB0+|yM;YrGB zF>Ge@isQ#73%Tp#k_(tInh3U$uJWY-+DND*o}L-CB5g@#9YWWw~pxZ!Obm>yN#ZHFvL0zA3vNCTJ=t?)~`2O1M{L6un=ml<2x zQEYfifmA?Pz0tqRs^2Utt1pU0BQB1eIY0U_I}c1Y#PP7Ci5s7#IJn}xK{G+{_v^Z+1V#$Erodv>d}ew>RP0wzw+GWkGCBlS1Oj5Z!5NK zUuSR6>pa}RSEZ;qE_w1l#`hQX4E67U6NeP zHZ`T&wj0_H)t|Y1thUqnhub?%e)Y07;a^Tq%FO&iQkR&`qG!dh*2WfW(HuRQj*_DI zeCD1bUA|tMwjOb8E|FRIn$pzEU!2j_N}1Z2ig)vbr5xA0rjC70cmI6*%Uf->hWzaZ z{33HABO5q)vRhzDly2l691@+q3O{}NbSzx+I*k@|L4&3leK#$>u+T#TvTELfKb|IH zc23atf3vmfCa0&TWY@iuoA_Pm<0~ttEC*ut`isb^jXS>X^Sp=l?RXN_OJ*&usGXg$ zTlTv;Ch^vhLDf&+62jl64*&D+=+`sN_dap_1W%p|KQVYIdgPL5uRE9(c4On)DXndL zLNq?%!-u*zmMxyYc4m4Nr>>=A=s}PkJkqr&E^b9>5g+}c1%X}3|WKcg&spcJQ)05zI<<5LTBhNKRg$XRTi2{j)yl_ zj4~kKOvr+m(;vw~9zVh(zC-y9jqQnguz5r7FRq^MyKuXAENp(TAzUVtg&Ts+B_s7) zGn+fN0sG>9GjsPLKTRrvCd`71IZulJ1_1jO9KWbD&_@2UC+LTNpxxrdz#E|j|2nA9 zzB!UTyfAEJ&#%$pQ>QX#8vk@_a5iqukMF;8`wRKe{BI}5$H%OROs4J1#j)|?p|YSh z_SpR^e`VE#F52;WL{!+L(yZLRh40*KS;@box;9(-tE)`mcVp27O*>Z{_Lb*5T3cJA yr~0nPHtg2+UHi&&$8ha;`+hiaUmw&!n@8(?5PqF(KE5>Ym)EG)p&uyBP5%a8^# + + + + + + + 1 + 0 + 1 + + + + images/ + .png + + + book toc,title + 3 + + + + + diff --git a/spring-boot-docs/src/main/docbook/xsl/epub.xsl b/spring-boot-docs/src/main/docbook/xsl/epub.xsl new file mode 100644 index 00000000000..f545daf76ce --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/epub.xsl @@ -0,0 +1,30 @@ + + + + + + + + + + diff --git a/spring-boot-docs/src/main/docbook/xsl/html-multipage.xsl b/spring-boot-docs/src/main/docbook/xsl/html-multipage.xsl new file mode 100644 index 00000000000..56d9673a7c5 --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/html-multipage.xsl @@ -0,0 +1,73 @@ + + + + + + + + + + css/manual-multipage.css + + '5' + '1' + + + + + + + + + + + + + + + + + + + + firstpage + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-boot-docs/src/main/docbook/xsl/html-singlepage.xsl b/spring-boot-docs/src/main/docbook/xsl/html-singlepage.xsl new file mode 100644 index 00000000000..525fa6590b8 --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/html-singlepage.xsl @@ -0,0 +1,30 @@ + + + + + + + + + + css/manual-singlepage.css + + diff --git a/spring-boot-docs/src/main/docbook/xsl/html.xsl b/spring-boot-docs/src/main/docbook/xsl/html.xsl new file mode 100644 index 00000000000..64a0f577869 --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/html.xsl @@ -0,0 +1,117 @@ + + + + + + + + + + + 1 + + + 1 + + + + 120 + images/callouts/ + .png + + + text/css + + text-align: left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + + + + + +

+

Authors

+ +
+ + diff --git a/spring-boot-docs/src/main/docbook/xsl/pdf.xsl b/spring-boot-docs/src/main/docbook/xsl/pdf.xsl new file mode 100644 index 00000000000..ce04aa349c6 --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/pdf.xsl @@ -0,0 +1,608 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + auto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + + + + + + + + + Copyright © + + + + + + + + + + + + + + + + + + + + + + + + + + + + -5em + -5em + 8pt + + + + + + + + + + + + + + + please define title in your docbook file! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 8pt + + + + + + + + + + + + + + + + + + + + + + + + + please define title in your docbook file! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 0 + + + + false + + + Helvetica + 10 + 8 + Helvetica + + + 1.4 + + + + left + bold + + + pt + + + + + + + + + + + + + + + 0.6em + 0.6em + 0.6em + + + pt + + 0.1em + 0.1em + 0.1em + + + + 0.4em + 0.4em + 0.4em + + + pt + + 0.1em + 0.1em + 0.1em + + + + 0.4em + 0.4em + 0.4em + + + pt + + 0.1em + 0.1em + 0.1em + + + + 0.3em + 0.3em + 0.3em + + + pt + + 0.1em + 0.1em + 0.1em + + + + + + + + 4pt + 4pt + 4pt + 4pt + + + + 0.1pt + 0.1pt + + + + + + + + + + + + + + + + 7pt + wrap + 1 + + + + 1em + 1em + 1em + 0.1em + 0.1em + 0.1em + + #444444 + solid + 0.1pt + 0.5em + 0.5em + 0.5em + 0.5em + 0.5em + 0.5em + + + + 1 + + #F0F0F0 + + + + 0.1em + 0.1em + 0.1em + 0.1em + 0.1em + 0.1em + + + + 0.5em + 0.5em + 0.5em + 0.1em + 0.1em + 0.1em + + + + #444444 + solid + 0.1pt + #F0F0F0 + + + + + + + normal + italic + + + pt + + false + 0.1em + 0.1em + 0.1em + + + + + + 0 + 1 + + + 90 + + + + + + figure after + example after + equation before + table before + procedure before + + + + 1 + 0pt + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0.1em + 2em + .75pt + solid + #5c5c4f + 0.5em + 1.5em + 1.5em + 1.5em + 1.5em + 1.5em + 1.5em + + + + 10pt + bold + false + always + 0 + + + + 0em + 0em + 0em + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-boot-docs/src/main/docbook/xsl/xslthl-config.xml b/spring-boot-docs/src/main/docbook/xsl/xslthl-config.xml new file mode 100644 index 00000000000..011a09e1bb5 --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/xslthl-config.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/spring-boot-docs/src/main/docbook/xsl/xslthl/asciidoc-hl.xml b/spring-boot-docs/src/main/docbook/xsl/xslthl/asciidoc-hl.xml new file mode 100644 index 00000000000..5478b1d6d58 --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/xslthl/asciidoc-hl.xml @@ -0,0 +1,41 @@ + + + + + //// + //// + + + // + + + + ^(={1,6} .+)$ + + MULTILINE + + + ^(\.[^\.\s].+)$ + + MULTILINE + + + ^(:!?\w.*?:) + + MULTILINE + + + ^(-|\*{1,5}|\d*\.{1,5})(?= .+$) + + MULTILINE + + + ^(\[.+\])$ + + MULTILINE + + diff --git a/spring-boot-docs/src/main/docbook/xsl/xslthl/bourne-hl.xml b/spring-boot-docs/src/main/docbook/xsl/xslthl/bourne-hl.xml new file mode 100644 index 00000000000..e2cd98d8b50 --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/xslthl/bourne-hl.xml @@ -0,0 +1,95 @@ + + + + # + + << + ' + " + - + + + + + " + \ + + + ' + \ + + + + 0x + + + + . + + + + + + if + then + else + elif + fi + case + esac + for + while + until + do + done + + exec + shift + exit + times + break + export + trap + continue + readonly + wait + eval + return + + cd + echo + hash + pwd + read + set + test + type + ulimit + umask + unset + + diff --git a/spring-boot-docs/src/main/docbook/xsl/xslthl/c-hl.xml b/spring-boot-docs/src/main/docbook/xsl/xslthl/c-hl.xml new file mode 100644 index 00000000000..176cc379ff9 --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/xslthl/c-hl.xml @@ -0,0 +1,117 @@ + + + + + /** + */ + + + + + + + + /* + */ + + // + + + # + \ + + + + + " + \ + + + ' + \ + + + 0x + ul + lu + u + l + + + + . + + e + ul + lu + u + f + l + + + + auto + _Bool + break + case + char + _Complex + const + continue + default + do + double + else + enum + extern + float + for + goto + if + _Imaginary + inline + int + long + register + restrict + return + short + signed + sizeof + static + struct + switch + typedef + union + unsigned + void + volatile + while + + diff --git a/spring-boot-docs/src/main/docbook/xsl/xslthl/cpp-hl.xml b/spring-boot-docs/src/main/docbook/xsl/xslthl/cpp-hl.xml new file mode 100644 index 00000000000..ef83c4f5eed --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/xslthl/cpp-hl.xml @@ -0,0 +1,151 @@ + + + + + /** + */ + + + + + + + + /* + */ + + // + + + # + \ + + + + + " + \ + + + ' + \ + + + 0x + ul + lu + u + l + + + + . + + e + ul + lu + u + f + l + + + + + auto + _Bool + break + case + char + _Complex + const + continue + default + do + double + else + enum + extern + float + for + goto + if + _Imaginary + inline + int + long + register + restrict + return + short + signed + sizeof + static + struct + switch + typedef + union + unsigned + void + volatile + while + + asm + dynamic_cast + namespace + reinterpret_cast + try + bool + explicit + new + static_cast + typeid + catch + false + operator + template + typename + class + friend + private + this + using + const_cast + inline + public + throw + virtual + delete + mutable + protected + true + wchar_t + + diff --git a/spring-boot-docs/src/main/docbook/xsl/xslthl/csharp-hl.xml b/spring-boot-docs/src/main/docbook/xsl/xslthl/csharp-hl.xml new file mode 100644 index 00000000000..d57e6310296 --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/xslthl/csharp-hl.xml @@ -0,0 +1,194 @@ + + + + + /** + */ + + + + /// + + + + /* + */ + + // + + + [ + ] + ( + ) + + + + # + \ + + + + + + @" + " + \ + + + + " + \ + + + ' + \ + + + 0x + ul + lu + u + l + + + + . + + e + ul + lu + u + f + d + m + l + + + + abstract + as + base + bool + break + byte + case + catch + char + checked + class + const + continue + decimal + default + delegate + do + double + else + enum + event + explicit + extern + false + finally + fixed + float + for + foreach + goto + if + implicit + in + int + interface + internal + is + lock + long + namespace + new + null + object + operator + out + override + params + private + protected + public + readonly + ref + return + sbyte + sealed + short + sizeof + stackalloc + static + string + struct + switch + this + throw + true + try + typeof + uint + ulong + unchecked + unsafe + ushort + using + virtual + void + volatile + while + + + + add + alias + from + get + global + group + into + join + orderby + partial + remove + select + set + value + where + yield + + diff --git a/spring-boot-docs/src/main/docbook/xsl/xslthl/css-hl.xml b/spring-boot-docs/src/main/docbook/xsl/xslthl/css-hl.xml new file mode 100644 index 00000000000..164c48c3d86 --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/xslthl/css-hl.xml @@ -0,0 +1,176 @@ + + + + + /* + */ + + + " + \ + + + + ' + \ + + + + . + + + + @charset + @import + @media + @page + + + + - + azimuth + background-attachment + background-color + background-image + background-position + background-repeat + background + border-collapse + border-color + border-spacing + border-style + border-top + border-right + border-bottom + border-left + border-top-color + border-right-color + border-bottom-color + border-left-color + border-top-style + border-right-style + border-bottom-style + border-left-style + border-top-width + border-right-width + border-bottom-width + border-left-width + border-width + border + bottom + caption-side + clear + clip + color + content + counter-increment + counter-reset + cue-after + cue-before + cue + cursor + direction + display + elevation + empty-cells + float + font-family + font-size + font-style + font-variant + font-weight + font + height + left + letter-spacing + line-height + list-style-image + list-style-position + list-style-type + list-style + margin-right + margin-left + margin-top + margin-bottom + margin + max-height + max-width + min-height + min-width + orphans + outline-color + outline-style + outline-width + outline + overflow + padding-top + padding-right + padding-bottom + padding-left + padding + page-break-after + page-break-before + page-break-inside + pause-after + pause-before + pause + pitch-range + pitch + play-during + position + quotes + richness + right + speak-header + speak-numeral + speak-punctuation + speak + speech-rate + stress + table-layout + text-align + text-decoration + text-indent + text-transform + top + unicode-bidi + vertical-align + visibility + voice-family + volume + white-space + widows + width + word-spacing + z-index + + diff --git a/spring-boot-docs/src/main/docbook/xsl/xslthl/html-hl.xml b/spring-boot-docs/src/main/docbook/xsl/xslthl/html-hl.xml new file mode 100644 index 00000000000..5b6761bab97 --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/xslthl/html-hl.xml @@ -0,0 +1,122 @@ + + + + + + + a + abbr + address + area + article + aside + audio + b + base + bdi + blockquote + body + br + button + caption + canvas + cite + code + command + col + colgroup + dd + del + dialog + div + dl + dt + em + embed + fieldset + figcaption + figure + font + form + footer + h1 + h2 + h3 + h4 + h5 + h6 + head + header + hr + html + i + iframe + img + input + ins + kbd + label + legend + li + link + map + mark + menu + menu + meta + nav + noscript + object + ol + optgroup + option + p + param + pre + q + samp + script + section + select + small + source + span + strong + style + sub + summary + sup + table + tbody + td + textarea + tfoot + th + thead + time + title + tr + track + u + ul + var + video + wbr + xmp + + + + + xsl: + + + diff --git a/spring-boot-docs/src/main/docbook/xsl/xslthl/ini-hl.xml b/spring-boot-docs/src/main/docbook/xsl/xslthl/ini-hl.xml new file mode 100644 index 00000000000..34c103637ed --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/xslthl/ini-hl.xml @@ -0,0 +1,45 @@ + + + + ; + + + ^(\[.+\]\s*)$ + + MULTILINE + + + + ^(.+)(?==) + + MULTILINE + + diff --git a/spring-boot-docs/src/main/docbook/xsl/xslthl/java-hl.xml b/spring-boot-docs/src/main/docbook/xsl/xslthl/java-hl.xml new file mode 100644 index 00000000000..f7bb1641462 --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/xslthl/java-hl.xml @@ -0,0 +1,117 @@ + + + + + /** + */ + + + + /* + */ + + // + + " + \ + + + ' + \ + + + @ + ( + ) + + + 0x + + + + . + e + f + d + l + + + + abstract + boolean + break + byte + case + catch + char + class + const + continue + default + do + double + else + extends + final + finally + float + for + goto + if + implements + import + instanceof + int + interface + long + native + new + package + private + protected + public + return + short + static + strictfp + super + switch + synchronized + this + throw + throws + transient + try + void + volatile + while + + diff --git a/spring-boot-docs/src/main/docbook/xsl/xslthl/javascript-hl.xml b/spring-boot-docs/src/main/docbook/xsl/xslthl/javascript-hl.xml new file mode 100644 index 00000000000..99b8a71e961 --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/xslthl/javascript-hl.xml @@ -0,0 +1,147 @@ + + + + + /* + */ + + // + + " + \ + + + ' + \ + + + 0x + + + + . + e + + + + break + case + catch + continue + default + delete + do + else + finally + for + function + if + in + instanceof + new + return + switch + this + throw + try + typeof + var + void + while + with + + abstract + boolean + byte + char + class + const + debugger + double + enum + export + extends + final + float + goto + implements + import + int + interface + long + native + package + private + protected + public + short + static + super + synchronized + throws + transient + volatile + + + prototype + + Array + Boolean + Date + Error + EvalError + Function + Math + Number + Object + RangeError + ReferenceError + RegExp + String + SyntaxError + TypeError + URIError + + decodeURI + decodeURIComponent + encodeURI + encodeURIComponent + eval + isFinite + isNaN + parseFloat + parseInt + + Infinity + NaN + undefined + + diff --git a/spring-boot-docs/src/main/docbook/xsl/xslthl/perl-hl.xml b/spring-boot-docs/src/main/docbook/xsl/xslthl/perl-hl.xml new file mode 100644 index 00000000000..73d71cc02cd --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/xslthl/perl-hl.xml @@ -0,0 +1,120 @@ + + + + # + + << + ' + " + + + + " + \ + + + ' + \ + + + + 0x + + + + . + + + + + if + unless + while + until + foreach + else + elsif + for + when + default + given + + caller + continue + die + do + dump + eval + exit + goto + last + next + redo + return + sub + wantarray + + caller + import + local + my + package + use + + do + import + no + package + require + use + + bless + dbmclose + dbmopen + package + ref + tie + tied + untie + use + + and + or + not + eq + ne + lt + gt + le + ge + cmp + + diff --git a/spring-boot-docs/src/main/docbook/xsl/xslthl/php-hl.xml b/spring-boot-docs/src/main/docbook/xsl/xslthl/php-hl.xml new file mode 100644 index 00000000000..1da25b8cc6c --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/xslthl/php-hl.xml @@ -0,0 +1,154 @@ + + + + + /** + */ + + + + + + + + /* + */ + + // + # + + " + \ + + + + ' + \ + + + + <<< + + + 0x + + + + . + e + + + + and + or + xor + __FILE__ + exception + __LINE__ + array + as + break + case + class + const + continue + declare + default + die + do + echo + else + elseif + empty + enddeclare + endfor + endforeach + endif + endswitch + endwhile + eval + exit + extends + for + foreach + function + global + if + include + include_once + isset + list + new + print + require + require_once + return + static + switch + unset + use + var + while + __FUNCTION__ + __CLASS__ + __METHOD__ + final + php_user_filter + interface + implements + extends + public + private + protected + abstract + clone + try + catch + throw + cfunction + old_function + true + false + + namespace + __NAMESPACE__ + goto + __DIR__ + + + + + ?> + <?php + <?= + + + diff --git a/spring-boot-docs/src/main/docbook/xsl/xslthl/python-hl.xml b/spring-boot-docs/src/main/docbook/xsl/xslthl/python-hl.xml new file mode 100644 index 00000000000..a4674432391 --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/xslthl/python-hl.xml @@ -0,0 +1,100 @@ + + + + + + @ + ( + ) + + # + + """ + + + + ''' + + + + " + \ + + + ' + \ + + + 0x + l + + + + . + + e + l + + + + and + del + from + not + while + as + elif + global + or + with + assert + else + if + pass + yield + break + except + import + print + class + exec + in + raise + continue + finally + is + return + def + for + lambda + try + + diff --git a/spring-boot-docs/src/main/docbook/xsl/xslthl/ruby-hl.xml b/spring-boot-docs/src/main/docbook/xsl/xslthl/ruby-hl.xml new file mode 100644 index 00000000000..d105640e80a --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/xslthl/ruby-hl.xml @@ -0,0 +1,109 @@ + + + + # + + << + + + + " + \ + + + %Q{ + } + \ + + + %/ + / + \ + + + ' + \ + + + %q{ + } + \ + + + 0x + + + + . + e + + + + alias + and + BEGIN + begin + break + case + class + def + defined + do + else + elsif + END + end + ensure + false + for + if + in + module + next + nil + not + or + redo + rescue + retry + return + self + super + then + true + undef + unless + until + when + while + yield + + diff --git a/spring-boot-docs/src/main/docbook/xsl/xslthl/sql2003-hl.xml b/spring-boot-docs/src/main/docbook/xsl/xslthl/sql2003-hl.xml new file mode 100644 index 00000000000..ac1d5d048bc --- /dev/null +++ b/spring-boot-docs/src/main/docbook/xsl/xslthl/sql2003-hl.xml @@ -0,0 +1,565 @@ + + + + -- + + /* + */ + + + ' + + + + U' + ' + + + + B' + ' + + + + N' + ' + + + + X' + ' + + + + . + + e + + + + + + A + ABS + ABSOLUTE + ACTION + ADA + ADMIN + AFTER + ALWAYS + ASC + ASSERTION + ASSIGNMENT + ATTRIBUTE + ATTRIBUTES + AVG + BEFORE + BERNOULLI + BREADTH + C + CARDINALITY + CASCADE + CATALOG_NAME + CATALOG + CEIL + CEILING + CHAIN + CHAR_LENGTH + CHARACTER_LENGTH + CHARACTER_SET_CATALOG + CHARACTER_SET_NAME + CHARACTER_SET_SCHEMA + CHARACTERISTICS + CHARACTERS + CHECKED + CLASS_ORIGIN + COALESCE + COBOL + CODE_UNITS + COLLATION_CATALOG + COLLATION_NAME + COLLATION_SCHEMA + COLLATION + COLLECT + COLUMN_NAME + COMMAND_FUNCTION_CODE + COMMAND_FUNCTION + COMMITTED + CONDITION_NUMBER + CONDITION + CONNECTION_NAME + CONSTRAINT_CATALOG + CONSTRAINT_NAME + CONSTRAINT_SCHEMA + CONSTRAINTS + CONSTRUCTORS + CONTAINS + CONVERT + CORR + COUNT + COVAR_POP + COVAR_SAMP + CUME_DIST + CURRENT_COLLATION + CURSOR_NAME + DATA + DATETIME_INTERVAL_CODE + DATETIME_INTERVAL_PRECISION + DEFAULTS + DEFERRABLE + DEFERRED + DEFINED + DEFINER + DEGREE + DENSE_RANK + DEPTH + DERIVED + DESC + DESCRIPTOR + DIAGNOSTICS + DISPATCH + DOMAIN + DYNAMIC_FUNCTION_CODE + DYNAMIC_FUNCTION + EQUALS + EVERY + EXCEPTION + EXCLUDE + EXCLUDING + EXP + EXTRACT + FINAL + FIRST + FLOOR + FOLLOWING + FORTRAN + FOUND + FUSION + G + GENERAL + GO + GOTO + GRANTED + HIERARCHY + IMPLEMENTATION + INCLUDING + INCREMENT + INITIALLY + INSTANCE + INSTANTIABLE + INTERSECTION + INVOKER + ISOLATION + K + KEY_MEMBER + KEY_TYPE + KEY + LAST + LENGTH + LEVEL + LN + LOCATOR + LOWER + M + MAP + MATCHED + MAX + MAXVALUE + MESSAGE_LENGTH + MESSAGE_OCTET_LENGTH + MESSAGE_TEXT + MIN + MINVALUE + MOD + MORE + MUMPS + NAME + NAMES + NESTING + NEXT + NORMALIZE + NORMALIZED + NULLABLE + NULLIF + NULLS + NUMBER + OBJECT + OCTET_LENGTH + OCTETS + OPTION + OPTIONS + ORDERING + ORDINALITY + OTHERS + OVERLAY + OVERRIDING + PAD + PARAMETER_MODE + PARAMETER_NAME + PARAMETER_ORDINAL_POSITION + PARAMETER_SPECIFIC_CATALOG + PARAMETER_SPECIFIC_NAME + PARAMETER_SPECIFIC_SCHEMA + PARTIAL + PASCAL + PATH + PERCENT_RANK + PERCENTILE_CONT + PERCENTILE_DISC + PLACING + PLI + POSITION + POWER + PRECEDING + PRESERVE + PRIOR + PRIVILEGES + PUBLIC + RANK + READ + RELATIVE + REPEATABLE + RESTART + RETURNED_CARDINALITY + RETURNED_LENGTH + RETURNED_OCTET_LENGTH + RETURNED_SQLSTATE + ROLE + ROUTINE_CATALOG + ROUTINE_NAME + ROUTINE_SCHEMA + ROUTINE + ROW_COUNT + ROW_NUMBER + SCALE + SCHEMA_NAME + SCHEMA + SCOPE_CATALOG + SCOPE_NAME + SCOPE_SCHEMA + SECTION + SECURITY + SELF + SEQUENCE + SERIALIZABLE + SERVER_NAME + SESSION + SETS + SIMPLE + SIZE + SOURCE + SPACE + SPECIFIC_NAME + SQRT + STATE + STATEMENT + STDDEV_POP + STDDEV_SAMP + STRUCTURE + STYLE + SUBCLASS_ORIGIN + SUBSTRING + SUM + TABLE_NAME + TABLESAMPLE + TEMPORARY + TIES + TOP_LEVEL_COUNT + TRANSACTION_ACTIVE + TRANSACTION + TRANSACTIONS_COMMITTED + TRANSACTIONS_ROLLED_BACK + TRANSFORM + TRANSFORMS + TRANSLATE + TRIGGER_CATALOG + TRIGGER_NAME + TRIGGER_SCHEMA + TRIM + TYPE + UNBOUNDED + UNCOMMITTED + UNDER + UNNAMED + USAGE + USER_DEFINED_TYPE_CATALOG + USER_DEFINED_TYPE_CODE + USER_DEFINED_TYPE_NAME + USER_DEFINED_TYPE_SCHEMA + VIEW + WORK + WRITE + ZONE + + ADD + ALL + ALLOCATE + ALTER + AND + ANY + ARE + ARRAY + AS + ASENSITIVE + ASYMMETRIC + AT + ATOMIC + AUTHORIZATION + BEGIN + BETWEEN + BIGINT + BINARY + BLOB + BOOLEAN + BOTH + BY + CALL + CALLED + CASCADED + CASE + CAST + CHAR + CHARACTER + CHECK + CLOB + CLOSE + COLLATE + COLUMN + COMMIT + CONNECT + CONSTRAINT + CONTINUE + CORRESPONDING + CREATE + CROSS + CUBE + CURRENT_DATE + CURRENT_DEFAULT_TRANSFORM_GROUP + CURRENT_PATH + CURRENT_ROLE + CURRENT_TIME + CURRENT_TIMESTAMP + CURRENT_TRANSFORM_GROUP_FOR_TYPE + CURRENT_USER + CURRENT + CURSOR + CYCLE + DATE + DAY + DEALLOCATE + DEC + DECIMAL + DECLARE + DEFAULT + DELETE + DEREF + DESCRIBE + DETERMINISTIC + DISCONNECT + DISTINCT + DOUBLE + DROP + DYNAMIC + EACH + ELEMENT + ELSE + END + END-EXEC + ESCAPE + EXCEPT + EXEC + EXECUTE + EXISTS + EXTERNAL + FALSE + FETCH + FILTER + FLOAT + FOR + FOREIGN + FREE + FROM + FULL + FUNCTION + GET + GLOBAL + GRANT + GROUP + GROUPING + HAVING + HOLD + HOUR + IDENTITY + IMMEDIATE + IN + INDICATOR + INNER + INOUT + INPUT + INSENSITIVE + INSERT + INT + INTEGER + INTERSECT + INTERVAL + INTO + IS + ISOLATION + JOIN + LANGUAGE + LARGE + LATERAL + LEADING + LEFT + LIKE + LOCAL + LOCALTIME + LOCALTIMESTAMP + MATCH + MEMBER + MERGE + METHOD + MINUTE + MODIFIES + MODULE + MONTH + MULTISET + NATIONAL + NATURAL + NCHAR + NCLOB + NEW + NO + NONE + NOT + NULL + NUMERIC + OF + OLD + ON + ONLY + OPEN + OR + ORDER + OUT + OUTER + OUTPUT + OVER + OVERLAPS + PARAMETER + PARTITION + PRECISION + PREPARE + PRIMARY + PROCEDURE + RANGE + READS + REAL + RECURSIVE + REF + REFERENCES + REFERENCING + REGR_AVGX + REGR_AVGY + REGR_COUNT + REGR_INTERCEPT + REGR_R2 + REGR_SLOPE + REGR_SXX + REGR_SXY + REGR_SYY + RELEASE + RESULT + RETURN + RETURNS + REVOKE + RIGHT + ROLLBACK + ROLLUP + ROW + ROWS + SAVEPOINT + SCROLL + SEARCH + SECOND + SELECT + SENSITIVE + SESSION_USER + SET + SIMILAR + SMALLINT + SOME + SPECIFIC + SPECIFICTYPE + SQL + SQLEXCEPTION + SQLSTATE + SQLWARNING + START + STATIC + SUBMULTISET + SYMMETRIC + SYSTEM_USER + SYSTEM + TABLE + THEN + TIME + TIMESTAMP + TIMEZONE_HOUR + TIMEZONE_MINUTE + TO + TRAILING + TRANSLATION + TREAT + TRIGGER + TRUE + UESCAPE + UNION + UNIQUE + UNKNOWN + UNNEST + UPDATE + UPPER + USER + USING + VALUE + VALUES + VAR_POP + VAR_SAMP + VARCHAR + VARYING + WHEN + WHENEVER + WHERE + WIDTH_BUCKET + WINDOW + WITH + WITHIN + WITHOUT + YEAR + + From 163509b5e5a181a8ba611cde5da6cd42798ec23b Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 13 Mar 2014 13:18:47 -0700 Subject: [PATCH 2/4] Add initial reference manual documentation See gh-295 --- .../appendix-application-properties.adoc | 249 +++ .../appendix-auto-configuration-classes.adoc | 147 ++ .../appendix-executable-jar-format.adoc | 277 +++ .../src/main/asciidoc/appendix.adoc | 7 + .../src/main/asciidoc/build-tool-plugins.adoc | 578 ++++++ .../main/asciidoc/documentation-overview.adoc | 123 ++ .../src/main/asciidoc/getting-started.adoc | 731 ++++++++ spring-boot-docs/src/main/asciidoc/howto.adoc | 17 + spring-boot-docs/src/main/asciidoc/index.adoc | 11 +- .../asciidoc/production-ready-features.adoc | 747 ++++++++ .../src/main/asciidoc/spring-boot-cli.adoc | 323 ++++ .../main/asciidoc/spring-boot-features.adoc | 1611 +++++++++++++++++ .../src/main/asciidoc/using-spring-boot.adoc | 597 ++++++ 13 files changed, 5416 insertions(+), 2 deletions(-) create mode 100644 spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc create mode 100644 spring-boot-docs/src/main/asciidoc/appendix-auto-configuration-classes.adoc create mode 100644 spring-boot-docs/src/main/asciidoc/appendix-executable-jar-format.adoc create mode 100644 spring-boot-docs/src/main/asciidoc/appendix.adoc create mode 100644 spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc create mode 100644 spring-boot-docs/src/main/asciidoc/documentation-overview.adoc create mode 100644 spring-boot-docs/src/main/asciidoc/getting-started.adoc create mode 100644 spring-boot-docs/src/main/asciidoc/howto.adoc create mode 100644 spring-boot-docs/src/main/asciidoc/production-ready-features.adoc create mode 100644 spring-boot-docs/src/main/asciidoc/spring-boot-cli.adoc create mode 100644 spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc create mode 100644 spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc new file mode 100644 index 00000000000..581411be4db --- /dev/null +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -0,0 +1,249 @@ +:numbered!: +[appendix] +[[common-application-properties]] +== Common application properties +Various properties can be specified inside your `application.properties`/`application.yml` +file or as command line switches. This section provides a list common Spring Boot +properties and references to the underlying classes that consume them. + +NOTE: Property contributions can come from additional jar files on your classpath so +you should not consider this an exhaustive list. It is also perfectly legal to define +your own properties. + +WARNING: This sample file is meant as a guide only. Do **not** copy/paste the entire +content into your application; rather pick only the properties that you need. + +[source,properties,indent=0,subs="verbatim,attributes"] +---- +# =================================================================== +# COMMON SPRING BOOT PROPERTIES +# +# This sample file is provided as a guideline. Do NOT copy it in its +# entirety to your own application. ^^^ +# =================================================================== + +# ---------------------------------------- +# CORE PROPERTIES +# ---------------------------------------- + +# SPRING CONFIG (ConfigFileApplicationListner) +spring.config.name= # config file name (default to 'application') +spring.config.location= # location of config file + +# PROFILES +spring.profiles= # comma list of active profiles + +# APPLICATION SETTINGS (SpringApplication_ +spring.main.sources= +spring.main.web-environment= # detect by default +spring.main.show-bannder=true +spring.main.... # see class for all properties + +# LOGGING +logging.path=/var/logs +logging.file=myapp.log +logging.config= + +# IDENTITY (ContextIdApplicationContextInitializer) +spring.application.name= +vcap.application.name= + +# EMBEDDED SERVER CONFIGURATION (ServerProperties) +server.port=8080 +server.address= # bind to a specific NIC +server.session-timeout= # session timeout in sections +server.context-path= # the context path, defaults to '/' +server.servlet-path= # the servlet path, defaults to '/' +server.tomcat.access-log-pattern= # log pattern of the access log +server.tomcat.access-log-enabled=false # is access logging enabled +server.tomcat.protocol-header="x-forwarded-proto" # ssl forward headers +server.tomcat.remote-ip-header="x-forwarded-for" +server.tomcat.basedir="/tmp" # base dir (usually not needed, defaults to tmp) +server.tomcat.background-processor-delay=30; # in seconds +server.tomcat.max-threads = 0 # number of threads in protocol handler + +# SPRING MVC (HttpMapperProperties) +http.mappers.json-pretty-print=false # pretty print JSON +spring.view.prefix= # MVC view prefix +spring.view.suffix= # ... and suffix +spring.resources.cache-period # cache timeouts in headers sent to browser + +# THYMELEAF (ThymeleafAutoConfiguration) +spring.thymeleaf.prefix="classpath:/templates/" +spring.thymeleaf.suffix=".html" +spring.thymeleaf.mode="HTML5" +spring.thymeleaf.encoding="UTF-8" +spring.thymeleaf.cache=true # set to false for hot refresh + +# INTERNATIONALIZATION (MessageSourceAutoConfiguration) +spring.messages.basename="messages" +spring.messages.encoding="UTF-8" + +# SECURITY (SecurityProperties) +security.user.name="user" # login username +security.user.password= # login password +security.user.role="USER" # role assigned to the user +security.require-ssl=false # advanced settings ... +security.enable-csrf=false +security.basic.enabled=true +security.basic.realm="Spring" +security.basic.path="/**" +security.headers.xss=false +security.headers.cache=false +security.headers.frame=false +security.headers.contentType=false +security.headers.hsts=all # none / domain / all +security.sessions=stateless # always / never / if_required / stateless +security.ignored=false + +# DATASOURCE (DataSourceAutoConfiguration & AbstractDataSourceConfiguration) +spring.datasource.name= # name of the data source +spring.datasource.intialize=true # populate using data.sql +spring.datasource.schema= # a schema resource reference +spring.datasource.continueOnError=false # continue even if can't be initialized +spring.datasource.driverClassName= # JDBC Settings... +spring.datasource.url= +spring.datasource.username= +spring.datasource.password= +spring.datasource.max-active=100 # Advanced configuration... +spring.datasource.max-idle=8 +spring.datasource.min-idle=8 +spring.datasource.initial-size=10 +spring.datasource.validation-query +spring.datasource.test-on-borrow=false +spring.datasource.test-on-return=false + +# MONGODB (MongoProperties) +spring.data.mongodb.host= # the db host +spring.data.mongodb.port=27017 # the connection port (defaults to 27107) +spring.data.mongodb.uri=mongodb://localhost/test # connection URL + +# JPA (JpaBaseConfiguration, HibernateJpaAutoConfiguration) +spring.jpa.properties.*= # properties to set on the JPA connection +spring.jpa.openInView=true +spring.jpa.show-sql=true +spring.jpa.database-platform= +spring.jpa.database= +spring.jpa.generate-ddl= +spring.jpa.hibernate.naming-strategy= # naming classname +spring.jpa.hibernate.ddl-auto= # defaults to create-drop for embedded dbs + +# JMX +spring.jmx.enabled=true # Expose MBeans from Spring + +# RABBIT (RabbitProperties) +spring.rabbitmq.host= # connection host +spring.rabbitmq.port= # connection port +spring.rabbitmq.username= # login user +spring.rabbitmq.password= # login password +spring.rabbitmq.virtualhost= +spring.rabbitmq.dynamic= + +# REDIS (RedisProperties) +spring.redis.host="localhost" # server host +spring.redis.password= # server password +spring.redis.port=6379 # connection port +spring.redis.pool.max-idle=8 # pool settings ... +spring.redis.pool.min-idle=0 +spring.redis.pool.max-active=8 +spring.redis.pool.max-wait=-1 + +# ACTIVEMQ (ActiveMQProperties) +spring.activemq.broker-url="tcp://localhost:61616" # connection URL +spring.activemq.in-memory=true +spring.activemq.pooled=false + +# JMS (JmsTemplateProperties) +spring.jms.pub-sub-domain= + +# SPRING BATCH (BatchDatabaseInitializer) +spring.batch.job.names="job1,job2" +spring.batch.job.enabled=true +spring.batch.initializer.enabled=true +spring.batch.schema= # batch schema to load + +# AOP +spring.aop.auto= +spring.aop.proxyTargetClass= + +# FILE ENCODING (FileEncodingApplicationListener) +spring.mandatory-file-encoding=false + +# ---------------------------------------- +# ACTUATOR PROPERTIES +# ---------------------------------------- + +# MANAGEMENT HTTP SERVER (ManagementServerProperties) +management.port= # defaults to 'server.port' +management.address= # bind to a specific NIC +management.contextPath= # default to '/' + +# ENDPOINTS (AbstractEndpoint subclasses) +endpoints.autoconfig.id="autoconfig" +endpoints.autoconfig.sensitive=true +endpoints.autoconfig.enabled=true +endpoints.beans.id="beans" +endpoints.beans.sensitive=true +endpoints.beans.enabled=true +endpoints.configprops.id="configprops" +endpoints.configprops.sensitive=true +endpoints.configprops.enabled=true +endpoints.configprops.keys-to-sanitize="password,secret" +endpoints.dump.id="dump" +endpoints.dump.sensitive=true +endpoints.dump.enabled=true +endpoints.env.id="env" +endpoints.env.sensitive=true +endpoints.env.enabled=true +endpoints.health.id="health" +endpoints.health.sensitive=false +endpoints.health.enabled=true +endpoints.info.id="info" +endpoints.info.sensitive=false +endpoints.info.enabled=true +endpoints.metrics.id="metrics" +endpoints.metrics.sensitive=true +endpoints.metrics.enabled=true +endpoints.shutdown.id="shutdown" +endpoints.shutdown.sensitive=true +endpoints.shutdown.enabled=false +endpoints.trace.id="trace" +endpoints.trace.sensitive=true +endpoints.trace.enabled=true + +# MVC ONLY ENDPOINTS +endpoints.jolokia.path="jolokia" +endpoints.jolokia.sensitive=true +endpoints.jolokia.enabled=true # when using Jolokia +endpoints.error.path="/error" + +# JMX ENDPOINT (EndpointMBeanExportProperties) +endpoints.jmx.enabled=true +endpoints.jmx.domain= # the JMX domain, defaults to 'org.springboot' +endpoints.jmx.unique-names=false +endpoints.jmx.enabled=true +endpoints.jmx.staticNames= + +# JOLOKIA (JolokiaProperties) +jolokia.config.*= # See Jolokia manual + +# REMOTE SHELL +shell.auth=simple # jaas, key, simple, spring +shell.command-refresh-interval=-1 +shell.command-path-pattern="classpath*:/commands/**, classpath*:/crash/commands/**" +shell.config-path-patterns="classpath*:/crash/*" +shell.disabled-plugins=false # don't expose plugins +shell.ssh.enabled= # ssh settings ... +shell.ssh.keyPath= +shell.ssh.port= +shell.telnet.enabled= # telnet settings ... +shell.telnet.port= +shell.auth.jaas.domain= # authentication settings ... +shell.auth.key.path= +shell.auth.simple.user.name= +shell.auth.simple.user.password= +shell.auth.spring.roles= + +# GIT INFO +spring.git.properties= # resource ref to generated git info properties file +---- diff --git a/spring-boot-docs/src/main/asciidoc/appendix-auto-configuration-classes.adoc b/spring-boot-docs/src/main/asciidoc/appendix-auto-configuration-classes.adoc new file mode 100644 index 00000000000..d1f612605f1 --- /dev/null +++ b/spring-boot-docs/src/main/asciidoc/appendix-auto-configuration-classes.adoc @@ -0,0 +1,147 @@ +[appendix] +[[auto-configuration-classes]] +== Auto-configuration classes +Here is a list of all auto configuration classes provided by Spring Boot with links to +documentation and source code. Remember to also look at the autoconfig report in your +application for more details of which features are switched on. +(start the app with `--debug` or `-Ddebug`, or in an Actuator application use the +`autoconfig` endpoint). + + + +[[auto-configuration-classes-from-autoconfigure-module]] +=== From the ``spring-boot-autoconfigure'' module +The following auto-configuration classes are from the `spring-boot-autoconfigure` module: + +[cols="4,1"] +|=== +|Configuration Class | Links + +|{sc-spring-boot-autoconfigure}/MessageSourceAutoConfiguration.{sc-ext}[MessageSourceAutoConfiguration] +|{dc-spring-boot-autoconfigure}/MessageSourceAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/PropertyPlaceholderAutoConfiguration.{sc-ext}[PropertyPlaceholderAutoConfiguration] +|{dc-spring-boot-autoconfigure}/PropertyPlaceholderAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/amqp/RabbitAutoConfiguration.{sc-ext}[RabbitAutoConfiguration] +|{dc-spring-boot-autoconfigure}/amqp/RabbitAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/aop/AopAutoConfiguration.{sc-ext}[AopAutoConfiguration] +|{dc-spring-boot-autoconfigure}/aop/AopAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/batch/BatchAutoConfiguration.{sc-ext}[BatchAutoConfiguration] +|{dc-spring-boot-autoconfigure}/batch/BatchAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/data/JpaRepositoriesAutoConfiguration.{sc-ext}[JpaRepositoriesAutoConfiguration] +|{dc-spring-boot-autoconfigure}/data/JpaRepositoriesAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/data/MongoRepositoriesAutoConfiguration.{sc-ext}[MongoRepositoriesAutoConfiguration] +|{dc-spring-boot-autoconfigure}/data/MongoRepositoriesAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/data/MongoTemplateAutoConfiguration.{sc-ext}[MongoTemplateAutoConfiguration] +|{dc-spring-boot-autoconfigure}/data/MongoTemplateAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/jdbc/DataSourceAutoConfiguration.{sc-ext}[DataSourceAutoConfiguration] +|{dc-spring-boot-autoconfigure}/jdbc/DataSourceAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/jdbc/DataSourceTransactionManagerAutoConfiguration.{sc-ext}[DataSourceTransactionManagerAutoConfiguration] +|{dc-spring-boot-autoconfigure}/jdbc/DataSourceTransactionManagerAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/jms/JmsTemplateAutoConfiguration.{sc-ext}[JmsTemplateAutoConfiguration] +|{dc-spring-boot-autoconfigure}/jms/JmsTemplateAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/jmx/JmxAutoConfiguration.{sc-ext}[JmxAutoConfiguration] +|{dc-spring-boot-autoconfigure}/jmx/JmxAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/mobile/DeviceResolverAutoConfiguration.{sc-ext}[DeviceResolverAutoConfiguration] +|{dc-spring-boot-autoconfigure}/mobile/DeviceResolverAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/mongo/MongoAutoConfiguration.{sc-ext}[MongoAutoConfiguration] +|{dc-spring-boot-autoconfigure}/mongo/MongoAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/orm/jpa/HibernateJpaAutoConfiguration.{sc-ext}[HibernateJpaAutoConfiguration] +|{dc-spring-boot-autoconfigure}/orm/jpa/HibernateJpaAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/reactor/ReactorAutoConfiguration.{sc-ext}[ReactorAutoConfiguration] +|{dc-spring-boot-autoconfigure}/reactor/ReactorAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/redis/RedisAutoConfiguration.{sc-ext}[RedisAutoConfiguration] +|{dc-spring-boot-autoconfigure}/redis/RedisAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/security/SecurityAutoConfiguration.{sc-ext}[SecurityAutoConfiguration] +|{dc-spring-boot-autoconfigure}/security/SecurityAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/thymeleaf/ThymeleafAutoConfiguration.{sc-ext}[ThymeleafAutoConfiguration] +|{dc-spring-boot-autoconfigure}/thymeleaf/ThymeleafAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/web/DispatcherServletAutoConfiguration.{sc-ext}[DispatcherServletAutoConfiguration] +|{dc-spring-boot-autoconfigure}/web/DispatcherServletAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/web/EmbeddedServletContainerAutoConfiguration.{sc-ext}[EmbeddedServletContainerAutoConfiguration] +|{dc-spring-boot-autoconfigure}/web/EmbeddedServletContainerAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/web/HttpMessageConvertersAutoConfiguration.{sc-ext}[HttpMessageConvertersAutoConfiguration] +|{dc-spring-boot-autoconfigure}/web/HttpMessageConvertersAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/web/MultipartAutoConfiguration.{sc-ext}[MultipartAutoConfiguration] +|{dc-spring-boot-autoconfigure}/web/MultipartAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/web/ServerPropertiesAutoConfiguration.{sc-ext}[ServerPropertiesAutoConfiguration] +|{dc-spring-boot-autoconfigure}/web/ServerPropertiesAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/web/WebMvcAutoConfiguration.{sc-ext}[WebMvcAutoConfiguration] +|{dc-spring-boot-autoconfigure}/web/WebMvcAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-autoconfigure}/websocket/WebSocketAutoConfiguration.{sc-ext}[WebSocketAutoConfiguration] +|{dc-spring-boot-autoconfigure}/websocket/WebSocketAutoConfiguration.{dc-ext}[javadoc] +|=== + + + +[[auto-configuration-classes-from-actuator]] +=== From the ``spring-boot-actuator'' module +The following auto-configuration classes are from the `spring-boot-actuator` module: + +[cols="4,1"] +|=== +|Configuration Class |Links + +|{sc-spring-boot-actuator}/autoconfigure/AuditAutoConfiguration.{sc-ext}[AuditAutoConfiguration] +|{dc-spring-boot-actuator}/autoconfigure/AuditAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-actuator}/autoconfigure/CrshAutoConfiguration.{sc-ext}[CrshAutoConfiguration] +|{dc-spring-boot-actuator}/autoconfigure/CrshAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-actuator}/autoconfigure/EndpointAutoConfiguration.{sc-ext}[EndpointAutoConfiguration] +|{dc-spring-boot-actuator}/autoconfigure/EndpointAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-actuator}/autoconfigure/EndpointMBeanExportAutoConfiguration.{sc-ext}[EndpointMBeanExportAutoConfiguration] +|{dc-spring-boot-actuator}/autoconfigure/EndpointMBeanExportAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-actuator}/autoconfigure/EndpointWebMvcAutoConfiguration.{sc-ext}[EndpointWebMvcAutoConfiguration] +|{dc-spring-boot-actuator}/autoconfigure/EndpointWebMvcAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-actuator}/autoconfigure/ErrorMvcAutoConfiguration.{sc-ext}[ErrorMvcAutoConfiguration] +|{dc-spring-boot-actuator}/autoconfigure/ErrorMvcAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-actuator}/autoconfigure/JolokiaAutoConfiguration.{sc-ext}[JolokiaAutoConfiguration] +|{dc-spring-boot-actuator}/autoconfigure/JolokiaAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-actuator}/autoconfigure/ManagementSecurityAutoConfiguration.{sc-ext}[ManagementSecurityAutoConfiguration] +|{dc-spring-boot-actuator}/autoconfigure/ManagementSecurityAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-actuator}/autoconfigure/ManagementServerPropertiesAutoConfiguration.{sc-ext}[ManagementServerPropertiesAutoConfiguration] +|{dc-spring-boot-actuator}/autoconfigure/ManagementServerPropertiesAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-actuator}/autoconfigure/MetricFilterAutoConfiguration.{sc-ext}[MetricFilterAutoConfiguration] +|{dc-spring-boot-actuator}/autoconfigure/MetricFilterAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-actuator}/autoconfigure/MetricRepositoryAutoConfiguration.{sc-ext}[MetricRepositoryAutoConfiguration] +|{dc-spring-boot-actuator}/autoconfigure/MetricRepositoryAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-actuator}/autoconfigure/TraceRepositoryAutoConfiguration.{sc-ext}[TraceRepositoryAutoConfiguration] +|{dc-spring-boot-actuator}/autoconfigure/TraceRepositoryAutoConfiguration.{dc-ext}[javadoc] + +|{sc-spring-boot-actuator}/autoconfigure/TraceWebFilterAutoConfiguration.{sc-ext}[TraceWebFilterAutoConfiguration] +|{dc-spring-boot-actuator}/autoconfigure/TraceWebFilterAutoConfiguration.{dc-ext}[javadoc] +|=== diff --git a/spring-boot-docs/src/main/asciidoc/appendix-executable-jar-format.adoc b/spring-boot-docs/src/main/asciidoc/appendix-executable-jar-format.adoc new file mode 100644 index 00000000000..3b6ec5cb0b9 --- /dev/null +++ b/spring-boot-docs/src/main/asciidoc/appendix-executable-jar-format.adoc @@ -0,0 +1,277 @@ +[appendix] +[[executable-jar]] +== The executable jar format +The `spring-boot-loader` modules allows Spring Boot to support executable jar and +war files. If you're using the Maven or Gradle plugin, executable jars are +automatically generated and you generally won't need to know the details of how +they work. + +If you need to create executable jars from a different build system, or if you are just +curious about the underlying technology, this section provides some background. + + + +[[executable-jar-nested-jars]] +=== Nested JARs +Java does not provide any standard way to load nested jar files (i.e. jar files that +are themselves contained within a jar). This can be problematic if you are looking +to distribute a self contained application that you can just run from the command line +without unpacking. + +To solve this problem, many developers use ``shaded'' jars. A shaded jar simply packages +all classes, from all jars, into a single 'uber jar'. The problem with shaded jars is +that it becomes hard to see which libraries you are actually using in your application. +It can also be problematic if the the same filename is used (but with different content) +in multiple jars. Spring Boot takes a different approach and allows you to actually nest +jars directly. + + + +[[executable-jar-jar-file-structure]] +==== The executable jar file structure +Spring Boot Loader compatible jar files should be structured in the following way: + +[indent=0] +---- + example.jar + | + +-META-INF + | +-MANIFEST.MF + +-org + | +-springframework + | +-boot + | +-loader + | +- + +-com + | +-mycompany + | + project + | +-YouClasses.class + +-lib + +-dependency1.jar + +-dependency2.jar +---- + +Dependencies should be placed in a nested `lib` directory. + + + +[[executable-jar-war-file-structure]] +==== The executable war file structure +Spring Boot Loader compatible war files should be structured in the following way: + +[indent=0] +---- + example.jar + | + +-META-INF + | +-MANIFEST.MF + +-org + | +-springframework + | +-boot + | +-loader + | +- + +-WEB-INF + +-classes + | +-com + | +-mycompany + | +-project + | +-YouClasses.class + +-lib + | +-dependency1.jar + | +-dependency2.jar + +-lib-provided + +-servlet-api.jar + +-dependency3.jar +---- + +Dependencies should be placed in a nested `WEB-INF/lib` directory. Any dependencies +that are required when running embedded but are not required when deploying to +a traditional web container should be placed in `WEB-INF/lib-provided`. + + + +[[executable-jar-jarfile]] +=== Spring Boot's ``JarFile'' class +The core class used to support loading nested jars is +`org.springframework.boot.loader.jar.JarFile`. It allows you load jar +content from a standard jar file, or from nested child jar data. When first loaded, the +location of each `JarEntry` is mapped to a physical file offset of the outer jar: + +[indent=0] +---- + myapp.jar + +---------+---------------------+ + | | /lib/mylib.jar | + | A.class |+---------+---------+| + | || B.class | B.class || + | |+---------+---------+| + +---------+---------------------+ + ^ ^ ^ + 0063 3452 3980 +---- + +The example above shows how `A.class` can be found in `myapp.jar` position `0063`. +`B.class` from the nested jar can actually be found in `myapp.jar` position `3452` +and `B.class` is at position `3980`. + +Armed with this information, we can load specific nested entries by simply seeking to +appropriate part if the outer jar. We don't need to unpack the archive and we don't +need to read all entry data into memory. + + + +[[executable-jar-jarfile-compatibility]] +==== Compatibility with the standard Java ``JarFile'' +Spring Boot Loader strives to remain compatible with existing code and libraries. +`org.springframework.boot.loader.jar.JarFile` extends from `java.util.jar.JarFile` and +should work as a drop-in replacement. The `RandomAccessJarFile.getURL()` method will +return a `URL` that opens a `java.net.JarURLConnection` compatible connection. +`RandomAccessJarFile` URLs can be used with Java's `URLClassLoader`. + + + +[[executable-jar-launching]] +=== Launching executable jars +The `org.springframework.boot.loader.Launcher` class is a special bootstrap class that +is used as an executable jars main entry point. It is the actual `Main-Class` in your jar +file and it's used to setup an appropriate `URLClassLoader` and ultimately call your +`main()` method. + +There are 3 launcher subclasses (`JarLauncher`, `WarLauncher` and `PropertiesLauncher`). +Their purpose is to load resources (`.class` files etc.) from nested jar files or war +files in directories (as opposed to explicitly on the classpath). In the case of the +`[Jar|War]Launcher` the nested paths are fixed `(lib/*.jar` and `lib-provided/*.jar` for +the war case) so you just add extra jars in those locations if you want more. The +`PropertiesLauncher` looks in `lib/` by default, but you can add additional locations by +setting an environment variable `LOADER_PATH` or `loader.path` in `application.properties` +(colon-separated list of directories or archives). + + + +[[executable-jar-launcher-manifest]] +==== Launcher manifest +You need specify an appropriate `Launcher` as the `Main-Class` attribute of +`META-INF/MANIFEST.MF`. The actual class that you want to launch (i.e. the class that +you wrote that contains a `main` method) should be specified in the `Start-Class` +attribute. + +For example, here is a typical `MANIFEST.MF` for a executable jar file: + +[indent=0] +---- + Main-Class: org.springframework.boot.loader.JarLauncher + Start-Class: com.mycompany.project.MyApplication +---- + +For a war file, it would be: + +[indent=0] +---- + Main-Class: org.springframework.boot.loader.WarLauncher + Start-Class: com.mycompany.project.MyApplication +---- + +NOTE: You do not need to specify `Class-Path` entries in your manifest file, the classpath +will be deduced from the nested jars. + + + +[[executable-jar-exploded-archives]] +==== Exploded archives +Certain PaaS implementations may choose to unpack archives before they run. For example, +Cloud Foundry operates in this way. You can run an unpacked archive by simply starting +the appropriate launcher: + +[indent=0] +---- + $ unzip -q myapp.jar + $ java org.springframework.boot.loader.JarLauncher +---- + + + +[[executable-jar-property-launcher-features]] +=== PropertiesLauncher Features + +`PropertiesLauncher` has a few special features that can be enabled with external +properties (System properties, environment variables, manifest entries or +`application.properties`). + +[cols="2,4"] +|=== +|Key |Purpose + +|`loader.path` +|Colon-separated Classpath, e.g. `lib:${HOME}/app/lib`. + +|`loader.home` +|Location of additional properties file, e.g. `file:///opt/app` + (defaults to `${user.dir}`) + +|`loader.args` +|Default arguments for the main method (space separated) + +|`loader.main` +|Name of main class to launch, e.g. `com.app.Application`. + +|`loader.config.name` +|Name of properties file, e.g. `loader` (defaults to `application`). + +|`loader.config.location` +|Path to properties file, e.g. `classpath:loader.properties` (defaults to + `application/.properties`). + +|`loader.system` +|Boolean flag to indicate that all properties should be added to System properties + (defaults to `false`) +|=== + +Manifest entry keys are formed by capitalizing initial letters of words and changing the +separator to "`-`" from "`.`" (e.g. `Loader-Path`). The exception is `loader.main` which +is looked up as `Start-Class` in the manifest for compatibility with `JarLauncher`). + +Environment variables can be capitalized with underscore separators instead of periods. + +* `loader.home` is the directory location of an additional properties file (overriding + the default) as long as `loader.config.location` is not specified. +* `loader.path` can contain directories (scanned recursively for jar and zip files), + archive paths, or wildcard patterns (for the default JVM behavior). +* Placeholder replacement is done from System and environment variables plus the + properties file itself on all values before use. + + + +[[executable-jar-restrictions]] +=== Executable jar restrictions +There are a number of restrictions that you need to consider when working with a Spring +Boot Loader packaged application. + + + +[[executable-jar-zip-entry-compression]] +==== Zip entry compression +The `ZipEntry` for a nested jar must be saved using the `ZipEntry.STORED` method. This +is required so that we can seek directly to individual content within the nested jar. +The content of the nested jar file itself can still be compressed, as can any other +entries in the outer jar. + + + +[[executable-jar-system-classloader]] +==== System ClassLoader +Launched applications should use `Thread.getContextClassLoader()` when loading classes +(most libraries and frameworks will do this by default). Trying to load nested jar +classes via `ClassLoader.getSystemClassLoader()` will fail. Please be aware that +`java.util.Logging` always uses the system classloader, for this reason you should +consider a different logging implementation. + + + +[[executable-jar-alternatives]] +=== Alternative single jar solutions +If the above restrictions mean that you cannot use Spring Boot Loader the following +alternatives could be considered: + +* http://maven.apache.org/plugins/maven-shade-plugin/[Maven Shade Plugin] +* http://www.jdotsoft.com/JarClassLoader.php[JarClassLoader] +* http://one-jar.sourceforge.net[OneJar] diff --git a/spring-boot-docs/src/main/asciidoc/appendix.adoc b/spring-boot-docs/src/main/asciidoc/appendix.adoc new file mode 100644 index 00000000000..6acfbf84d7b --- /dev/null +++ b/spring-boot-docs/src/main/asciidoc/appendix.adoc @@ -0,0 +1,7 @@ +[[appendix]] += Appendices + +include::appendix-application-properties.adoc[] +include::appendix-auto-configuration-classes.adoc[] +include::appendix-executable-jar-format.adoc[] + diff --git a/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc b/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc new file mode 100644 index 00000000000..a5f84aa4dc6 --- /dev/null +++ b/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc @@ -0,0 +1,578 @@ +[[build-tool-plugins]] += Build tool plugins + +[partintro] +-- +Spring Boot provides build tool plugins for Maven and Gradle. The plugins offer a +variety of features, including the packaging of executable jars. The section provides +more details on both plugins, as well as some help should you need to extend an +unsupported build system. If you are just getting started, you might want to read +``<>'' from the +<> section first. +-- + + + +[[build-tool-plugins-maven-plugin]] +== Spring Boot Maven plugin +The Spring Boot Maven Plugin provides Spring Boot support in Maven, allowing you to +package executable jar or war archives and run an application ``in-place''. To use it you +must be using Maven 3 (or better). + + + +[[build-tool-plugins-include-maven-plugin]] +=== Including the plugin +To use the Spring Boot Maven Plugin simply include the appropriate XML in the `plugins` +section of your `pom.xml` + +[source,xml,indent=0,subs="verbatim,attributes"] +---- + + + 4.0.0 + + + + + org.springframework.boot + spring-boot-maven-plugin + {spring-boot-version} + + + + repackage + + + + + + + +---- + +This configuration will repackage a jar or war that is built during the `package` phase of +the Maven lifecycle. The following example shows both the repackaged jar, as well as the +original jar, in the `target` directory: + +[indent=0] +---- + $ mvn package + $ ls target/*.jar + target/myproject-1.0.0.jar target/myproject-1.0.0.jar.original +---- + + +If you don't include the `` configuration as above, you can run the plugin on +its own (but only if the package goal is used as well). For example: + +[indent=0] +---- + $ mvn package spring-boot:repackage + $ ls target/*.jar + target/myproject-1.0.0.jar target/myproject-1.0.0.jar.original +---- + +If you are using a milestone or snapshot release you will also need to add appropriate +`pluginRepository` elements: + +[source,xml,indent=0,subs="verbatim,attributes"] +---- + + + spring-snapshots + http://repo.spring.io/snapshot + + + spring-milestones + http://repo.spring.io/milestone + + +---- + + + +[[build-tool-plugins-maven-packaging]] +=== Packaging executable jar and war files +Once `spring-boot-maven-plugin` has been included in your `pom.xml` it will automatically +attempt to rewrite archives to make them executable using the `spring-boot:repackage` +goal. You should configure your project to build a jar or war (as appropriate) using the +usual `packaging` element: + +[source,xml,indent=0,subs="verbatim,attributes"] +---- + + + + jar + + +---- + +Your existing archive will be enhanced by Spring Boot during the `package` phase. The +main class that you want to launch can either be specified using a configuration option, +or by adding a `Main-Class` attribute to the manifest in the usual way. If you don't +specify a main class the plugin will search for a class with a +`public static void main(String[] args)` method. + +To build and run a project artifact, you can type the following: + +[indent=0] +---- + $ mvn package + $ java -jar target/mymodule-0.0.1-SNAPSHOT.jar +---- + + + +[[build-tool-plugins-maven-packaging-configuration]] +=== Repackage configuration +The following configuration options are available for the `spring-boot:repackage` goal: + + + +[[build-tool-plugins-maven-packaging-required-params]] +==== Required parameters +[cols="2,4"] +|=== +|Name |Description + +|`outputDirectory` +|Directory containing the generated archive (defaults to `${project.build.directory}`). + +|`finalName` +|Name of the generated archive (defaults to `${project.build.finalName}`). +|=== + +|== + +[[build-tool-plugins-maven-packaging-optional-params]] +==== Optional parameters +[cols="2,4"] +|=== +|Name |Description + +|`classifier` +|Classifier to add to the artifact generated. If given, the artifact will be attached. If + this is not given, it will merely be written to the output directory according to the + `finalName`. + +|`mainClass` +|The name of the main class. If not specified will search for a single compiled class + that contains a `main` method. + +|`layout` +|The type of archive (which corresponds to how the dependencies are laid out inside it). + Defaults to a guess based on the archive type. +|=== + +The plugin rewrites your manifest, and in particular it manages the `Main-Class` and +`Start-Class` entries, so if the defaults don't work you have to configure those there +(not in the jar plugin). The `Main-Class` in the manifest is actually controlled by the +`layout` property of the boot plugin, e.g. + +[source,xml,indent=0,subs="verbatim,attributes"] +---- + + org.springframework.boot + spring-boot-maven-plugin + {spring-boot-version} + + ${start-class} + ZIP + + + + + repackage + + + + +---- + +The layout property defaults to a guess based on the archive type (jar or war). For the +`PropertiesLauncher` the layout is ``ZIP'' (even though the output might be a jar file). + +TIP: The executable jar format is <>. + +[[build-tool-plugins-maven-running-applications]] +=== Running applications +The Spring Boot Maven Plugin includes a `run` goal which can be used to launch your +application from the command line. Type the following from the root of your Maven +project: + +[indent=0] +---- + $ mvn spring-boot:run +---- + +By default, any `src/main/resources` folder will be added to the application classpath +when you run via the maven plugin. This allows hot refreshing of resources which can be +very useful when developing web applications. For example, you can work on HTML, CSS or +JavaScipt files and see your changes immediately without recompiling your application. It +is also a helpful way of allowing your front end developers to work without needing to +download and install a Java IDE. + + + +[[build-tool-plugins-maven-run-configuration]] +=== Run configuration +The following configuration options are available for the `spring-boot:run` goal: + + + +[[build-tool-plugins-maven-run-configuration-required-params]] +=== Required parameters +[cols="2,4"] +|=== +|Name |Description + +|`classesDirectrory` +|Directory containing the classes and resource files that should be packaged into the + archive (defaults to `${project.build.outputDirectory}`). +|=== + + + +[[build-tool-plugins-maven-run-configuration-optional-params]] +=== Optional parameters +[cols="2,4"] +|=== +|Name |Description + +|`arguments` or `-Drun.arguments` +|Arguments that should be passed to the application. + +|`addResources` or `-Drun.addResources` +|Add Maven resources to the classpath directly, this allows live in-place editing or + resources. Since resources will be added directly, and via the target/classes folder + they will appear twice if `ClassLoader.getResources()` is called. In practice, however, + most applications call `ClassLoader.getResource()` which will always return the first + resource (defaults to `true`). + +|`mainClass` +|The name of the main class. If not specified the first compiled class found that + contains a 'main' method will be used. + +|`folders` +|Folders that should be added to the classpath (defaults to + `${project.build.outputDirectory}`). +|=== + + + +[[build-tool-plugins-gradle-plugin]] +== Spring Boot Gradle plugin +The Spring Boot Gradle Plugin provides Spring Boot support in Gradle, allowing you to +package executable jar or war archives, run Spring Boot applications and omit version +information from your `build.gradle` file for ``blessed'' dependencies. + + + +[[build-tool-plugins-including-the-gradle-plugin]] +=== Including the plugin +To use the Spring Boot Gradle Plugin simply include a `buildscript` dependency and apply +the `spring-boot` plugin: + +[source,groovy,indent=0,subs="verbatim,attributes"] +---- + buildscript { + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:{spring-boot-version}") + } + } + apply plugin: 'spring-boot' +---- + +If you are using a milestone or snapshot release you will also need to add appropriate +`repositories` reference: + +[source,groovy,indent=0,subs="verbatim,attributes"] +---- + buildscript { + repositories { + maven.url "http://repo.spring.io/snapshot" + maven.url "http://repo.spring.io/milestone" + } + // ... + } +---- + + + +[[build-tool-plugins-gradle-dependencies-without-versions]] +=== Declaring dependencies without versions +The `spring-boot` plugin will register a custom Gradle `ResolutionStrategy` with your +build that allows you to omit version numbers when declaring dependencies to ``blessed'' +artifacts. All artifacts with a `org.springframework.boot` group ID, and any of the +artifacts declared in the `managementDependencies` section of the +{github-code}/spring-boot-dependencies/pom.xml[`spring-dependencies`] +POM can have their version number resolved automatically. + +Simply declare dependencies in the usual way, but leave the version number empty: + +[source,groovy,indent=0,subs="verbatim,attributes"] +---- + dependencies { + compile("org.springframework.boot:spring-boot-starter-web") + compile("org.thymeleaf:thymeleaf-spring4") + compile("nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect") + } +---- + + + +[[build-tool-plugins-gradle-packaging]] +=== Packaging executable jar and war files +Once the `spring-boot` plugin has been applied to your project it will automatically +attempt to rewrite archives to make them executable using the `bootRepackage` task. You +should configure your project to build a jar or war (as appropriate) in the usual way. + +The main class that you want to launch can either be specified using a configuration +option, or by adding a `Main-Class` attribute to the manifest. If you don't specify a +main class the plugin will search for a class with a +`public static void main(String[] args)` method. + +To build and run a project artifact, you can type the following: + +[indent=0] +---- + $ gradle build + $ java -jar build/libs/mymodule-0.0.1-SNAPSHOT.jar +---- + + + +[[build-tool-plugins-gradle-running-applications]] +=== Running a project in-place +To run a project in place without building a jar first you can use the "bootRun" task: + +[indent=0] +---- + $ gradle bootRun +---- + +Running this way makes your static classpath resources (i.e. in `src/main/resources` by +default) reloadable in the live application, which can be helpful at development time. + +[[build-tool-plugins-gradle-repackage-configuration]] +=== Repackage configuration +The gradle plugin automatically extends your build script DSL with a `springBoot` element +for configuration. Simply set the appropriate properties as you would any other Gradle +extension (see below for a list of configuration options): + +[source,groovy,indent=0,subs="verbatim,attributes"] +---- + springBoot { + backupSource = false + } +---- + + + +[[build-tool-plugins-gradle-repackage-custom-configuration]] +=== Repackage with custom Gradle configuration +Sometimes it may be more appropriate to not package default dependencies resolved from +`compile`, `runtime` and `provided` scopes. If the created executable jar file +is intended to be run as it is, you need to have all dependencies nested inside it; +however, if the plan is to explode a jar file and run main class manually, you may already +have some of the libraries available via `CLASSPATH`. This is a situation where +you can repackage your jar with a different set of dependencies. + +Using a custom +configuration will automatically disable dependency resolving from +`compile`, `runtime` and `provided` scopes. Custom configuration can be either +defined globally (inside the `springBoot` section) or per task. + +[source,groovy,indent=0,subs="verbatim,attributes"] +---- + task clientJar(type: Jar) { + appendix = 'client' + from sourceSets.main.output + exclude('**/*Something*') + } + + task clientBoot(type: BootRepackage, dependsOn: clientJar) { + withJarTask = clientJar + customConfiguration = "mycustomconfiguration" + } +---- + +In above example, we created a new `clientJar` Jar task to package a customized +file set from your compiled sources. Then we created a new `clientBoot` +BootRepackage task and instructed it to work with only `clientJar` task and +`mycustomconfiguration`. + +[source,groovy,indent=0,subs="verbatim,attributes"] +---- + configurations { + mycustomconfiguration.exclude group: 'log4j' + } + + dependencies { + mycustomconfiguration configurations.runtime + } +---- + +The configuration that we are referring to in `BootRepackage` is a normal +http://www.gradle.org/docs/current/dsl/org.gradle.api.artifacts.Configuration.html[Gradle +configuration]. In the above example we created a new configuration named +`mycustomconfiguration` instructing it to derive from a `runtime` and exclude the `log4j` +group. If the `clientBoot` task is executed, the repackaged boot jar will have all +dependencies from `runtime` but no `log4j` jars. + + + +[[build-tool-plugins-gradle-configuration-options]] +==== Configuration options +The following configuration options are available: + +[cols="2,4"] +|=== +|Name |Description + +|`mainClass` +|The main class that should be run. If not specified the value from the manifest will be + used, or if no manifest entry is the archive will be searched for a suitable class. + +|`providedConfiguration` +|The name of the provided configuration (defaults to `providedRuntime`). + +|`backupSource` +|If the original source archive should be backed-up before being repackaged (defaults + to `true`). + +|`customConfiguration` +|The name of the custom configuration. + +|`layout` +|The type of archive, corresponding to how the dependencies are laid out inside + (defaults to a guess based on the archive type). +|=== + + + +[[build-tool-plugins-understanding-the-gradle-plugin]] +=== Understanding how the Gradle plugin works +When `spring-boot` is applied to your Gradle project a default task named `bootRepackage` +is created automatically. The `bootRepackage` task depends on Gradle `assemble` task, and +when executed, it tries to find all jar artifacts whose qualifier is empty (i.e. tests and +sources jars are automatically skipped). + +Due to the fact that `bootRepackage` finds 'all' created jar artifacts, the order of +Gradle task execution is important. Most projects only create a single jar file, so +usually this is not an issue; however, if you are planning to create a more complex +project setup, with custom `Jar` and `BootRepackage` tasks, there are few tweaks to +consider. + +If you are 'just' creating custom jar files from your project you can simply disables +default `jar` and `bootRepackage` tasks: + +[source,groovy,indent=0,subs="verbatim,attributes"] +---- + jar.enabled = false + bootRepackage.enabled = false +---- + +Another option is to instruct the default `bootRepackage` task to only work with a +default `jar` task. + +[source,groovy,indent=0,subs="verbatim,attributes"] +---- + bootRepackage.withJarTask = jar +---- + +If you have a default project setup where the main jar file is created and repackaged, +'and' you still want to create additional custom jars, you can combine your custom +repackage tasks together and use `dependsOn` so that the `bootJars` task will run after +the default `bootRepackage` task is executed: + +[source,groovy,indent=0,subs="verbatim,attributes"] +---- + task bootJars + bootJars.dependsOn = [clientBoot1,clientBoot2,clientBoot3] + build.dependsOn(bootJars) +---- + +All the above tweaks are usually used to avoid situations where an already created boot +jar is repackaged again. Repackaging an existing boot jar will not break anything, but +you may find that it includes unnecessary dependencies. + + + +[[build-tool-plugins-other-build-systems]] +== Supporting other build systems +If you want to use a build tool other than Maven or Gradle, you will likely need to develop +your own plugin. Executable jars need to follow a specific format and certain entries need +to be written in an uncompressed form (see the +``<>'' section +in the appendix for details). + +The Spring Boot Maven and Gradle plugins both make use of `spring-boot-loader-tools` to +actually generate jars. You are also free to use this library directly yourself if you +need to. + + + +[[build-tool-plugins-repackaging-archives]] +=== Repackaging archives +To repackage an existing archive so that it becomes a self-contained executable archive +use `org.springframework.boot.loader.tools.Repackager`. The `Repackager` class takes a +single constructor argument that refers to an existing jar or war archive. Use one of the +two available `repackage()` methods to either replace the original file or write to a new +destination. Various settings can also be configured on the repackager before it is +run. + + + +[[build-tool-plugins-nested-libraries]] +=== Nested libraries +When repackaging an archive you can include references to dependency files using the +`org.springframework.boot.loader.tools.Libraries` interface. We don't provide any +concrete implementations of `Libraries` here as they are usually build system specific. + +If your archive already includes libraries you can use `Libraries.NONE`. + + + +[[build-tool-plugins-find-a-main-class]] +=== Finding a main class +If you don't use `Repackager.setMainClass()` to specify a main class, the repackager will +use http://asm.ow2.org/[ASM] to read class files and attempt to find a suitable class +with a `public static void main(String[] args)` method. An exception is thrown if more +than one candidate is found. + + + +[[build-tool-plugins-repackage-implementation]] +=== Example repackage implementation +Here is a typical example repackage: + +[source,java,indent=0] +---- + Repackager repackager = new Repackager(sourceJarFile); + repackager.setBackupSource(false); + repackager.repackage(new Libraries() { + @Override + public void doWithLibraries(LibraryCallback callback) throws IOException { + // Build system specific implementation, callback for each dependency + // callback.library(nestedFile, LibraryScope.COMPILE); + } + }); +---- + + + +[[build-tool-plugins-whats-next]] +== What to read next +If your interested to looking at how the build tool plugins were developed you can +look at the {github-code}/spring-boot-tools[`spring-boot-tools`] module on GitHub. More +technical details of the <> are covered in the appendix. + +If you have specific build related questions, you can check out the +``<>'' guides. diff --git a/spring-boot-docs/src/main/asciidoc/documentation-overview.adoc b/spring-boot-docs/src/main/asciidoc/documentation-overview.adoc new file mode 100644 index 00000000000..3292b6788e9 --- /dev/null +++ b/spring-boot-docs/src/main/asciidoc/documentation-overview.adoc @@ -0,0 +1,123 @@ +[[boot-documentation]] += Spring Boot Documentation + +[partintro] +-- +This section provides a brief overview of Spring Boot reference documentation. Think of +it as map for the rest of the document. You can read this reference guide in a linear +fashion, or you can skip sections if something doesn't interest you. + +-- + + +[[boot-documentation-getting-help]] +== Getting help +Having trouble with Spring Boot, We'd like to help! + +* Try the <> -- they provide solutions to the most common + questions +* Learn the Spring basics -- Spring Boot is builds on many other Spring projects, check + the http://spring.io[spring.io] web-site for a wealth of reference documentation. If + you are just starting out with Spring, try one of the http://spring.io/guides[guides] +* Ask a questions - we monitor http://stackoverflow.com[stackoverflow.com] for questions + tagged with http://stackoverflow.com/tags/spring-boot[`spring-boot`] +* Report bugs with Spring Boot at https://github.com/spring-projects/spring-boot/issues + +NOTE: All of Spring Boot is open source, including the documentation! If you find problems +with the docs; or if you just want to improve them, please <>. + +[[boot-documentation-first-steps]] +== First steps +If your just getting started with Spring Boot, or 'Spring' in general, +<> + +* *From scratch:* + <> | + <> +* *Tutorial:* + <> | + <> +* *Running your example:* + <> | + <> + + + +== Working with Spring Boot +Ready to actually start using Spring Boot? <>. + +* *Build systems:* + <> | + <> | + <> | + <> +* *Best practices:* + <> | + <> | + <> | + <> +* *Running your code* + <> | + <> | + <> | + <> +* *Packaging your app:* + <> +* *Spring Boot CLI:* +<> + +== Learning about Spring Boot features +Need more details about Spring Boot's core features? +<>! + +* *Core Features:* + <> | + <> | + <> | + <> +* *Web Applications:* + <> | + <> +* *Working with data:* + <> | + <> +* *Testing:* + <> | + <> | + <> +* *Extending:* + <> | + <> + + +== Moving to production +When your ready to push your Spring Boot application to production, we've got +<>! + +* *Management endpoints:* +<> | +<> +* *Connection options:* +<> | +<> | +<> +* *Monitoring:* +<> | +<> | +<> + +== Advanced topics +Lastly, we have a few topics for the more advanced user. + +* *Build tool plugins:* +<> | +<> +* *Appendix:* +<> | +<> | +<> + + + + diff --git a/spring-boot-docs/src/main/asciidoc/getting-started.adoc b/spring-boot-docs/src/main/asciidoc/getting-started.adoc new file mode 100644 index 00000000000..f169dcf5a1f --- /dev/null +++ b/spring-boot-docs/src/main/asciidoc/getting-started.adoc @@ -0,0 +1,731 @@ +[[getting-started]] += Getting started + +[partintro] +-- +If your just getting started with Spring Boot, or 'Spring' in general, this is the section +for you! Here we answer the basic '``what?''', '``how?''' and '``why?''' questions. You'll +find a gentle introduction to Spring Boot along with installation instructions. +We'll then build our first Spring Boot application, discussing some core principles as +we go. +-- + + +[[getting-started-introducing-spring-boot]] +== Introducing Spring Boot +Spring Boot makes it easy to create stand-alone, production-grade Spring based +Applications that can you can ``just run''. We take an opinionated view of the Spring +platform and third-party libraries so you can get started with minimum fuss. Most Spring +Boot applications need very little Spring configuration. + +You can use Spring Boot to create Java applications that can be started using `java -jar` +or more traditional war deployments. We also provide a command line tool that runs +``spring scripts''. + +Our primary goals are: + +* Provide a radically faster and widely accessible getting started experience for all +Spring development. +* Be opinionated out of the box, but get out of the way quickly as requirements start to +diverge from the defaults. +* Provide a range of non-functional features that are common to large classes of projects +(e.g. embedded servers, security, metrics, health checks, externalized configuration). +* Absolutely no code generation and no requirement for XML configuration. + + + +[[getting-started-installing-spring-boot]] +== Installing Spring Boot +Spring Boot can be used with ``classic'' Java development tools or installed as a command +line tool. Regardless, you will need http://www.java.com[Java SDK v1.6] or higher. You +should check your current Java installation before you begin: + +[indent=0] +---- + $ java -version +---- + +If you are new to Java development, or if you just want to experiment with Spring Boot +you might want to try the <> first, +otherwise, read on for ``classic'' installation instructions. + +TIP: Although Spring Boot is compatible with Java 1.6, if possible, you should consider +using the latest version of Java. + +[[getting-started-installation-instructions-for-java]] +=== Installation instructions for the Java developer +You can use Spring Boot in the same way as any standard java library. Simply include the +appropriate `spring-boot-*.jar` files on your classpath. Spring Boot does not require +any special ``tools'' integration, so you can use any IDE or text editor; and there is +nothing special about a Spring Boot application, so you can run and debug as you would +any other Java program. + +Although you _could_ just copy Spring Boot jars, we generally recommend that you use a +build tool that supports dependency management (such as Maven or Gradle). + + + +[[getting-started-maven-installation]] +==== Maven installation +Spring Boot is compatible with Apache Maven 3.0 or above. If you don't already have Maven +installed you can follow the instructions at http://maven.apache.org. + +TIP: On many operating systems Maven can be installed via a package manager. If you're an +OSX Homebrew user try `brew install maven`. Ubuntu users can run +`sudo apt-get install maven`. + +Spring Boot dependencies use the `org.springframework.boot` `groupId`. Typically your +Maven POM file will inherit from the `spring-boot-starter-parent` project and declare +dependencies to one or more <>. Spring Boot also provides an optional +<> to create +executable jars. + +Here is a typical `pom.xml` file: + +[source,xml,indent=0,subs="verbatim,quotes,attributes"] +---- + + + 4.0.0 + + com.example + myproject + 0.0.1-SNAPSHOT + + + + org.springframework.boot + spring-boot-starter-parent + {spring-boot-version} + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + +ifeval::["{spring-boot-repo}" != "release"] + + + + + spring-snapshots + http://repo.spring.io/snapshot + true + + + spring-milestones + http://repo.spring.io/milestone + + + + + spring-snapshots + http://repo.spring.io/snapshot + + + spring-milestones + http://repo.spring.io/milestone + + +endif::[] + +---- + + + +[[getting-started-gradle-installation]] +==== Gradle installation +Spring Boot is compatible with Gradle 1.6 or above. If you don't already have Gradle +installed you can follow the instructions at http://www.gradle.org/. + +Spring Boot dependencies can be declared using the `org.springframework.boot` `group`. +Typically your project will declare dependencies to one or more +<>. Spring Boot +provides a useful <> +that can be used to simplify dependency declarations and to create executable jars. + +.Gradle Wrapper +**** +The Gradle Wrapper provides a nice way of ``obtaining'' Gradle when you need to build a +project. It's a small script and library that you commit alongside your code to bootstrap +the build process. See http://www.gradle.org/docs/current/userguide/gradle_wrapper.html +for details. +**** + +Here is a typical `build.gradle` file: + +[source,groovy,indent=0,subs="verbatim,attributes"] +---- + buildscript { + repositories { + mavenCentral() +ifndef::release[] + maven { url "http://repo.spring.io/snapshot" } + maven { url "http://repo.spring.io/milestone" } +endif::release[] + } + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:{spring-boot-version}") + } + } + + apply plugin: 'java' + apply plugin: 'spring-boot' + + jar { + baseName = 'myproject' + version = '0.0.1-SNAPSHOT' + } + + repositories { + mavenCentral() +ifndef::release[] + maven { url "http://repo.spring.io/snapshot" } + maven { url "http://repo.spring.io/milestone" } +endif::release[] + } + + dependencies { + compile("org.springframework.boot:spring-boot-starter-web") + testCompile("junit:junit") + } +---- + + + +[[getting-started-installing-the-cli]] +=== Installing the Spring Boot CLI +The Spring Boot CLI is a command line tool that can be used if you want to quickly +prototype with Spring. It allows you to run http://groovy.codehaus.org/[Groovy] scripts, +which means that you have a familiar Java-like syntax, without so much boilerplate code. + +You don't need to use the CLI to work with Spring Boot but it's definitely the quickest +way to get a Spring application off the ground. + + + +[[getting-started-manual-cli-installation]] +==== Manual installation +You can download the Spring CLI distribution from the Spring software repository: + +* http://repo.spring.io/{spring-boot-repo}/org/springframework/boot/spring-boot-cli/{spring-boot-version}/spring-boot-cli-{spring-boot-version}-bin.zip[spring-boot-cli-{spring-boot-version}-bin.zip] +* http://repo.spring.io/{spring-boot-repo}/org/springframework/boot/spring-boot-cli/{spring-boot-version}/spring-boot-cli-{spring-boot-version}-bin.tar.gz[spring-boot-cli-{spring-boot-version}-bin.tar.gz] + +Cutting edge http://repo.spring.io/snapshot/org/springframework/boot/spring-boot-cli/[snapshot distributions] +are also available. + +Once downloaded, follow the {github-raw}/spring-boot-cli/src/main/content/INSTALL.txt[INSTALL.txt] +instructions from the unpacked archive. In summary: there is a `spring` script +(`spring.bat` for Windows) in a `bin/` directory in the `.zip` file, or alternatively you +can use `java -jar` with the `.jar` file (the script helps you to be sure that the +classpath is set correctly). + + + +[[getting-started-gvm-cli-installation]] +==== Installation with GVM +GVM (the Groovy Environment Manager) can be used for managing multiple versions of +various Groovy and Java binary packages, including Groovy itself and the Spring Boot CLI. +Get `gvm` from http://gvmtool.net and install Spring Boot with + +[indent=0,subs="verbatim,quotes,attributes"] +---- + $ gvm install springboot + $ spring --version + Spring Boot v{spring-boot-version} +---- + +If you are developing features for the CLI and want easy access to the version you just +built, follow these extra instructions. + +[indent=0,subs="verbatim,quotes,attributes"] +---- + $ gvm install springboot dev /path/to/spring-boot/spring-boot-cli/target/spring-boot-cli-{spring-boot-version}-bin/spring-{spring-boot-version}/ + $ gvm use springboot dev + $ spring --version + Spring CLI v{spring-boot-version} +---- + +This will install a local instance of `spring` called the `dev` instance inside your gvm +repository. It points at your target build location, so every time you rebuild Spring +Boot, `spring` will be up-to-date. + +You can see it by doing this: + +[indent=0,subs="verbatim,quotes,attributes"] +---- + $ gvm ls springboot + + ================================================================================ + Available Springboot Versions + ================================================================================ + > + dev + * {spring-boot-version} + + ================================================================================ + + - local version + * - installed + > - currently in use + ================================================================================ +---- + + + +[[getting-started-homebrew-cli-installation]] +==== OSX Homebrew installation +If you are on a Mac and using http://brew.sh/[Homebrew], all you need to do to install +the Spring Boot CLI is: + +[indent=0] +---- + $ brew tap pivotal/tap + $ brew install springboot +---- + +Homebrew will install `spring` to `/usr/local/bin`. + +NOTE: If you don't see the formula, you're installation of brew might be out-of-date. +Just execute `brew update` and try again. + + + +[[getting-started-cli-command-line-completion]] +==== Command-line completion +Spring Boot CLI ships with scripts that provide command completion for +http://en.wikipedia.org/wiki/Bash_%28Unix_shell%29[BASH] and +http://en.wikipedia.org/wiki/Zsh[zsh] shells. You can `source` the script (also named +`spring`) in any shell, or put it in your personal or system-wide bash completion +initialization. On a Debian system the system-wide scripts are in `/etc/bash_completion.d` +and all scripts in that directory are executed when a new shell starts. To run the script +manually, e.g. if you have installed using `GVM` + +[indent=0] +---- + $ . ~/.gvm/springboot/current/bash_completion.d/spring + $ spring + grab help jar run test version +---- + +NOTE: If you install Spring Boot CLI using Homebrew, the command-line completion scripts +are automatically registered with your shell. + + + +[[getting-started-cli-example]] +==== Quick start Spring CLI example +Here's a really simple web application that you can use to test you installation. Create +a file called `app.groovy`: + +[source,groovy,indent=0,subs="verbatim,quotes,attributes"] +---- + @Controller + class ThisWillActuallyRun { + + @RequestMapping("/") + @ResponseBody + String home() { + return "Hello World!" + } + + } +---- + +Then simply run it from a shell: + +[indent=0] +---- + $ spring run app.groovy +---- + +NOTE: It will take some time when you first run the application as dependencies are +downloaded, subsequent runs will be much quicker. + +Open http://localhost:8080 in your favorite web browser and you should see the following +output: + +[indent=0] +---- + Hello World! +---- + + + +[[getting-started-first-application]] +== Developing your first Spring Boot application +Let's develop a simple ``Hello World!'' web application in Java that highlights some +of Spring Boot's key features. We'll use Maven to build this project since most IDEs +support it. + +TIP: The http://spring.io[spring.io] web site contains many ``Getting Started'' guides +that use Spring Boot. If you're looking to solve a specific problem; check there first. + +Before we begin, open a terminal to check that you have valid versions of Java and Maven +installed. + +[indent=0] +---- + $ java -version + java version "1.7.0_51" + Java(TM) SE Runtime Environment (build 1.7.0_51-b13) + Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode) +---- + +[indent=0] +---- + $ mvn -v + Apache Maven 3.1.1 (0728685237757ffbf44136acec0402957f723d9a; 2013-09-17 08:22:22-0700) + Maven home: /Users/user/tools/apache-maven-3.1.1 + Java version: 1.7.0_51, vendor: Oracle Corporation +---- + +NOTE: This sample needs to be created in its own folder. Subsequent instructions assume +that you have created a suitable folder and that it is your ``current directory''. + + + +[[getting-started-first-application-pom]] +=== Creating the POM +We need to start by creating a Maven `pom.xml` file. The `pom.xml` is the recipe that +will be used to build your project. Open you favorite text editor and add the following: + +[source,xml,indent=0,subs="verbatim,quotes,attributes"] +---- + + + 4.0.0 + + com.example + myproject + 0.0.1-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + {spring-boot-version} + + + + +ifeval::["{spring-boot-repo}" != "release"] + + + + spring-snapshots + http://repo.spring.io/snapshot + true + + + spring-milestones + http://repo.spring.io/milestone + + + + + spring-snapshots + http://repo.spring.io/snapshot + + + spring-milestones + http://repo.spring.io/milestone + + +endif::[] + +---- + +This should give you a working build, you can test it out by running `mvn package` (you +can ignore the '``jar will be empty - no content was marked for inclusion!''' warning for +now). + +NOTE: At this point you could import the project into an IDE (most modern Java IDE's +include built-in support for Maven). For simplicity, we will continue to use a plain +text editor for this example. + + + +[[getting-started-first-application-dependencies]] +=== Adding classpath dependencies +Spring Boot provides a number of ``Starter POMs'' that make easy to add jars to your +classpath. Our sample application has already used `spring-boot-starter-parent` in the +`parent` section of the POM. The `spring-boot-starter-parent` is a special starter +that provides useful Maven defaults. It also provides a `dependency-management` section +so that you can omit `version` tags for ``blessed'' dependencies. + +Other ``Starter POMs'' simply provide dependencies that you are likely to need when +developing a specific type of application. Since we are developing web application we will +add a `spring-boot-starter-web` dependency -- but before that, lets look at what we +currently have. + +[indent=0] +---- + $ mvn dependency:tree + + [INFO] com.example:myproject:jar:0.0.1-SNAPSHOT + [INFO] +- junit:junit:jar:4.11:test + [INFO] | \- org.hamcrest:hamcrest-core:jar:1.3:test + [INFO] +- org.mockito:mockito-core:jar:1.9.5:test + [INFO] | \- org.objenesis:objenesis:jar:1.0:test + [INFO] \- org.hamcrest:hamcrest-library:jar:1.3:test +---- + +The `mvn dependency:tree` command prints tree representation of your project dependencies. +You can see that `spring-boot-starter-parent` has already provides some useful test +dependencies. Lets edit our `pom.xml` and add the `spring-boot-starter-web` dependency +just below the `parent` section: + +[source,xml,indent=0,subs="verbatim,quotes,attributes"] +---- + + + org.springframework.boot + spring-boot-starter-web + + +---- + +If you run `mvn dependency:tree` again, you will see that there are now a number of +additional dependencies, including the Tomcat web server and Spring Boot itself. + + + +[[getting-started-first-application-code]] +=== Writing the code +To finish our application we need to create a single Java file. Maven will compile sources +from `src/main/java` so you need to create that folder structure, then add a file named +`src/main/java/Example.java`: + +[source,java,indent=0] +---- + import org.springframework.boot.*; + import org.springframework.boot.autoconfigure.*; + import org.springframework.stereotype.*; + import org.springframework.web.bind.annotation.*; + + @Controller + @EnableAutoConfiguration + public class Example { + + @RequestMapping("/") + @ResponseBody + String home() { + return "Hello World!"; + } + + public static void main(String[] args) throws Exception { + SpringApplication.run(Example.class, args); + } + + } +---- + +Although there isn't much code here, quite a lot is going on. Lets step though the +important parts. + + + +[[getting-started-first-application-annotations]] +==== The @Controller, @RequestMapping and @ResponseBody annotations +The first annotation on our `Example` class is `@Controller`. This is known as a +_stereotype_ annotation. It provides hints for people reading the code, and for Spring, +that the class plays a specific role. In this case, our class is a web `@Controller` so +Spring will consider it when handling incoming web requests. + +The `@RequestMapping` annotation provides ``routing'' information. It is telling Spring +that any HTTP request with the path "`/`" should be mapped to the `home` method. The +additional `@ResponseBody` annotation tells Spring to render the resulting string directly +back to the caller. + +TIP: The `@Controller`, `@RequestMapping` and `@ResponseBody` annotations are Spring MVC +annotations (they are not specific to Spring Boot). See the +<{spring-reference}/#mvc>[MVC section] in the Spring +Reference Documentation for more details. + + + +[[getting-started-first-application-auto-configuration]] +==== The @EnableAutoConfiguration annotation +The second class-level annotation is `@EnableAutoConfiguration`. This annotation tells +Spring Boot to ``guess'' how you will want to configure Spring, based on the jar +dependencies that you have added. Since `spring-boot-starter-web` added Tomcat and +Spring MVC, the auto-configuration will assume that you are developing a web application +and setup Spring accordingly. + +.Starter POMs and Auto-Configuration +**** +Auto-configuration is designed to work well with ``Starter POMs'', but the two concepts +are not directly tied. You are free to pick-and-choose jar dependencies outside of the +starter POMs and Spring Boot will still do its best to auto-configure your application. +**** + + + +[[getting-started-first-application-main-method]] +==== The ``main'' method +The final part of our application is the `main` method. This is just a standard method +that follows the Java convention for an application entry point. Our main method delegates +to Spring Boot's `SpringApplication` class by calling `run`. `SpringApplication` will +bootstrap our application, starting Spring which will in turn start the auto-configured +Tomcat web server. We need to pass `Example.class` as an argument to the `run` method to +tell `SpringApplication` which is the primary Spring component. The `args` array is also +passed though to expose any command-line arguments. + + + +[[getting-started-first-application-run]] +=== Running the example +At this point out application should work. Since we have used the +`spring-boot-starter-parent` POM we have a useful `run` goal that we can use to start +the application. Type `mvn spring-boot:run` from the root project directory to start the +application: + +[indent=0,subs="attributes"] +---- + $ mvn spring-boot:run + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ + ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v{spring-boot-version}) + ....... . . . + ....... . . . (log output here) + ....... . . . + ........ Started Example in 2.222 seconds (JVM running for 6.514) +---- + +If you open a web browser to http://localhost:8080 you should see the following output: + +[indent=0] +---- + Hello World! +---- + +To gracefully exit the application hit `ctrl-c`. + + + +[[getting-started-first-application-executable-jar]] +=== Creating an executable jar +Lets finish our example by creating a completely self-contained executable jar file that +we could run in production. Executable jars (sometimes called ``fat jars'') are archives +containing your compiled classes along with all of the jar dependencies that your code +needs to run. + +.Executable jars and Java +**** +Java does not provide any standard way to load nested jar files (i.e. jar files that are +themselves contained within a jar). This can be problematic if you are looking to +distribute a self contained application. + +To solve this problem, many developers use ``shaded'' jars. A shaded jar simply packages +all classes, from all jars, into a single ``uber jar''. The problem with shaded jars is that +it becomes hard to see which libraries you are actually using in your application. It can +also be problematic if the the same filename is used (but with different content) in +multiple jars. + +Spring Boot takes a <> and allows you to actually nest jars directly. +**** + +To create an executable jar we need to add the `spring-boot-maven-plugin` to our +`pom.xml`. Insert the following lines just below the `dependencies` section: + +[source,xml,indent=0,subs="verbatim,quotes,attributes"] +---- + + + + org.springframework.boot + spring-boot-maven-plugin + + + +---- + +Save your `pom.xml` and run `mvn package` from the command line: + +[indent=0,subs="attributes"] +---- + $ mvn package + + [INFO] Scanning for projects... + [INFO] + [INFO] ------------------------------------------------------------------------ + [INFO] Building myproject 0.0.1-SNAPSHOT + [INFO] ------------------------------------------------------------------------ + [INFO] .... .. + [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ myproject --- + [INFO] Building jar: /Users/developer/example/spring-boot-example/target/myproject-0.0.1-SNAPSHOT.jar + [INFO] + [INFO] --- spring-boot-maven-plugin:{spring-boot-version}:repackage (default) @ myproject --- + [INFO] ------------------------------------------------------------------------ + [INFO] BUILD SUCCESS + [INFO] ------------------------------------------------------------------------ +---- + +If you look in the `target` directory you should see `myproject-0.0.1-SNAPSHOT.jar`. The +file should be around 10 Mb in size. If you want to peek inside, you can use `jar tvf`: + +[indent=0] +---- + $ jar tvf target/myproject-0.0.1-SNAPSHOT.jar +---- + +You should also see a much smaller file named `myproject-0.0.1-SNAPSHOT.jar.original` +in the `target` directory. This is the original jar file that Maven created before it was +repackaged by Spring Boot. + +To run that application, use the `java -jar` command: + +[indent=0,subs="attributes"] +---- + $ java -jar target/myproject-0.0.1-SNAPSHOT.jar + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ + ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v{spring-boot-version}) + ....... . . . + ....... . . . (log output here) + ....... . . . + ........ Started Example in 3.236 seconds (JVM running for 3.764) +---- + +As before, to gracefully exit the application hit `ctrl-c`. + + + +[[getting-started-whats-next]] +== What to read next +Hopefully this section has provided you with some of the Spring Boot basics, and got you +on your way to writing your own applications. If your a ``task oriented'' type of +developer you might want to jump over to http://spring.io and check out some of the +http://spring.io/guides/[getting started] guides that solve specific +'``How do I do that with Spring''' problems; we also have a Spring Boot specific +``<>'' reference documentation. + +Otherwise, the next logical step is to read the ``<>'' +section. If you're really impatient, you could also jump ahead and read about +``<>''. diff --git a/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-docs/src/main/asciidoc/howto.adoc new file mode 100644 index 00000000000..81ac1973930 --- /dev/null +++ b/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -0,0 +1,17 @@ +[[howto]] += ``How-to'' guides + +[partintro] +-- +This section provides answers to some common '``how do I do that...''' type of questions +that often arise when using Spring Boot. This is by no means an exhaustive list, but it +does cover quite a lot. + +If you are having a specific problem that we don't cover here, you might want to check out +http://stackoverflow.com/tags/spring-boot[stackoverflow.com] to see if someone has +already provided an answer; this is also a great place to ask new questions (please use +the `spring-boot` tag). + +We're also more than happy to extend this section; If you want to add a ``how-to'' you +can send us a {github-code}[pull request]. +-- diff --git a/spring-boot-docs/src/main/asciidoc/index.adoc b/spring-boot-docs/src/main/asciidoc/index.adoc index 82f12e55392..607b2dd214c 100644 --- a/spring-boot-docs/src/main/asciidoc/index.adoc +++ b/spring-boot-docs/src/main/asciidoc/index.adoc @@ -28,7 +28,14 @@ Phillip Webb; Dave Syer; :spring-data-mongo-javadoc: http://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb // ====================================================================================== -= Spring Boot -== Reference Documentation +include::documentation-overview.adoc[] +include::getting-started.adoc[] +include::using-spring-boot.adoc[] +include::spring-boot-features.adoc[] +include::production-ready-features.adoc[] +include::spring-boot-cli.adoc[] +include::build-tool-plugins.adoc[] +include::howto.adoc[] +include::appendix.adoc[] // ====================================================================================== diff --git a/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc new file mode 100644 index 00000000000..57545d6ea4d --- /dev/null +++ b/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -0,0 +1,747 @@ +[[production-ready]] += Production-ready features + +[partintro] +-- +Spring Boot includes a number of additional features to help you monitor and manage your +application when it's pushed to production. You can choose to manage and monitor your +application using HTTP endpoints, with JMX or even by remote shell (SSH or Telnet). +Auditing, health and metrics gathering can be automatically applied to your application. +-- + + + +[[production-ready-enabling]] +== Enabling production-ready features. +The `spring-boot-actuator` project provides all of Spring Boot's production-ready +features. The simplist way to enable the features is to add a dependency to the +`spring-boot-starter-actuator` ``Starter POM''. + +.Definition of Actuator +**** +An actuator is a manufacturing term, referring to a mechanical device for moving or +controlling something. Actuators can generate a large amount of motion from a small +change. +**** + +To add the actuator to a Maven based project, add the following ``starter'' +dependency: + +[source,xml,indent=0] +---- + + + org.springframework.boot + spring-boot-starter-actuator + + +---- + +For Gradle, use the declaration: + +[source,groovy,indent=0] +---- + dependencies { + compile("org.springframework.boot:spring-boot-starter-actuator") + } +---- + + + +[[production-ready-endpoints]] +== Endpoints +Actuator endpoints allow you to monitor and interact with your application. Spring Boot +includes a number of built-in endpoints and you can also add your own. For example the +`health` endpoint provides basic application health information. + +The way that enpoints are exposed will depend on the type of technology that you choose. +Most applications choose HTTP monitoring, where the ID of the endpoint is mapped +to a URL. For example, by default, the `health` endpoint will be mapped to `/health`. + +The following endpoints are available: + +[cols="2,5,1"] +|=== +| ID | Description | Sensitive + +|`autoconfig` +|Displays an auto-configuration report showing all auto-configuration candidates and the + reason why they ``were'' or ``were not'' applied. +|true + +|`beans` +|Displays a complete list of all the Spring Beans in your application. +|true + +|`configprops` +|Displays a collated list of all `@ConfigurationProperties`. +|true + +|`dump` +|Performs a thread dump. +|true + +|`env` +|Exposes properties from Spring's `ConfigurableEnvironment`. +|true + +|`health` +|Shows application health information (defaulting to a simple ``OK'' message). +|false + +|`info` +|Displays arbitrary application info. +|false + +|`metrics` +|Shows ``metrics'' information for the current application. +|true + +|`mappings` +|Displays a collated list of all `@RequestMapping` paths. +|true + +|`shutdown` +|Allows the application to be gracefully shutdown (not enabled by default). +|true + +|`trace` +|Displays trace information (by default the last few HTTP requests). +|true +|=== + +NOTE: Depending on how an endpoint is exposed, the `sensitive` parameter may be used as +a security hint. For example, sensitive endpoints will require a username/password when +they are accessed over HTTP (or simply disabled if web security is not enabled). + + + +[[production-ready-customizing-endpoints]] +=== Customizing endpoints +Endpoints can be customized using Spring properties. You can change if an endpoint is +`enabled`, if it is considered `sensitive` and even its `id`. + +For example, here is an `application.properties` that changes the sensitivity and id +of the `beans` endpoint and also enables `shutdown`. + +[indent=0] +---- + endpoints.beans.id=springbeans + endpoints.beans.sensitive=false + endpoints.shutdown.enabled=true +---- + +NOTE: The prefix "`endpoints` + `.` + `name`" is used to uniquely identify the endpoint +that is being configured. + + + +[[production-ready-health]] +=== Custom health information +The default information exposed by the `health` endpoint is a simple ``OK'' message. It +is often useful to perform some additional health checks, for example you might check +that a database connection works, or that a remote REST endpoint is functioning. + +To provide custom health information you can register a Spring bean that implements the +{sc-spring-boot-actuator}/health/HealthIndicator.{sc-ext}[`HealthIndicator`] interface. + +[source,java,indent=0] +---- + import org.springframework.boot.actuate.health.HealthIndicator; + import org.springframework.stereotype.Component; + + @Component + public class MyHealth implements HealthIndicator { + + @Override + public String health() { + // perform some specific health check + return ... + } + + } +---- + +Spring Boot also provides a +{sc-spring-boot-actuator}/health/SimpleHealthIndicator/{sc-ext}[`SimpleHealthIndicator`] +implementation that attempts a simple database test. + + + +[[production-ready-application-info]] +=== Custom application info information +You can customize the data exposed by the `info` endpoint by settings `info.*` Spring +properties. All `Environment` properties under the info key will be automatically +exposed. For example, you could add the following to your `application.properties`: + +[indent=0] +---- + info.app.name: MyService + info.app.description: My awesome service + info.app.version: 1.0.0 +---- + +If you are using Maven, you can automatically expand info properties from the Maven +project using resource filtering. In your `pom.xml` you have (inside the `` +element): + +[source,xml,indent=0] +---- + + + src/main/resources + true + + +---- + +You can then refer to your Maven ``project properties'' via placeholders, e.g. + +[indent=0] +---- + project.artifactId: myproject + project.name: Demo + project.version: X.X.X.X + project.description: Demo project for info endpoint + info.build.artifact: ${project.artifactId} + info.build.name: ${project.name} + info.build.description: ${project.description} + info.build.version: ${project.version} +---- + +NOTE: In the above example we used `project.*` to set some values to be used as +fallbacks if the Maven resource filtering has not been switched on for some reason. + + + +[[production-ready-git-commit-information]] +==== Git commit information +Another useful feature of the `info` endpoint is its ability to publish information +about the state of your `git` source code repository when the project was built. If a +`git.properties` file is contained in your jar the `git.branch` and `git.commit` +properties will be loaded. + +For Maven users the `spring-boot-starter-parent` POM includes a pre-configured plugin to +generate a `git.properties` file. Simply add the following declaration to your POM: + +[source,xml,indent=0] +---- + + + + pl.project13.maven + git-commit-id-plugin + + + +---- + +A similar https://github.com/ajoberstar/gradle-git[`gradle-git`] plugin is also available +for Gradle users, although a little more work is required to generate the properties file. + + + +[[production-ready-monitoring]] +== Monitoring and management over HTTP +If you are developing a Spring MVC application, Spring Boot Actuator will auto-configure +all non-sensitive endpoints to be exposed over HTTP. The default convention it to use the +`id` of the endpoint as the URL path. For example, `health` is exposed as `/health`. + + + +[[production-ready-sensitive-endpoints]] +=== Exposing sensitive endpoints +If you use ``Spring Security'' sensitive endpoints will also be exposed over HTTP. By +default ``basic'' authentication will be used with the username `user` and a generated +password. + +TIP: Generated passwords are logged as the application starts. Search for ``Using default +password for application endpoints''. + +You can use Spring properties to change the username and passsword and to change the +security role required to access the endpoints. For example, you might set the following +in your `application.properties`: + +[indent=0] +---- + security.user.name=admin + security.user.password=secret + management.security.role=SUPERUSER +---- + + + +[[production-ready-customizing-management-server-context-path]] +=== Customizing the management server context path +Sometimes it is useful to group all management endpoints under a single path. For example, +your application might already use `/info` for another purpose. You can use the +`management.contextPath` property to set a prefix for your manangement endpoint: + +[indent=0] +---- + management.contextpath=/manage +---- + +The `application.properties` example above will change the endpoint from `/{id}` to +`/manage/{id}` (e.g. `/manage/info`). + + + +[[production-ready-customizing-management-server-port]] +=== Customizing the management server port +Exposing management endpoints using the default HTTP port is a sensible choice for cloud +based deployments. If, however, your application runs inside your own data center you +may prefer to expose endpoints using a different HTTP port. + +The `management.port` property can be used to change the HTTP port. Since your management +port is often protected by a firewall, and not exposed to the public, you might also +want to disable management security: + +[indent=0] +---- + management.port=8081 + management.security.enabled=false +---- + + + +[[production-ready-customizing-management-server-address]] +=== Customizing the management server address +You can customize the address that the management endpoints are available on by +setting the `management.security.address` property. This can be useful if you want to +listen only on an internal or ops-facing network, or to only listen for connections from +`localhost`. + +NOTE: You can only listen on a different address if the port is different to the +main server port. + +Here is an example `application.properties` that will not allow remote management +connections: + +[indent=0] +---- + management.port=8081 + management.address=127.0.0.1 +---- + + + +[[production-ready-disabling-http-endpoints]] +=== Disabling HTTP endpoints +If you don't want to expose endpoints over HTTP you can set the management port to `-1`: + +[indent=0] +---- + management.port=-1 +---- + + + +[[production-ready-jmx]] +== Monitoring and management over JMX +Java Management Extensions (JMX) provide a standard mechanism to monitor and manage +applications. By default Spring Boot will expose management endpoints as JMX MBeans +under the `org.springframework.boot` domain. + + + +[[production-ready-custom-mbean-names]] +=== Customizing MBean names +The name of the MBean is usually generated from the `id` of the endpoint. For example +the `health` endpoint is exposed as `org.springframework.boot/Endpoint/HealthEndpoint`. + +If your application contains more than one Spring `ApplicationContext` you may find that +names clash. To solve this problem you can set the `endpoints.jmx.uniqueNames` property +to `true` so that MBean names are always unique. + +You can also customize the JMX domain under which endpoints are exposed. Here is an +example `application.properties`: + +[indent=0] +---- + endpoints.jmx.domain=myapp + endpoints.jmx.uniqueNames=true +---- + + + +[[production-ready-disable-jmx-endpoints]] +=== Disabling JMX endpoints +If you don't want to expose endpoints over JMX you can set the `spring.jmx.enabled` +property to `false`: + +[indent=0] +---- + spring.jmx.enabled=false +---- + + + +[[production-ready-jolokia]] +=== Using Jolokia for JMX over HTTP +Jolokia is a JMX-HTTP bridge giving an alternative method of accessing JMX beans. To +use Jolokia, simply include a dependency to `org.jolokia:jolokia-core`. For example, +using Maven you you add the following: + +[source,xml,indent=0] +---- + + org.jolokia + jolokia-core + +---- + +Jolokia can then be accessed using `/jolokia` on your management HTTP server. + + + +[[production-ready-customizing-jolokia]] +==== Customizing Jolokia +Jolokia has a number of settings that you would traditionally configure using servlet +parameters. With Spring Boot you can use your `application.properties`, simply prefix the +parameter with `jolokia.config.`: + +[indent=0] +---- + jolokia.config.debug=true +---- + + + +[[production-ready-disabling-jolokia]] +==== Disabling Jolokia +If you are using Jolokia but you don't want Spring Boot to configure it, simply set the +`endpoints.jolokia.enabled` property to `false`: + +[indent=0] +---- + jolokia.config.enabled=false +---- + + + +[[production-ready-remote-shell]] +== Monitoring and management using a remote shell +Spring Boot supports an integrated Java shell called ``CRaSH''. You can use CRaSH to +`ssh` or `telnet` into your running application. To enable remote shell support add a +dependency to `spring-boot-starter-shell-remote`: + +[source,xml,indent=0] +---- + + org.springframework.boot + spring-boot-starter-shell-remote + +---- + +TIP: If you want to also enable telnet access your will additionally need a dependency +on `org.crsh:crsh.shell.telnet`. + + + +[[production-ready-connecting-to-the-remote-shell]] +=== Connecting to the remote shell +By default the remote shell will listen for connections on port `2000`. The default user +is `user` and the default password will be randomly generated and displayed in the log +output, you should see a message like this: + +[indent=0] +---- + Using default password for shell access: ec03e16c-4cf4-49ee-b745-7c8255c1dd7e +---- + +Linux and OSX users can use `ssh` to connect to the remote shell, Windows users can +download and install http://www.putty.org/[PuTTY]. + +[indent=0,subs="attributes"] +---- + $ ssh -p 2000 user@localhost + + user@localhost's password: + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ + ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v{spring-boot-version}) on myhost +---- + +Type `help` for a list of commands. Spring boot provides `metrics`, `beans` and +`autoconfig` commands. You can also use the `jmx` command to query endpoint data: + +[indent=0] +---- + jmx find -p org.springframework.boot:type=Endpoint,name=healthEndpoint | jmx get Data +---- + + + +[[production-ready-remote-shell-credentials]] +==== Remote shell credentials +You can use the `shell.auth.simple.username` and `shell.auth.simple.password` properties +to configure custom connection credentials. It is also possible to use a +``Spring Security'' `AuthenticationManager` to handle login duties. See the +{dc-spring-boot-actuator}/autoconfigure/CrshAutoConfiguration.{dc-ext}[`CrshAutoConfiguration`] +and {dc-spring-boot-actuator}/autoconfigure/ShellProperties.{dc-ext}[`ShellProperties`] +Javadoc for full details. + + + +[[production-ready-extending-the-remote-shell]] +=== Extending the remote shell +The remote shell can be extended in a number of interesting ways. + + + +[[production-ready-remote-commands]] +==== Remote shell commands +You can write additional shell commands using Groovy or Java (see the CRaSH documentation +for details). By default Spring Boot will search for commands in the following locations: + +* `classpath*:/commands/**` +* `classpath*:/crash/commands/**` + +TIP: You can change the search path by settings a `shell.commandpathpatterns` property. + +Here is a simple ``hello world'' command that could be loaded from +`src/main/resources/commands/Hello.groovy` + +[source,groovy,indent=0] +---- + package commands + + import org.springframework.boot.actuate.endpoint.BeansEndpoint + + class hello { + + @Usage("Say Hello") + @Command + def main(InvocationContext context) { + return "Hello" + } + + } +---- + +Spring Boot adds some additional attributes to `InvocationContext` that you can access +from your command: + +[cols="2,3"] +|=== +| Attribute Name | Description + +|`spring.boot.version` +|The version of Spring Boot + +|`spring.version` +|The version of the core Spring Framework + +|`spring.beanFactory` +|Access to the Spring `BeanFactory` +|=== + + + +[[production-ready-remote-shell-plugins]] +==== Remote shell plugins +In addition to new commands, it is also possible to extend other CRaSH shell features. +All Spring Beans that extends `org.crsh.plugin.CRaSHPlugin` will be automatically +registered with the shell. + +For more information please refer to the http://www.crashub.org/[CRaSH reference +documentation]. + + + +[[production-ready-metrics]] +== Metrics +Spring Boot Actuator includes a metrics service with ``gauge'' and ``counter'' support. +A ``gauge'' records a single value; and a ``counter'' records a delta (an increment or +decrement). Metrics for all HTTP requests are automatically recorded, so if you hit the +`metrics` endpoint should should see a response similar to this: + +[source,json,indent=0] +---- + { + "counter.status.200.root": 20, + "counter.status.200.metrics": 3, + "counter.status.401.root": 4, + "gauge.response.root": 2, + "gauge.response.metrics": 3, + "mem": 466944, + "mem.free": 410117, + "processors": 8 + } +---- + +Here we can see basic `memory` and `processor` information along with some HTTP metrics. +In this instance the `root` (``/'') and `/metrics` URLs have returned `HTTP 200` responses +`20` and `3` times respectively. It also appears that the `root` URL returned `HTTP 401` +(unauthorized) `4` times. + +The `gauge` shows the last response time for a request. So the last request to `root` took +`2ms` to respond and the last to `/metrics` took `3ms`. + +NOTE: In this example we are actually accessing the endpoint over HTTP using the +`/metrics` URL, this explains why `metrics` appears in the response. + + + +[[production-ready-recording-metrics]] +=== Recording your own metrics +To record your own metrics inject a +{sc-spring-boot-actuator}/metrics/CounterService.{sc-ext}[`CounterService`] and/or +{sc-spring-boot-actuator}/metrics/GaugeService.{sc-ext}[`GaugeService`] into +your bean. The `CounterService` exposes `increment`, `decrement` and `reset` methods; the +`GaugeService` provides a `submit` method. + +Here is a simple example that counts the number of times that a method is invoked: + +[source,java,indent=0] +---- + import org.springframework.beans.factory.annotation.Autowired; + import org.springframework.boot.actuate.metrics.CounterService; + import org.springframework.stereotype.Service; + + @Service + public class MyService { + + private final CounterService counterService; + + @Autowired + public MyService(CounterService counterService) { + this.counterService = counterService; + } + + public void exampleMethod() { + this.counterService.increment("services.system.myservice.invoked"); + } + + } +---- + +TIP: You can use any string as a metric name but you following guidelines of your chosen +store/graphing technology. Some good guidelines for Graphite are available on +http://matt.aimonetti.net/posts/2013/06/26/practical-guide-to-graphite-monitoring/[Matt Aimonetti's Blog]. + + + +[[production-ready-metric-repositories]] +=== Metric repositories +Metric service implementations are usually bound to a +{sc-spring-boot-actuator}/metrics/repository/MetricRepository.{sc-ext}[`MetricRepository`]. +A `MetricRepository` is responsible for storing and retrieving metric information. Spring +Boot provides an `InMemoryMessageRespository` and a `RedisMetricRepository` out of the +box (the in-memory repository is the default) but you can also write your own. The +`MetricRepository` interface is actually composed of higher level `MetricReader` and +`MetricWriter` interfaces. For full details refer to the +{dc-spring-boot-actuator}/metrics/repository/MetricRepository.{dc-ext}[Javadoc]. + + + +[[production-ready-code-hale-metrics]] +=== Coda Hale Metrics +User of the http://metrics.codahale.com/[Coda Hale ``Metrics'' library] will automatically +find that Spring Boot metrics are published to `com.codahale.metrics.MetricRegistry`. A +default `com.codahale.metrics.MetricRegistry` Spring bean will be created when you declare +a dependency to the `com.codahale.metrics:metrics-core` library; you can also register you +own `@Bean` instance if you need customizations. + +Users can create Coda Hale metrics by prefixing their metric names with the appropriate +type (e.g. `histogram.*`, `meter.*`). + + + +[[production-ready-metrics-message-channel-integration]] +=== Message channel integration +If the ``Spring Messaging'' jar is on your classpath a `MessageChannel` called +`metricsChannel` is automatically created (unless one already exists). All metric update +events are additionally published as ``messages'' on that channel. Additional analysis or +actions can be taken by clients subscribing to that channel. + + + +[[production-ready-auditing]] +== Auditing +Spring Boot Actuator has a flexible audit framework that will publish events once Spring +Security is in play (``authentication success'', ``failure'' and ``access denied'' +exceptions by default). This can be very useful for reporting, and also to implement a +lock-out policy based on authentication failures. + +You can also choose to use the audit services for your own business events. To do that +you can either inject the existing `AuditEventRepository` into your own components and +use that directly, or you can simply publish `AuditApplicationEvent` via the Spring +`ApplicationEventPublisher` (using `ApplicationEventPublisherAware`). + + + +[[production-ready-tracing]] +== Tracing +Tracing is automatically enable for all HTTP requests. You can view the `trace` endpoint +and obtain basic information about the last few requests: + +[source,json,indent=0] +---- + [{ + "timestamp": 1394343677415, + "info": { + "method": "GET", + "path": "/trace", + "headers": { + "request": { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + "Connection": "keep-alive", + "Accept-Encoding": "gzip, deflate", + "User-Agent": "Mozilla/5.0 Gecko/Firefox", + "Accept-Language": "en-US,en;q=0.5", + "Cookie": "_ga=GA1.1.827067509.1390890128; ..." + "Authorization": "Basic ...", + "Host": "localhost:8080" + }, + "response": { + "Strict-Transport-Security": "max-age=31536000 ; includeSubDomains", + "X-Application-Context": "application:8080", + "Content-Type": "application/json;charset=UTF-8", + "status": "200" + } + } + } + },{ + "timestamp": 1394343684465, + ... + }] +---- + + + +[[production-ready-custom-tracing]] +=== Custom tracing +If you need to trace additional events you can inject a +{sc-spring-boot-actuator}/trace/TraceRepository.{sc-ext}[`TraceRepository`] into your +Spring Beans. The `add` method accepts a single `Map` structure that will be converted to +JSON and logged. + +By default an `InMemoryTraceRepository` will be used that stores the last 100 events. You +can define your own instance of the `InMemoryTraceRepository` bean if you need to expand +the capacity. You can also create your own alternative `TraceRepository` implementation +if needed. + + + +[[production-ready-error-handling]] +== Error Handling +Spring Boot Actuator provides an `/error` mapping by default that handles all errors in a +sensible way. If you want more specific error pages for some conditions, the embedded +servlet containers support a uniform Java DSL for customizing the error handling. + + + +[[production-ready-whats-next]] +== What to read next +If you want to explore some of the concepts discussed in this chapter, you can take a +look at the actuator {github-code}/spring-boot-samples[sample applications]. You also +might want to read about graphing tools such as http://graphite.wikidot.com/[Graphite]. + +Otherwise, you can continue on, to read about Spring Boot's +<>. diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-cli.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-cli.adoc new file mode 100644 index 00000000000..affd73db8ed --- /dev/null +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-cli.adoc @@ -0,0 +1,323 @@ +[[cli]] += Spring Boot CLI + +[partintro] +-- +The Spring Boot CLI is a command line tool that can be used if you want to quickly +prototype with Spring. It allows you to run Groovy scripts, which means that you have a +familiar Java-like syntax, without so much boilerplate code. +-- + + + +[[cli-installation]] +== Installing the CLI +The Spring Boot CLI can be installed manually; using GVM (the Groovy Environment +Manually) or using Homebrew if you are an OSX user. See +``<>'' +in the ``Getting started'' section for comprehensive installation instructions. + + + +[[cli-using-the-cli]] +== Using the CLI +Once you have installed the CLI you can run it by typing `spring`. If you run `spring` +without any arguments, a simple help screen is displayed: + +[indent=0,subs="verbatim,quotes,attributes"] +---- + $ spring + usage: spring [--help] [--version] + [] + + Available commands are: + + run [options] [--] [args] + Run a spring groovy script + + _... more command help is shown here_ +---- + +You can use `help` to get more details about any of the supported commands. For example: + +[indent=0] +---- + $ spring help run + spring run - Run a spring groovy script + + usage: spring run [options] [--] [args] + + Option Description + ------ ----------- + --autoconfigure [Boolean] Add autoconfigure compiler + transformations (default: true) + --classpath, -cp Additional classpath entries + -e, --edit Open the file with the default system + editor + --no-guess-dependencies Do not attempt to guess dependencies + --no-guess-imports Do not attempt to guess imports + -q, --quiet Quiet logging + -v, --verbose Verbose logging of dependency + resolution + --watch Watch the specified file for changes +---- + +The `version` command provides a quick way to check which version of Spring Boot you are +using. + +[indent=0,subs="verbatim,quotes,attributes"] +---- + $ spring version + Spring CLI v{spring-boot-version} +---- + + + +[[cli-run]] +=== Running applications using the CLI +You can compile and run Groovy source code using the `run` command. The Spring Boot CLI +is completely self contained so you don't need any external Groovy installation. + +Here is an example ``hello world'' web application written in Groovy: + +[source,groovy,indent=0,subs="verbatim,quotes,attributes"] +---- + @Controller + class WebApplication { + + @RequestMapping("/") + @ResponseBody + String home() { + return "Hello World!" + } + + } +---- + + + +[[cli-deduced-grab-annotations]] +==== Deduced ``grab'' dependencies +Standard Groovy includes a `@Grab` annotation which allows you to declare dependencies +on a third-party libraries. This useful technique allows Groovy to download jars in the +same way as Maven or Gradle would; but without requiring you to use a build tool. + +Spring Boot extends this technique further, and will attempt to deduce which libraries +to ``grab'' based on your code. For example, since the `WebApplication` code above uses +`@Controller` annotations, ``Tomcat'' and ``Spring MVC'' will be grabbed. + +The following items are used as ``grab hints'': + +|=== +| Items | Grabs + +|`JdbcTemplate`, `NamedParameterJdbcTemplate`, `DataSource` +|JDBC Application. + +|`@EnableJmsMessaging` +|JMS Application. + +|`@Test` +|JUnit. + +|`@EnableRabbitMessaging` +|RabbitMQ. + +|`@EnableReactor` +|Project Reactor. + +|extends `Specification` +|Spock test. + +|`@EnableBatchProcessing` +|Spring Batch. + +|`@MessageEndpoint` `@EnableIntegrationPatterns` +|Spring Integration. + +|`@EnableDeviceResolver` +|Spring Mobile. + +|`@Controller` `@RestController` `@EnableWebMvc` +|Spring MVC + Embedded Tomcat. + +|`@EnableWebSecurity` +|Spring Security. + +|`@EnableTransactionManagement` +|Spring Transaction Management. +|=== + +TIP: See subclasses of +{sc-spring-boot-cli}/compiler/CompilerAutoConfiguration.{sc-ext}[`CompilerAutoConfiguration`] +in the Spring Boot CLI source code to understand exactly how customizations are applied. + + + +[[cli-default-import-statements]] +==== Default import statements +To help reduce the size of your Groovy code, several `import` statements are +automatically included. Notice how the example above refers to `@Component`, +`@Controller`, `@RequestMapping` and `@ResponseBody` without needing to use +fully-qualified names or `import` statements. + +TIP: Many Spring annotations will work without using `import` statements. Try running +your application to see what fails before adding imports. + + + +[[cli-automatic-main-method]] +==== Automatic main method +Unlike the equilvement Java application, you do not need to include a +`public static void main(String[] args)` method with your `Groovy` scripts. A +`SpringApplication` is automatically created, with your compiled code acting as the +`source`. + + + +[[cli-testing]] +=== Testing your code +The `test` command allows you to compile and run tests for your application. Typical +usage looks like this: + +[indent=0] +---- + $ spring test app.groovy tests.groovy + Total: 1, Success: 1, : Failures: 0 + Passed? true +---- + +In this example, `tests.groovy` contains JUnit `@Test` methods or Spock `Specification` +classes. All the common framework annotations and static methods should be available to +you without having to `import` them. + +Here is the `test.groovy` file that we used above: + +[source,groovy,indent=0] +---- + class ApplicationTests { + + @Test + void homeSaysHello() { + assertEquals("Hello World", new WebApplication().home()) + } + + } +---- + +TIP: If you have more than one test source files, you might prefer to organize them +into a `test` directory. + + + +[[cli-multiple-source-files]] +=== Applications with multiple source files +You can use ``shell globbing'' with all commands that accept file input. This allows you +to easily use multiple files from a single directory, e.g. + +[indent=0] +---- + $ spring run *.groovy +---- + +This technique can also be useful if you want to segregate your ``test'' or ``spec'' code +from the main application code: + +[indent=0] +---- + $ spring test app/*.groovy test/*.groovy +---- + + + +[[cli-jar]] +=== Packaging your application +You can use the `jar` command to package your application into a self-contained +executable jar file. For example: + +[indent=0] +---- + $ spring jar my-app.jar *.groovy +---- + +The resulting jar will contain the classes produced by compiling the application and all +of the application's dependencies so that it can then be run using `java -jar`. The jar +file will also contain entries from the application's classpath. + +See the output of `spring help jar` for more information. + + + +[[cli-shell]] +=== Using the embedded shell +Spring Boot includes command-line completion scripts for BASH and zsh shells. If you +don't use either of these shells (perhaps you are a Windows user) then you can use the +`shell` command to launch an integrated shell. + +[indent=0,subs="verbatim,quotes,attributes"] +---- + $ spring shell + *Spring Boot* (v{spring-boot-version}) + Hit TAB to complete. Type \'help' and hit RETURN for help, and \'exit' to quit. +---- + +From inside the embedded shell you can run other commands directly: + +[indent=0,subs="verbatim,quotes,attributes"] +---- + $ version + Spring CLI v{spring-boot-version} +---- + +The embedded shell supports ANSI color output as well as `tab` completion. If you need +to run a native command you can use the `$` prefix. Hitting `ctrl-c` will exit the +embedded shell. + +[[cli-groovy-beans-dsl]] +== Developing application with the Groovy beans DSL +Spring Framework 4.0 has native support for a `beans{}` ``DSL'' (borrowed from +http://grails.org/[Grails]), and you can embed bean definitions in your Groovy +application scripts using the same format. This is sometimes a good way to include +external features like middleware declarations. For example: + +[source,groovy,indent=0] +---- + @Configuration + class Application implements CommandLineRunner { + + @Autowired + SharedService service + + @Override + void run(String... args) { + println service.message + } + + } + + import my.company.SharedService + + beans { + service(SharedService) { + message "Hello World" + } + } +---- + +You can mix class declarations with `beans{}` in the same file as long as they stay at +the top level, or you can put the beans DSL in a separate file if you prefer. + + + +[[cli-whats-next]] +== What to read next +There are some {github-code}/spring-boot-cli/samples[sample groovy +scripts] available from the GitHub repository that you can use to try out the +Spring Boot CLI. There is also extensive javadoc throughout the +{sc-spring-boot-cli}[source code]. + +If you find that you reach the limit of the CLI tool, you will probably want to look +at converting your application to full Gradle or Maven built ``groovy project''. The +next section covers Spring Boot's +``<>'' that you can +use with Gradle or Maven. diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc new file mode 100644 index 00000000000..5dfc7790d55 --- /dev/null +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -0,0 +1,1611 @@ +[[boot-features]] += Spring Boot features + +[partintro] +-- +This section dives into the details of Spring Boot. Here you can learn about the key +features that you will want to use and customize. If you haven't already, you might want +to read the ``<>'' and +``<>'' sections so that you have a good grounding +of the basics. +-- + + + +[[boot-features-spring-application]] +== SpringApplication +The `SpringApplication` class provides a convenient way to bootstrap a Spring application +that will be started from a `main()` method. In many situations you can just delegate to +the static `SpringApplication.run` method: + +[source,java,indent=0] +---- + public static void main(String[] args) { + SpringApplication.run(MySpringConfiguration.class, args); + } +---- + +When you application starts you should see something similar to the following: + +[indent=0,subs="attributes"] +---- + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: v{spring-boot-version} + +2013-07-31 00:08:16.117 INFO 56603 --- [ main] o.s.b.s.app.SampleApplication : Starting SampleApplication v0.1.0 on mycomputer with PID 56603 (/apps/myapp.jar started by pwebb) +2013-07-31 00:08:16.166 INFO 56603 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@6e5a8246: startup date [Wed Jul 31 00:08:16 PDT 2013]; root of context hierarchy +2014-03-04 13:09:54.912 INFO 41370 --- [ main] .t.TomcatEmbeddedServletContainerFactory : Server initialized with port: 8080 +2014-03-04 13:09:56.501 INFO 41370 --- [ main] o.s.b.s.app.SampleApplication : Started SampleApplication in 2.992 seconds (JVM running for 3.658) +---- + +By default `INFO` logging messages will shown, including some relevant startup details +such as the user that launched the application. + + + +[[boot-features-customizing-spring-application]] +=== Customizing SpringApplication +If the `SpringApplication` defaults aren't to your taste you can instead create a local +instance and customize it. For example, to turn off the banner you would write: + +[source,java,indent=0] +---- + public static void main(String[] args) { + SpringApplication app = new SpringApplication(MySpringConfiguration.class); + app.setShowBanner(false); + app.run(args); + } +---- + +NOTE: The constructor arguments passed to `SpringApplication` are configuration sources +for spring beans. In most cases these will be references to `@Configuration` classes, but +they could also be references to XML configuration or to packages that should be scanned. + +It is also possible to configure the `SpringApplication` using an `application.properties` +file. See ``<>'' for details. + +For a complete list of the configuration options, see the +{dc-spring-boot}/SpringApplication.{dc-ext}[`SpringApplication` Javadoc]. + + + +[[boot-features-fluent-builder-api]] +=== Fluent builder API +If you need to build an `ApplicationContext` hierarchy (multiple contexts with a +parent/child relationship), or if you just prefer using a ``fluent'' builder API, you +can use the `SpringApplicationBuilder`. + +The `SpringApplicationBuilder` allows you to chain together multiple method calls, and +includes `parent` and `child` methods that allow you to create a hierarchy. + +For example: +[source,java,indent=0] +---- + new SpringApplicationBuilder() + .showBanner(false) + .sources(Parent.class) + .child(Application.class) + .run(args); +---- + +NOTE: There are some restrictions when creating an `ApplicationContext` hierarchy, e.g. +the parent application context is *not* a `WebApplicationContext`. Both parent and child +are executed with the same `Environment` constructed in the usual way to include command +line arguments. Any `ServletContextAware` components all have to go in the child +context, otherwise there is no way for Spring Boot to create the `ServletContext` in time. + + + +[[boot-features-application-events-and-listeners]] +=== Application events and listeners +In addition to the usual Spring Framework events, such as `ContextRefreshedEvent`, a +`SpringApplication` sends some additional application events. Some events are actually +triggered before the `ApplicationContext` is created. + +You can register event listeners in a number of ways, the most common being +`SpringApplication.addListeners(...)` method. + +Application events are sent in the following order, as your application runs: + +. An `ApplicationStartedEvent` is sent at the start of a run, but before any + processing except the registration of listeners and initializers. +. An `ApplicationEnvironmentPreparedEvent` is sent when the `Environment` to be used in + the context is known, but before the context is created. +. An `ApplicationPreparedEvent` is sent just before the refresh is started, but after bean + definitions have been loaded. +. An `ApplicationFailedEvent` is sent if there is an exception on startup. + +TIP: You often won't need to use application events, but it can be handy to know that they +exist. Internally, Spring Boot uses events to handle a variety of tasks. + + + +[[boot-features-web-environment]] +=== Web environment +A `SpringApplication` will attempt to create the right type of `ApplicationContext` on +your behalf. By default, an `AnnotationConfigApplicationContext` or +`AnnotationConfigEmbeddedWebApplicationContext` will be used, depending on whether you +are developing a web application or not. + +The algorithm used to determine a ``web environment'' is fairly simplistic (based on the +presence of a few classes). You can use `setWebEnvironment(boolean webEnvironment)` if +you need to override the default. + +It is also possible to take complete control of the `ApplicationContext` type that will +be used by calling `setApplicationContextClass(...)`. + +TIP: It is often desirable call `setWebEnvironment(false)` when using `SpringApplication` +within a JUnit test. + + + +[[boot-features-command-line-runner]] +=== Using the CommandLineRunner +If you want access to the raw command line arguments, or you need to run some specific code +once the `SpringApplication` has started you can implement the `CommandLineRunner` +interface. The `run(String... args)` method will be called on all spring beans +implementing this interface. + +[source,java,indent=0] +---- + import org.springframework.boot.* + import org.springframework.stereotype.* + + @Component + public class MyBean implements CommandLineRunner { + + public void run(String... args) { + // Do something... + } + + } +---- + +You can additionally implement the `org.springframework.core.Ordered` interface or use the +`org.springframework.core.annotation.Order` annotation if several `CommandLineRunner` +beans are defined that must be called in a specific order. + + + +[[boot-features-application-exit]] +=== Application exit +Each `SpringApplication` will register a shutdown hook with the JVM to ensure that the +`ApplicationContext` is closed gracefully on exit. All the standard Spring lifecycle +callbacks (such as the `DisposableBean` interface, or the `@PreDestroy` annotation) can +be used. + +In addition, beans may implement the `org.springframework.boot.ExitCodeGenerator` +interface if they wish to return a specific exit code when the application ends. + + + +[[boot-features-external-config]] +== Externalized Configuration +Spring Boot likes you to externalize your configuration so you can work with the same +application code in different environments. You can use properties files, YAML files, +environment variables and command-line arguments to externalize configuration. Property +values can be injected directly into your beans using the `@Value` annotation, accessed +via Spring's `Environment` abstraction or bound to structured objects. + +Spring Boot uses a very particular `PropertySource` order that is designed to allow +sensible overriding of values, properties are considered in the the following order: + +. Command line arguments. +. Java System properties (`System.getProperties()`). +. OS environment variables. +. `@PropertySource` annotations on your `@Configuration` classes. +. Application properties outside of your packaged jar (`application.properties` + including YAML and profile variants). +. Application properties packaged inside your jar (`application.properties` + including YAML and profile variants). +. Default properties (specified using `SpringApplication.setDefaultProperties`). + +To provide a concrete example, suppose you develop a `@Component` that uses a +`name` property: + +[source,java,indent=0] +---- + import org.springframework.stereotype.* + import org.springframework.beans.factory.annotation.* + + @Component + public class MyBean { + + @Value("${name}") + private String name; + + // ... + + } +---- + +You can bundle an `application.properties` inside your jar that provides a sensible +default `name`. When running in production, an `application.properties` can be provided +outside of your jar that overrides `name`; and for one off testing, you can launch with +a specific command line switch (e.g. `java -jar app.jar --name="Spring"`). + + + +[[boot-features-external-config-command-line-args]] +=== Accessing command line properties +By default SpringApplication will convert any command line option arguments (starting +with ``--'', e.g. `--server.port=9000`) to a `property` and add it to the Spring +`Environment`. As mentioned above, command line properties always take precedence over +other property sources. + +If you don't want command line properties to be added to the `Environment` you can disable +them using `SpringApplication.setAddCommandLineProperties(false)`. + + + +[[boot-features-external-config-application-property-files]] +=== Application property files +`SpringApplication` will load properties from `application.properties` files in the +following locations and add them to the Spring `Environment`: + +. The current directory +. A `/config` subdir of the current directory. +. The classpath root +. A classpath `/config` package + +The list is ordered by precedence (locations higher in the list override lower items). + +NOTE: You can also use YAML ('.yml') files as an alternative to '.properties' (see below) + +If you don't like `application.properties` as the configuration file name you can switch +to another by specifying a `spring.config.name` environment property. You can also refer +to an explicit location using the `spring.config.location` environment property. + +[indent=0] +---- + $ java -jar myproject.jar --spring.config.name=myproject +---- + + + +[[boot-features-external-config-profile-specific-properties]] +=== Profile specific properties +In addition to `application.properties` files, profile specific properties can also be +defined using the naming convention `application-{profile}.properties`. + +Profile specific properties are loaded from the same locations as standard +`application.properties`, with profiles specific files overriding the default ones. + + + +[[boot-features-external-config-placeholders-in-properties]] +=== Placeholders in properties +The values in `application.properties` are filtered through the existing `Environment` +when they are used so you can refer back to previously defined values (e.g. from System +properties). + +[indent=0] +---- + app.name: MyApp + app.description: ${app.name} is a Spring Boot application +---- + +TIP: You can also use this technique to create ``short'' variants of existing Spring Boot +properties. + + + +[[boot-features-external-config-yaml]] +=== Using YAML instead of Properties +http://yaml.org[YAML] is a superset of JSON, and as such is a very convenient format +for specifying hierarchical configuration data. The `SpringApplication` class will +automatically support YAML as an alternative to properties whenever you have the +http://code.google.com/p/snakeyaml/[SnakeYAML] library on your classpath. + +NOTE: If you use ``starter POMs'' SnakeYAML will be automatically provided via +`spring-boot-starter`. + + + +[[boot-features-external-config-loading-yaml]] +==== Loading YAML +Spring Boot provides two convenient classes that can be used to load YAML documents. The +`YamlPropertiesFactoryBean` will load YAML as `Properties` and the `YamlMapFactoryBean` +will load YAML as a `Map`. + +For example, the following YAML document: + +[source,yaml,indent=0] +---- + dev: + url: http://dev.bar.com + name: Developer Setup + prod: + url: http://foo.bar.com + name: My Cool App +---- + +Would be transformed into these properties: + +[indent=0] +---- + environments.dev.url=http://dev.bar.com + environments.dev.name=Developer Setup + environments.prod.url=http://foo.bar.com + environments.prod.name=My Cool App +---- + +YAML lists are represented as comma-separated values (useful for simple String values) +and also as property keys with `[index]` dereferencers, for example this YAML: + +[source,yaml,indent=0] +---- + servers: + - dev.bar.com + - foo.bar.com +---- + +Would be transformed into these properties: + +[indent=0] +---- + servers=dev.bar.com,foo.bar.com + servers[0]=dev.bar.com + servers[1]=foo.bar.com +---- + + + +[[boot-features-external-config-exposing-yaml-to-spring]] +==== Exposing YAML as properties in the Spring Environment +The `YamlPropertySourceLoader` class can be used to expose YAML as a `PropertySource` +in the Spring `Environment`. This allows you to use the familiar `@Value` annotation with +placeholders syntax to access YAML properties. + + + +[[boot-features-external-config-multi-profile-yaml]] +==== Multi-profile YAML documents +You can specify multiple profile-specific YAML document in a single file by +by using a `spring.profiles` key to indicate when the document applies. For example: + +[source,yaml,indent=0] +---- + server: + address: 192.168.1.100 + --- + spring: + profiles: production + server: + address: 192.168.1.120 +---- + + + +[[boot-features-external-config-yaml-shortcomings]] +==== YAML shortcomings +YAML files can't be loaded via the `@PropertySource` annotation. So in the +case that you need to load values that way, you need to use a properties file. + + + +[[boot-features-external-config-typesafe-configuration-properties]] +=== Typesafe Configuration Properties +Using the `@Value("${property}")` annotation to inject configuration properties can +sometimes be cumbersome, especially if you are working with multiple properties or +your data is hierarchical in nature. Spring Boot provides an alternative method +of working with properties that allows strongly typed beans to govern and validate +the configuration of your application. For example: + +[source,java,indent=0] +---- + @Component + @ConfigurationProperties(name="connection") + public class ConnectionSettings { + + private String username; + + private InetAddress remoteAddress; + + // ... getters and setters + + } +---- + +When the `@EnableConfigurationProperties` annotation is applied to your `@Configuration`, +any beans annotated with `@ConfigurationProperties` will be automatically configured +from the `Environment` properties. This style of configuration works particularly well +with the `SpringApplication` external YAML configuration: + +[source,yaml,indent=0] +---- + # application.yml + + connection: + username: admin + remoteAddress: 192.168.1.1 + + # additional configuration as required +---- + +To work with `@ConfigurationProperties` beans you can just inject them in the same way +as any other bean. + +[source,java,indent=0] +---- + @Service + public class MyService { + + @Autowired + private ConnectionSettings connection; + + //... + + @PostConstruct + public void openConnection() { + Server server = new Server(); + this.connection.configure(server); + } + + } +---- + +It is also possible to shortcut the registration of `@ConfigurationProperties` bean +definitions by simply listing the properties classes directly in the +`@EnableConfigurationProperties` annotation: + +[source,java,indent=0] +---- + @Configuration + @EnableConfigurationProperties(ConnectionSettings.class) + public class MyConfiguration { + } +---- + + + +[[boot-features-external-config-relaxed-binding]] +==== Relaxed binding +Spring Boot uses some relaxed rules for binding `Environment` properties to +`@ConfigurationProperties` beans, so there doesn't need to be an exact match between +the `Environment` property name and the bean property name. Common examples where this +is useful include underscore separated (e.g. `context_path` binds to `contextPath`), and +capitalized (e.g. `PORT` binds to `port`) environment properties. + +Spring will attempt to coerce the external application properties to the right type when +it binds to the `@ConfigurationProperties` beans. If you need custom type conversion you +can provide a `ConversionService` bean (with bean id `conversionService`) or custom +property editors (via a `CustomEditorConfigurer` bean). + + + +[[boot-features-external-config-validation]] +==== @ConfigurationProperties Validation +Spring Boot will attempt to validate external configuration, by default using JSR-303 +(if it is on the classpath). You can simply add JSR-303 `javax.valididation` constraint +annotations to your `@ConfigurationProperties` class: + +[source,java,indent=0] +---- + @Component + @ConfigurationProperties(name="connection") + public class ConnectionSettings { + + @NotNull + private InetAddress remoteAddress; + + // ... getters and setters + + } +---- + +You can also add a custom Spring `Validator` by creating a bean definition called +`configurationPropertiesValidator`. + +TIP: The `spring-boot-actuator` module includes an endpoint that exposes all +`@ConfigurationProperties` beans. Simply point your web browser to `/configprops` +or use the equivalent JMX endpoint. See the +``<>''. +section for details. + + +[[boot-features-profiles]] +== Profiles +Spring Profiles provide a way to segregate parts of your application configuration and +make it only available in certain environments. Any `@Component` or `@Configuration` can +be marked with `@Profile` to limit when it is loaded: + +[source,java,indent=0] +---- + @Configuration + @Profile("production") + public class ProductionConfiguraiton { + + // ... + + } +---- + +Spring Boot takes this a stage further, in that you can use a `spring.profiles.active` +`Environment` property to specify which profiles are active. You can specify the property +in any of the usual ways, for example you could include it in your +`application.properties`: + +[indent=0] +---- + spring.profiles.active=dev,hsqldb +---- + +or specify on the command line using the switch `--spring.profiles.active=dev,hsqldb`. + + + +[[boot-features-adding-active-profiles]] +=== Adding active profiles +The `spring.profiles.active` property follows the same ordering rules as other +properties, the highest `PropertySource` will win. This means that you can specify +active profiles in `application.properties` then *replace* them using the command line +switch. + +Sometimes it is useful to have profile specific properties that *add* to the active +profiles rather than replace them. The `+` prefix can be used to add active profiles. + +For example, when an application with following properties is run using the switch +`--spring.profiles.active=prod` the `proddb` and `prodmq` profiles will also be activated: + +[source,yaml,indent=0] +---- + --- + my.property: fromyamlfile + --- + spring.profiles: prod + spring.profiles.active: +proddb,+prodmq +---- + + + +[[boot-features-programmatically-setting-profiles]] +=== Programmatically setting profiles +You can programmatically set active profiles by calling +`SpringApplication.setAdditionalProfiles(...)` before your application runs. It is also +possible to activate profiles using Spring's `ConfigurableEnvironment` interface. + + + +[[boot-features-profile-specific-configuration]] +=== Profile specific configuration files +Profile specific variants of both `application.properties` (or `application.yml`) and +files referenced via `@ConfigurationProperties` are considered as files are loaded. +See ``<>'' for details. + + + +[[boot-features-logging]] +== Logging +Spring Boot uses http://commons.apache.org/logging[Commons Logging] for all internal +logging, but leaves the underlying log implementation open. Default configurations are +provided for +http://docs.oracle.com/javase/7/docs/api/java/util/logging/package-summary.html[Java Util Logging], +http://logging.apache.org/log4j/[Log4J] and +http://logback.qos.ch/[Logback]. +In each case there is console output and file output (rotating, 10 Mb file size). + +By default, If you use the ``Starter POMs'', Logback will be used for logging. Appropriate +Logback routing is also included to ensure that dependent libraries that use +Java Util Logging, Commons Logging, Log4J or SLF4J will all work correctly. + +TIP: There are a lot of logging frameworks available for Java. Don't worry if the above +list seems confusing, generally you won't need to change your logging dependencues and +the Spring Boot defaults will work just fine. + + + +[[boot-features-logging-format]] +=== Log format +The default log output from Spring Boot looks like this: + +[indent=0] +---- +2014-03-05 10:57:51.112 INFO 45469 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/7.0.52 +2014-03-05 10:57:51.253 INFO 45469 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2014-03-05 10:57:51.253 INFO 45469 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1358 ms +2014-03-05 10:57:51.698 INFO 45469 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/] +2014-03-05 10:57:51.702 INFO 45469 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] +---- + +The following items are output: + +* Date and Time -- Millesecond precision and easily sortable. +* Log Level -- `ERROR`, `WARN`, `INFO`, `DEBUG` or `TRACE`. +* Process ID. +* A `---` separator to distinguish the start of actual log messages. +* Logger name -- This is usually the source class name (often abbreviated). +* The log message. + + + +[[boot-features-logging-console-output]] +=== Console output +The default log configuration will echo messages to the console as they written. By +default `ERROR`, `WARN` and `INFO` level messages are logged. To also log `DEBUG` level +messages to the console you can start your application with a `--debug` flag. + +[indent=0] +---- + $ java -jar myapp.jar --debug +---- + +If your terminal supports ANSI, color output will be used to aid readability. + + + +[[boot-features-logging-file-output]] +=== File output +By default, log files are written to `spring.log` in your `temp` directory and rotate at +10 Mb. You can easily customize the output folder by setting the `logging.path` property +(for example in your `application.properties`). It is also possible to change the filename +using a `logging.file` property. + +As with console output, `ERROR`, `WARN` and `INFO` level messages are logged by default. + + + +[[boot-features-custom-log-configuration]] +=== Custom log configuration + +The various logging systems can be activated by including the appropriate libraries on +the classpath, and further customized by providing a suitable configuration file in the +root of the classpath, or in a location specified by the Spring `Environment` property +`logging.config`. + +Depending on your logging system, the following files will be loaded: + +|=== +|Logging System |Customization + +|Logback +|`logback.xml` + +|Log4j +|`log4j.properties` or `log4j.xml` + +|JDK (Java Util Logging) +|`logging.properties` +|=== + +To help with the customization some other properties are transferred from the Spring +`Environment` to System properties: + +|=== +|Spring Environment |System Property |Comments + +|`logging.file` +|`LOG_FILE` +|Used in default log configuration if defined. + +|`logging.path` +|`LOG_PATH` +|Used in default log configuration if defined. + +|`PID` +|`PID` +|The current process ID is discovered if possible and not already provided. +|=== + +All the logging systems supported can consult System properties when parsing their +configuration files. See the default configurations in `spring-boot.jar` for examples. + +WARNING: There are know classloading issues with Java Util Logging that cause problems +when running from an ``executable jar''. We recommend that you avoid it if at all +possible. + + + +[[boot-features-developing-web-applications]] +== Developing web applications +Spring Boot is well suited for web application development. You can easily create a +self-contained HTTP server using embedded Tomcat or Jetty. Most web applications will +use the `spring-boot-starter-web` module to get up and running quickly. + +If you haven't yet developed a Spring Boot web application you can follow the +"Hello World!" example in the +``<>'' section. + + + +[[boot-features-spring-mvc]] +=== The ``Spring Web MVC framework'' +The Spring Web MVC framework (often referred to as simply ``Spring MVC'') is a rich +``model view controller'' web framework. Spring MVC lets you create special `@Controller` +or `@RestController` beans to handle incoming HTTP requests. Methods in your controller +are mapped to HTTP using `@RequestMapping` annotations. + +Here is a typical example `@RestController` to serve JSON data: + +[source,java,indent=0] +---- + @RestController + @RequestMapping(value="/users") + public class MyRestController { + + @RequestMapping(value="/{user}", method=RequestMethod.GET) + public User getUser(@PathVariable Long user) { + // ... + } + + @RequestMapping(value="/{user}/customers", method=RequestMethod.GET) + List getUserCustomers(@PathVariable Long user) { + // ... + } + + @RequestMapping(value="/{user}", method=RequestMethod.DELETE) + public User deleteUser(@PathVariable Long user) { + // ... + } + + } +---- + +Spring MVC is part of the core Spring Framework and detailed information is available in +the {spring-reference}#mvc[reference documentation]. There are also several guides +available at http://spring.io/guides that cover Spring MVC. + + + +[[boot-features-spring-mvc-auto-configuration]] +==== Spring MVC auto-configuration +Spring Boot provides auto-configuration for Spring MVC that works well with most +applications. If you want to take complete control of Spring MVC you can add your +own `@Configuration` annotated with `@EnableWebMvc`. + +The auto-configuration adds the following features on top of Spring's defaults: + +* Inclusion of `ContentNegotiatingViewResolver` and `BeanNameViewResolver` beans. +* Support for serving static resources, including support for WebJars (see below). +* Automatic registration of `Converter`, `GenericConverter`, `Formatter` beans. +* Support for `HttpMessageConverters` (see below). +* Static `index.html` support. +* Custom `Favicon` support. + + + +[[boot-features-spring-mvc-message-converters]] +==== HttpMessageConverters +Spring MVC uses the `HttpMessageConverter` interface to convert HTTP requests and +responses. Sensible defaults are included out of the box, for example Objects can be +automatically converted to JSON (using the Jackson library) or XML (using JAXB). + +If you need to add or customize converters you can use Spring Boot's +`HttpMessageConverters` class: +[source,java,indent=0] +---- + import org.springframework.boot.autoconfigure.web.HttpMessageConverters; + import org.springframework.context.annotation.*; + import org.springframework.http.converter.*; + + @Configuration + public class MyConfiguration { + + @Bean + public HttpMessageConverters customConverters() { + HttpMessageConverter additional = ... + HttpMessageConverter another = ... + return new HttpMessageConverters(additional, another); + } + + } +---- + + + +[[boot-features-spring-mvc-static-content]] +==== Static Content +By default Spring Boot will serve static content from a folder called `/static` (or +`/public` or `/resources` or `/META-INF/resources`) in the classpath or from the root +of the `ServeltContext`. It uses the `ResourceHttpRequestHandler` from Spring MVC so you +can modify that behavior by adding your own `WebMvcConfigurerAdapter` and overriding the +`addResourceHandlers` method. + +In a stand-alone web application the default servlet from the container is also +enabled, and acts as a fallback, serving content from the root of the `ServletContext` if +Spring decides not to handle it. Most of the time this will not happen (unless you modify +the default MVC configuration) because Spring will always be able to handle requests +through the `DispatcherServlet`. + +In addition to the ``standard'' static resource locations above, a special case is made for +http://www.webjars.org/[Webjars content]. Any resources with a path in `/webjars/**` will +be served from jar files if they are packaged in the Webjars format. + +TIP: Do not use the `src/main/webapp` folder if your application will be packaged as a +jar. Although this folder is a common standard, it will *only* work with war packaging +and it will be silently ignored by most build tools if you generate a jar. + + + +[[boot-features-spring-mvc-template-engines]] +==== Template engines +As well as REST web services, you can also use Spring MVC to serve dynamic HTML content. +Spring MVC supports a variety of templating technologies including: velocity, freemarker, +and JSPs. Many other templating engines also ship their own Spring MVC integrations. + +Spring Boot includes auto-configuration support for the Thymeleaf templating engine. +Thymeleaf is an XML/XHTML/HTML5 template engine that can work both in web and non-web +environments. If allows you to create natural templates, that can be correctly displayed +by browsers and therefore work also as static prototypes. Thymeleaf templates will be +picked up automatically from `src/main/resources/templates`. + +TIP: JSPs should be avoided if possible, there are several +<> when using them with embedded +servlet containers. + + + +[[boot-features-embedded-container]] +=== Embedded servlet container support +Spring Boot includes support for embedded Tomcat and Jetty servers. Most developers will +simply use the appropriate ``Starter POM'' to obtain a fully configured instance. By +default both Tomcat and Jetty will listen for HTTP requests on port `8080`. + + + +[[boot-features-embedded-container-servlets-and-filters]] +==== Servlets and Filters +When using an embedded servlet container you can register Servlets and Filters directly as +Spring beans. This can be particularly convenient if you want to refer to a value from +your `application.properties` during configuration. + +By default, if the context contains only a single Servlet it will be mapped to `/`. In +the case of multiple Servlets beans the bean name will be used as a path prefix. Filters +will map to `/*`. + +If convention based mapping is not flexible enough you can use the +`ServletRegistrationBean` and `FilterRegistrationBean` classes for complete control. You +can also register items directly if your bean implements the `ServletContextInitializer` +interface. + + + +[[boot-features-embedded-container-application-context]] +==== The EmbeddedWebApplicationContext +Under the hood Spring Boot uses a new type of `ApplicationContext` for embedded +servlet container support. The `EmbeddedWebApplicationContext` is a special +type of `WebApplicationContext` that bootstraps itself by searching for a single +`EmbeddedServletContainerFactory` bean. Usually a `TomcatEmbeddedServletContainerFactory` +or `JettyEmbeddedServletContainerFactory` will have been auto-configured. + +NOTE: You usually won't need to be aware of these implementation classes. Most +applications will be auto-configured and the appropriate `ApplicationContext` and +`EmbeddedServletContainerFactory` will be created on your behalf. + + + +[[boot-features-customizing-embedded-containers]] +==== Customizing embedded servlet containers +Common servlet container settings can be configured using Spring `Environment` +properties. Usually you would define the properties in your `application.properties` +file. + +Common server settings include: + +* `server.port` -- The listen port for incoming HTTP requests. +* `server.address` -- The interface address to bind to. +* `server.sessionTimeout` -- A session timeout. + +See the {sc-spring-boot-autoconfigure}/web/ServerProperties.{sc-ext}[`ServerProperties`] +class for a complete list. + + + +[[boot-features-programmatic-embedded-container-customization]] +===== Programmatic customization +If you need to configure your embdedded servlet container programmatically you can register +a Spring bean that implements the `EmbeddedServletContainerCustomizer` interface. +`EmbeddedServletContainerCustomizer` provides access to the +`ConfigurableEmbeddedServletContainerFactory` which includes numerous customization +setter methods. + +[source,java,indent=0] +---- + import org.springframework.boot.context.embedded.*; + import org.springframework.stereotype.Component; + + @Component + public class CustomizationBean implements EmbeddedServletContainerCustomizer { + + @Override + public void customize(ConfigurableEmbeddedServletContainer container) { + container.setPort(9000); + } + + } +---- + + + +[[boot-features-customizing-configurableembeddedservletcontainerfactory-directly]] +===== Customizing ConfigurableEmbeddedServletContainerFactory directly +If the above customization techniques are too limited, you can register the +`TomcatEmbeddedServletContainerFactory` or `JettyEmbeddedServletContainerFactory` bean +yourself. + +[source,java,indent=0] +---- + @Bean + public EmbeddedServletContainerFactory servletContainer() { + TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory(); + factory.setPort(9000); + factory.setSessionTimeout(10, TimeUnit.MINUTES); + factory.addErrorPages(new ErrorPage(HttpStatus.404, "/notfound.html"); + return factory; + } +---- + +Setters are provided for many configuration options. Several protected method +``hooks'' are also provided should you need to do something more exotic. See the +source code documentation for details. + + + +[[boot-features-jsp-limitations]] +==== JSP limitations +When running a Spring Boot application that uses an embedded servlet container (and is +packaged as an executable archive), there are some limitations in the JSP support. + +* With Tomcat it should work if you use war packaging, i.e. an executable war will work, + and will also be deployable to a standard container (not limited to, but including + Tomcat). An executable jar will not work because of a hard coded file pattern in Tomcat. + +* Jetty does not currently work as an embedded container with JSPs. + +There is a {github-code}/spring-boot-samples/spring-boot-sample-web-jsp[JSP sample] so +you can see how to set things up. + + + +[[boot-features-sql]] +== Working with SQL databases +The Spring Framework provides extensive support for working with SQL databases. From +direct JDBC access using `JdbcTemplate` though to complete ``object relational mapping'' +technologies such as Hibernate. Spring Data provides an additional level of functionality, +creating `Repoistory` implementations directly from interfaces and using conventions to +generate queries from your method names. + + + +[[boot-features-configure-datasource]] +=== Configure a DataSource +Java's `javax.sql.DataSource` interface provides a standard method of working with +database connections. Traditionally a DataSource uses a `URL` along with some +credentials to establish a database connection. + + + +[[boot-features-embedded-database-support]] +==== Embedded Database Support +It's often convenient develop applications using an in-memory embedded database. +Obviously, in-memory databases do not provide persistent storage; you will need to +populate your database when your application starts and be prepared to throw away +data when your application ends. + +TIP: The ``How-to'' section includes a <> + +Spring Boot can auto-configure embedded http://www.h2database.com[H2], +http://hsqldb.org/[HSQL] and http://db.apache.org/derby/[Derby] databases. You don't +need to provide any connection URLs, simply include a build dependency to the +embedded database that you want to use. + +For example, typical POM dependencies would be: + +[source,xml,indent=0] +---- + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.hsqldb + hsqldb + runtime + +---- + +NOTE: You need a dependency on `spring-jdbc` for an embedded database to be +auto-configured. In this example it's pulled in transitively via +`spring-boot-starter-data-jpa`. + + + +[[boot-features-connect-to-production-database]] +==== Connection to a production database +Production database connections can also be auto-configured using a pooling +`DataSource`. Here's the algorithm for choosing a specific implementation. + +* We prefer the Tomcat pooling `DataSource` for its performance and concurrency, so if + that is available we always choose it. +* If commons-dbcp is available we will use that, but we don't recommend it in production. + +If you use the `spring-boot-starter-jdbc` or `spring-boot-starter-data-jpa` +``starter POMs'' you will automcatically get a dependency to `tomcat-jdbc`. + +NOTE: Additional connection pools can always be configured manually. If you define your +own `DataSource` bean, auto-configuration will not occur. + +DataSource configuration is controlled by external configuration properties in +`spring.datasource.*`. For example, you might declare the following section +in `application.properties`: + +[indent=0] +---- + spring.datasource.url: jdbc:mysql://localhost/test + spring.datasource.username: dbuser + spring.datasource.password: dbpass + spring.datasource.driverClassName: com.mysql.jdbc.Driver +---- + +See {sc-spring-boot-autoconfigure}/jdbc/AbstractDataSourceConfiguration.{sc-ext}[`AbstractDataSourceConfiguration`] +for more of the supported options. + +NOTE: For a pooling `DataSource` to be created we need to be able to verify that a valid +`Driver` class is available, so we check for that before doing anything. I.e. if you set +`spring.datasource.driverClassName=com.mysql.jdbc.Driver` then that class has to be +loadable. + +[[boot-features-using-jdbc-template]] +=== Using JdbcTemplate +Spring's `JdbcTemplate` and `NamedParameterJdbcTemplate` classes are auto-configured and +you can `@Autowire` them directly into your own beans: + +[source,java,indent=0] +---- + import org.springframework.beans.factory.annotation.Autowired; + import org.springframework.jdbc.core.JdbcTemplate; + import org.springframework.stereotype.Component; + + @Component + public class MyBean { + + private final JdbcTemplate jdbcTemplate; + + @Autowired + public MyBean(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + // ... + + } +---- + + + +[[boot-features-jpa-and-spring-data]] +=== JPA and ``Spring Data'' +The Java Persistence API is a standard technology that allows you to ``map'' objects to +relational databases. The `spring-boot-starter-data-jpa` POM provides a quick way to get +started. It provides the following key dependencies: + +* Hibernate -- One of the most popular JPA implementations. +* Spring Data JPA -- Makes it easy to easily implement JPA based repositories. +* Spring ORMs -- Core ORM support from the Spring Framework. + +TIP: We won't go into too many details of JPA or Spring Data here. You can follow the +http://spring.io/guides/gs/accessing-data-jpa/[``Accessing Data with JPA''] guide from +http://spring.io and read the http://projects.spring.io/spring-data-jpa/[Spring Data JPA] +and http://hibernate.org/orm/documentation/[Hibernate] reference documentation. + + + +[[boot-features-entity-classes]] +==== Entity Classes +Traditionally, JPA ``Entity'' classes are specified in a `persistence.xml` file. With +Spring Boot this file is not necessary and instead ``Entity Scanning'' is used. By +default all packages below your main configuration class (the one annotated with +`@EnableAutoConfiguration`) will be searched. + +Any classes annotated with `@Entity`, `@Embeddable` or `@MappedSuperclass` will be +considered. A typical entity class would look something like this: + +[source,java,indent=0] +---- + package com.example.myapp.domain; + + import java.io.Serializable; + import javax.persistence.*; + + @Entity + public class City implements Serializable { + + @Id + @GeneratedValue + private Long id; + + @Column(nullable = false) + private String name; + + @Column(nullable = false) + private String state; + + // ... additional members, often include @OneToMany mappings + + protected City() { + // no-args constructor required by JPA spec + // this one is protected since it shouldn't be used directly + } + + public City(String name, String state) { + this.name = name; + this.country = country; + } + + public String getName() { + return this.name; + } + + public String getState() { + return this.state; + } + + // ... etc + + } +---- + +TIP: You can customize entity scanning locations using the `@EntityScan` annotation. +See the ``<>'' +how-to. + + + +[[boot-features-spring-data-jpa-repositories]] +==== Spring Data JPA Repositories +Spring Data JPA repositories are interfaces that you can define to access data. JPA +queries are created automatically from your method names. For example, a `CityRepoistory` +interface might declare a `findAllByState(String state)` method to find all cities +in a given state. + +For more complex queries you can annotate your method using Spring Data's +{spring-data-javadoc}/repository/Query.html[`Query`] annotation. + +Spring Data repositories usually extend from the +{spring-data-commons-javadoc}/repository/Repository.html[`Repository`] or +{spring-data-commons-javadoc}/repository/CrudRepository.html[`CrudRepository`] interfaces. If you are using +auto-configuration, repositories will be searched from the package containing your +main configuration class (the one annotated with `@EnableAutoConfiguration`) down. + +Here is a typical Spring Data repository: + +[source,java,indent=0] +---- + package com.example.myapp.domain; + + import org.springframework.data.domain.*; + import org.springframework.data.repository.*; + + public interface CityRepository extends Repository { + + Page findAll(Pageable pageable); + + City findByNameAndCountryAllIgnoringCase(String name, String country); + + } +---- + +TIP: We have barely scratched the surface of Spring Data JPA. For complete details check +their http://projects.spring.io/spring-data-jpa/[reference documentation]. + + + +[[boot-features-creating-and-dropping-jpa-databases]] +==== Creating and dropping JPA databases +By default JPA database will be automatically created *only* if you use an embedded +database (H2, HSQL or Derby). You can explicitly configure JPA settings using +`spring.jpa.*` properties. For example, to create and drop tables you can add the +following to your `application.properties`. + +[indent=0] +---- + spring.jpa.hibernate.ddl-auto="create-drop" +---- + + + +[[boot-features-nosql]] +== Working with NoSQL technologies +Spring Data provides additional projects that help you access a variety of NoSQL +technologies including +http://projects.spring.io/spring-data-mongodb/[MongoDB], +http://projects.spring.io/spring-data-neo4j/[Neo4J], +http://projects.spring.io/spring-data-redis/[Redis], +http://projects.spring.io/spring-data-gemfire/[Gemfire], +http://projects.spring.io/spring-data-couchbase/[Couchbase] and +http://projects.spring.io/spring-data-cassandra/[Cassandra]. +Spring Boot provides auto-configuration for MongoDB; you can make use of the other +project, but you will need to configure them yourself. Refer to the appropriate +reference documentation at http://projects.spring.io/spring-data. + + + +[[boot-features-mongodb]] +=== MongoDB +http://www.mongodb.com/[MongoDB] is an open-source NoSQL document database that uses a +JSON-like schema instead of traditional table-based relational data. Spring Boot offers +several conveniences for working with MongoDB, including the The +`spring-boot-starter-data-mongodb` ``Starter POM''. + + + +[[boot-features-connecting-to-mongodb]] +==== Connecting to a MongoDB database +You can inject an auto-configured `com.mongodb.Mongo` instance as you would any other +Spring Bean. By default the instance will attempt to connect to a MongoDB server using +the URL `mongodb://localhost/test`: + +[source,java,indent=0] +---- + import org.springframework.beans.factory.annotation.Autowired; + import org.springframework.stereotype.Component; + + import com.mongodb.Mongo; + + @Component + public class MyBean { + + private final Mongo mongo; + + @Autowired + public MyBean(Mongo mongo) { + this.mongo = mongo; + } + + // ... + + } +---- + +You can set `spring.data.mongodb.url` property to change the `url`, or alternatively +specify a `host`/`port`. For example, you might declare the following in your +`application.properties`: + +[indent=0] +---- + spring.data.mongodb.host = mongoserver + spring.data.mongodb.port = 27017 +---- + +TIP: If `spring.data.mongodb.port` is not specified the default of `27017` is used. You +could simply delete this line from the sample above. + +You can also declare your own `Mongo` `@Bean` if you want to take complete control of +establishing the MongoDB connection. + + + +[[boot-features-mongo-template]] +==== MongoTemplate +Spring Data Mongo provides a {spring-data-mongo-javadoc}/core/MongoTemplate.html[`MongoTemplate`] +class that is very similar in its design to Spring's `JdbcTemplate`. As with +`JdbcTemplate` Spring Boot auto-configures a bean for you to simply inject: + +[source,java,indent=0] +---- + import org.springframework.beans.factory.annotation.Autowired; + import org.springframework.data.mongodb.core.MongoTemplate; + import org.springframework.stereotype.Component; + + @Component + public class MyBean { + + private final MongoTemplate mongoTemplate; + + @Autowired + public MyBean(MongoTemplate mongoTemplate) { + this.mongoTemplate = mongoTemplate; + } + + // ... + + } +---- + +See the `MongoOperations` Javadoc for complete details. + + + +[[boot-features-spring-data-mongo-repositories]] +==== Spring Data MongoDB repositories +Spring Data includes repository support for MongoDB. As with the JPA repositories +discussed earlier, the basic principal is that queries are constructed for you +automatically based on method names. + +In fact, both Spring Data JPA and Spring Data MongoDB share the same common +infrastructure; so you could take the JPA example from earlier and, assuming that +`City` is now a Mongo data class rather than a JPA `@Entity`, it will work in the +same way. + +[source,java,indent=0] +---- + package com.example.myapp.domain; + + import org.springframework.data.domain.*; + import org.springframework.data.repository.*; + + public interface CityRepository extends Repository { + + Page findAll(Pageable pageable); + + City findByNameAndCountryAllIgnoringCase(String name, String country); + + } +---- + +TIP: For complete details of Spring Data MongoDB, including its rich object mapping +technologies, refer to their http://projects.spring.io/spring-data-mongodb/[reference +documentation]. + + + +[[boot-features-testing]] +== Testing +Spring Boot provides a number of useful tools for testing your application. The +`spring-boot-starter-parent` POM provides JUnit, Hamcrest and Mockito ``test'' `scope` +dependencies. There are also useful test utilities in the core `spring-boot` module +under the `org.springframework.boot.test` package. There is also a +`spring-boot-starter-test` ``Starter POM''. + + + +[[boot-features-test-scope-dependencies]] +=== Test scope dependencies +If you extend your Maven project from the `spring-boot-starter-parent` POM, or use the +`spring-boot-starter-test` ``Starter POM'' (in the `test` `scope`), you will find +the following provided libraries: + +* Junit -- The de-facto standard for unit testing Java applications. +* Hamcrest -- A library of matcher objects (also known as constraints or predicates) + allowing `assertThat` style JUnit assertions. +* Mockito -- A Java mocking framework. + +These are common libraries that we generally find useful when writing Tests. You are free +to replace them if they don't suit your needs. + + + +[[boot-features-testing-spring-applications]] +=== Testing Spring applications +One of the major advantages of dependency injection is that it should make your code +easier to unit test. You can simply instantiate objects using the `new` operator without +even involving Spring. You can also use _mock objects_ instead of real dependencies. + +Often you need to move beyond ``unit testing'' and start ``integration testing'' (with +a Spring `ApplicationContext` actually involved in the process). It's useful to be able +to perform integration testing without requiring deployment of your application or +needing to connect to other infrastructure. + +The Spring Framework includes a dedicated test module for just such integration testing. +You can declare a dependency directly to `org.springframework:spring-test` or use the +`spring-boot-starter-test` ``Starter POM'' to pull it in transitively. + +If you have not use the `spring-test` module before you should start by reading the +{spring-reference}/#testing[relevant section] of the Spring Framework reference +documentation. + + + +[[boot-features-testing-spring-boot-applications]] +=== Testing Spring Boot applications +A Spring Boot application is just a Spring `ApplicationContext` so nothing very special +has to be done to test it beyond what you would normally do with a vanilla Spring context. +One thing to watch out for though is that the external properties, logging and other +features of Spring Boot are only installed in the context by default if you use +`SpringApplication` to create it. + +Spring Boot provides a `@SpringApplicationConfiguration` annotation as an alternative +to the standard `spring-test` `@ContextConfiguration` annotation. If you use +`@SpringApplicationConfiguration` to configure the `ApplicationContext` used in your +tests, it will be created via `SpringApplication` and you will get the additional Spring +Boot features. + +For example: +[source,java,indent=0,subs="verbatim,quotes,attributes"] +---- + @RunWith(SpringJUnit4ClassRunner.class) + @SpringApplicationConfiguration(classes = SampleDataJpaApplication.class) + public class CityRepositoryIntegrationTests { + + @Autowired + CityRepository repository; + + // ... + + } +---- + +TIP: The context loader guesses whether you want to test a web application or not (e.g. with +`MockMVC`) by looking for the `@WebAppConfiguration` annotation. (`MockMVC` and +`@WebAppConfiguration` are part of `spring-test`). + + + +[[boot-features-test-utilities]] +=== Test utilities +A few test utility classes are packaged as part of `spring-boot` that are generally +useful when testing your application. + + + +[[boot-features-configfileapplicationcontextinitializer-test-utility]] +==== ConfigFileApplicationContextInitializer +`ConfigFileApplicationContextInitializer` is an `ApplicationContextInitializer` that +can apply to your tests to load Spring Boot `application.properties` files. You can use +when you don't need the full features provided by `@SpringApplicationConfiguration`. + +[source,java,indent=0] +---- + @ContextConfiguration(classes = Config.class, + initializers = ConfigFileApplicationContextInitializer.class) +---- + + + +[[boot-features-environment-test-utilities]] +==== EnvironmentTestUtils +`EnvironmentTestUtils` allows you to quickly add properties to a +`ConfigurableEnvironment` or `ConfigurableApplicationContext`. Simply call it with +`key=value` strings: + +[source,java,indent=0] +---- +EnvironmentTestUtils.addEnvironment(env, "org=Spring", "name=Boot"); +---- + + + +[[boot-features-output-capture-test-utility]] +==== OutputCapture +`OutputCapture` is a JUnit `Rule` that you can use to capture `System.out` and +`System.err` output. Simply declare the capture as a `@Rule` then use `toString()` +for assertions: + +[source,java,indent=0] +---- +import org.junit.Rule; +import org.junit.Test; +import org.springframework.boot.test.OutputCapture; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +public class MyTest { + + @Rule + public OutputCapture capture = new OutputCapture(); + + @Test + public void testName() throws Exception { + System.out.println("Hello World!"); + assertThat(capture.toString(), containsString("World")); + } + +} +---- + + + +[[boot-features-developing-auto-configuration]] +== Developing auto-configuration and using conditions +If you work in a company that develops shared libraries, or if you work on an open-source +or commercial library, you might want to develop your own auto-configuration. +Auto-configuration classes can be bundled in external jars and still be picked-up by +Spring Boot. + + + +[[boot-features-understanding-auto-configured-beans]] +=== Understanding auto-configured beans +Under the hood, auto-configuration is implemented with standard `@Configuration` classes. +Additional `@Conditional` annotations are used to constrain when the auto-configuration +should apply. Usually auto-configuration classes use `@ConditionalOnClass` and +`@ConditionalOnMissingBean` annotations. This ensures that auto-configuration only +applies when relevant classes are found and when you have not declared your own +`@Configuration`. + +You can browse the source code of `spring-boot-autoconfigure` to see the `@Configuration` +classes that we provide (see the `META-INF/spring.factories` file). + + + +[[boot-features-locating-auto-configuration-candidates]] +=== Locating auto-configuration candidates +Spring Boot checks for the presence of a `META-INF/spring.factories` file within your +published jar. The file should list your configuration classes under the +`EnableAutoConfiguration` key. + +[indent=0] +---- + org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.mycorp.libx.autoconfigure.LibXAutoConfiguration,\ + com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration +---- + +You can use the +{sc-spring-boot-autoconfigure}/AutoConfigureAfter.{sc-ext}[`@AutoConfigureAfter`] or +{sc-spring-boot-autoconfigure}/AutoConfigureBefore.{sc-ext}[`@AutoConfigureBefore`] +annotations if your configuration needs to be applied in a specific order. For example, +if you provide web specific configuration, your class may need to be applied after +`WebMvcAutoConfiguration`. + + + +[[boot-features-condition-annotations]] +=== Condition annotations +You almost always want to include one or more `@Condition` annotations on your +auto-configuration class. The `@ConditionalOnMissingBean` is one common example that is +used to allow developers to ``override'' auto-configuration if they are not happy with +your defaults. + +Spring Boot includes a number of `@Conditional` annotations that you can reuse in your own +code by annotating `@Configuration` classes or individual `@Bean` methods. + + + +[[boot-features-class-conditions]] +==== Class conditions +The `@ConditionalOnClass` and `@ConditionalOnMissingClass` annotations allows configuration +to be skipped based on the presence or absence of specific classes. Due to the fact that +annotation meta-data is parsed using http://asm.ow2.org/[ASM] you can actually use the +`value` attribute to refer to the real class, even though that class might not actually +appear on the running application classpath. You can also use the `name` attribute if you +prefer to specify the class name using a `String` value. + + + +[[boot-features-bean-conditions]] +==== Bean conditions +The `@ConditionalOnBean` and `@ConditionalOnMissingBean` annotations allow configurations +to be skipped based on the presence or absence of specific beans. You can use the `value` +attribute to specify beans by type, or `name` to specify beans by name. The `search` +attribute allows you to limit the `ApplicationContext` hierarchy that should be considered +when searching for beans. + +NOTE: `@Conditional` annotations are processed when `@Configuration` classes are +parsed. Auto-configure `@Configuration` is always parsed last (after any user defined +beans), however, if you are using these annotations on regular `@Configuration` classes, +care must be take not to refer to bean definitions that have not yet been created. + + + +[[boot-features-resource-conditions]] +==== Resource conditions +The `@ConditionalOnResource` annotation allows configuration to be skipped when a specific +resource is not present. Resources can be specified using the usual Spring conventions, +for example, `file:/home/user/test.dat`. + + + +[[boot-features-web-application-conditions]] +==== Web Application Conditions +The `@ConditionalOnWebApplication` and `@ConditionalOnNotWebApplication` annotations +allow configuration to be skipped depending on whether the application is a +'web application'. A web application is any application that is using a Spring +`WebApplicationContext`, defines a `session` scope or has a `StandardServletEnvironment`. + + + +[[boot-features-spel-conditions]] +==== SpEL expression conditions +The `@ConditionalOnExpression` annotation allows configuration to be skipped based on the +result of a {spring-reference}/#expressions[SpEL expression]. + + + +[[boot-features-whats-next]] +== What to read next +If you want to learn more about any of the classes discussed in this section you can +check out the {dc-root}[Spring Boot API documentation] or you can browse the +{github-code}[source code directly]. If you have specific questions, take a look at the +<> section. + +If you are comfortable with Spring Boot's core features, you can carry on and read +about <>. + diff --git a/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc b/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc new file mode 100644 index 00000000000..70be2bee119 --- /dev/null +++ b/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc @@ -0,0 +1,597 @@ +[[using-boot]] += Using Spring Boot + +[partintro] +-- +This section goes into more detail about how you should use Spring Boot. It covers topics +such as build systems, auto-configuration and run/deployment options. We also cover some +Spring Boot ``best practices''. Although there is nothing particularly special about +Spring Boot (it is just another library that you can consume). There are a few +recommendations that, when followed, will make your development process just a +little easier. + +If you're just starting out with Spring Boot, you should probably read the +``<>'' guide before diving into +this section. +-- + + + +[[using-boot-build-systems]] +== Build systems +It is strongly recommended that you choose a build system that supports _dependency +management_, and one that can consume artifacts published to the ``Maven Central'' +repository. We would recommend that you choose Maven or Gradle. It is possible to get +Spring Boot to work with other build systems (Ant for example), but they will not be +particularly well supported. + + + +[[using-boot-maven]] +=== Maven +Maven users can inherit from the `spring-boot-starter-parent` project to obtain sensible +defaults. The parent project provides the following features: + +* Java 1.6 as the default compiler level. +* UTF-8 source encoding. +* A Dependency Management section, allowing you to omit `` tags for common + dependencies. +* Generally useful test dependencies (http://junit.org/[JUnit], + https://code.google.com/p/hamcrest/[Hamcrest], + https://code.google.com/p/mockito/[Mockito]). +* Sensible https://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html[resource filtering]. +* Sensible plugin configuration (http://mojo.codehaus.org/exec-maven-plugin/[exec plugin], + http://maven.apache.org/surefire/maven-surefire-plugin/[surefire], + https://github.com/ktoso/maven-git-commit-id-plugin[Git commit ID], + http://maven.apache.org/plugins/maven-shade-plugin/[shade]). + + + +[[using-boot-maven-parent-pom]] +==== Inheriting the starter parent +To configure your project to inherit from the `spring-boot-starter-parent` simply set +the `parent`: + +[source,xml,indent=0,subs="verbatim,quotes,attributes"] +---- + + + org.springframework.boot + spring-boot-starter-parent + {spring-boot-version} + +---- + +NOTE: You should only need to specify the Spring Boot version number on this dependency. +if you import additional starters, you can safely omit the version number. + + + +[[using-boot-maven-your-own-parent]] +==== Using your own parent POM +If you don't want to use the Spring Boot starter parent, you can use your own and still +keep the benefit of the dependency management (but not the plugin management) using a +`scope=import` dependency: + +[source,xml,indent=0,subs="verbatim,quotes,attributes"] +---- + + + + + org.springframework.boot + spring-boot-starter-parent + {spring-boot-version} + import + + + +---- + + + +[[using-boot-maven-java-version]] +==== Changing the Java version +The `spring-boot-starter-parent` chooses fairly conservative Java compatibility. If you +want to follow our recommendation and use a later Java version you can add a +`java.version` property: + +[source,xml,indent=0,subs="verbatim,quotes,attributes"] +---- + + 1.8 + +---- + + + +[[using-boot-maven-plugin]] +==== Using the Spring Boot Maven plugin +Spring Boot includes a <> +that can package the project as an executable jar. Add the plugin to your `` +section if you want to use it: + +[source,xml,indent=0,subs="verbatim,quotes,attributes"] +---- + + + + org.springframework.boot + spring-boot-maven-plugin + + + +---- + +NOTE: You only need to add the plugin, there is no need for to configure it unless you +want to change the settings defined in the parent. + + + +[[using-boot-gradle]] +=== Gradle +Gradle users can directly import ``starter POMs'' in their `dependencies` section. Unlike +Maven, there is no ``super parent'' to import. + +[source,groovy,indent=0,subs="attributes"] +---- + apply plugin: 'java' + + repositories { mavenCentral() } + dependencies { + compile("org.springframework.boot:spring-boot-starter-web:{spring-boot-version}") + } +---- + +The <> +is also available and provides tasks to create executable jars and run projects from +source. It also adds a `ResolutionStrategy` that enables you to omit the version number +for ``blessed'' dependencies: + +[source,groovy,indent=0,subs="attributes"] +---- + buildscript { + repositories { mavenCentral() } + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:{spring-boot-version}") + } + } + + apply plugin: 'java' + apply plugin: 'spring-boot' + + repositories { mavenCentral() } + dependencies { + compile("org.springframework.boot:spring-boot-starter-web") + testCompile("org.springframework.boot:spring-boot-starter-test") + } +---- + + + +[[using-boot-ant]] +=== Ant +It is possible to build a Spring Boot project using Apache Ant, however, no special +support or plugins are provided. Ant scripts can use the Ivy dependency system to import +starter POMs. + +See the ``<>'' ``How-to'' for more +complete instructions. + + + +[[using-boot-starter-poms]] +=== Starter POMs +Starter POMs are a set of convenient dependency descriptors that you can include in your +application. You get a one-stop-shop for all the Spring and related technology that you +need, without having to hunt through sample code and copy paste loads of dependency +descriptors. For example, if you want to get started using Spring and JPA for database +access, just include the `spring-boot-starter-data-jpa` dependency in your project, and +you are good to go. + +The starters contain a lot of the dependencies that you need to get a project up and +running quickly and with a consistent, supported set of managed transitive dependencies. + +.What's in a name +**** +All starters follow a similar naming pattern; `spring-boot-starter-*`, where `*` is +a particular type of application. This naming structure is intended to help when you need +to find a starter. The Maven integration in many IDEs allow you to search dependencies by +name. For example, with the appropriate Eclipse or STS plugin installed, you can simply +hit `ctrl-space` in the POM editor and type ''spring-boot-starter'' for a complete list. +**** + +The following application starters are provided by Spring Boot under the +`org.springframework.boot` group: + +.Spring Boot application starters +|=== +| Name | Description + +|`spring-boot-starter` +|The core Spring Boot starter, including auto-configuration support, logging and YAML. + +|`spring-boot-starter-amqp` +|Support for the ``Advanced Message Queuing Protocol'' via `spring-rabbit`. + +|`spring-boot-starter-aop` +|Full AOP programming support including `spring-aop` and AspectJ. + +|`spring-boot-starter-batch` +|Support for ``Spring Batch'' including HSQLDB database. + +|`spring-boot-starter-data-jpa` +|Full support for the ``Java Persistence API'' including `spring-data-jpa`, `spring-orm` +and Hibernate. + +|`spring-boot-starter-data-mongodb` +|Support for the MongoDB NoSQL Database, including `spring-data-mongodb`. + +|`spring-boot-starter-data-rest` +|Support for exposing Spring Data repositories over REST via `spring-data-rest-webmvc`. + +|`spring-boot-starter-integration` +|Support for common `spring-integration` modules. + +|`spring-boot-starter-jdbc` +|JDBC Database support. + +|`spring-boot-starter-mobile` +|Support for `spring-mobile` + +|`spring-boot-starter-redis` +|Support for the REDIS key-value data store, including `spring-redis`. + +|`spring-boot-starter-security` +|Support for `spring-security`. + +|`spring-boot-starter-test` +|Support for common test dependencies, including JUnit, Hamcrest and Mockito along with + the `spring-test` module. + +|`spring-boot-starter-thymeleaf` +|Support for the Thymeleaf templating engine, including integration with Spring. + +|`spring-boot-starter-web` +|Support for full-stack web development, including Tomcat and `spring-webmvc`. + +|`spring-boot-starter-websocket` +|Support for websocket development with Tomcat. +|=== + +In addition to the application starters, the following starters can be used to +add ``<>'' features. + +.Spring Boot production ready starters +|=== +| Name | Description + +|`spring-boot-starter-actuator` +|Adds production ready features such as metrics and monitoring. + +|`spring-boot-starter-shell-remote` +|Adds remote `ssh` shell support. +|=== + +Finally, Spring Boot includes some starters that can be used if you want to exclude or +swap specific technical facets. + +.Spring Boot technical starters +|=== +| Name | Description + +|`spring-boot-starter-jetty` +|Imports the Jetty HTTP engine (to be used as an alternative to Tomcat) + +|`spring-boot-starter-log4j` +|Support the Log4J looggin framework + +|`spring-boot-starter-logging` +|Import Spring Boot's default logging framework (Logback). + +|`spring-boot-starter-tomcat` +|Import Spring Boot's default HTTP engine (Tomcat). +|=== + + + +[[using-boot-structuring-your-code]] +== Structuring your code +Spring Boot does not require any specific code layout to work, however, there are some +best practices that help. + + + +[[using-boot-using-the-default-package]] +=== Using the ``default'' package +When a class doesn't include a `package` declaration it is considered to be in the +``default package''. The use of the ``default package'' is generally discouraged, and +should be avoided. It can cause particular problems for Spring Boot applications that +use `@ComponentScan` or `@EntityScan` annotations, since every class from every jar, +will be read. + +TIP: We recommend that you use the follow Java's recommended package naming conventions +and use a reversed domain name (for example, `com.example.project`). + + + +[[using-boot-locating-the-main-class]] +=== Locating the main application class +We generally recommend that you locate your main application class in a root package +above other classes. The `@EnableAutoConfiguration` annotation is often placed on your +main class, and it implicitly defines a base ``search package'' for certain items. For +example, if you are writing a JPA application, the package of the +`@EnableAutoConfiguration` annotated class will be used to search for `@Entity` items. + +Using a root package also allows the `@ComponentScan` annotation to be used without +needing to specify a `basePackage` attribute. + +Here is a typical layout: + +[indent=0] +---- + com + +- example + +- myproject + +- Application.java + | + +- domain + | +- Customer.java + | +- CustomerRepository.java + | + +- service + | +- CustomerService.java + | + +- web + +- CustomerController.java +---- + +The `Application.java` file would declare the `main` method, along with the basic +`@Configuration`. + +[source,java,indent=0] +---- + package com.example.myproject; + + import org.springframework.boot.SpringApplication; + import org.springframework.boot.autoconfigure.EnableAutoConfiguration; + import org.springframework.context.annotation.ComponentScan; + import org.springframework.context.annotation.Configuration; + + @Configuration + @EnableAutoConfiguration + @ComponentScan + public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + } +---- + + + +[[using-boot-configuration-classes]] +== Configuration classes +Spring Boot favors Java-based configuration. Although it is possible to call +`SpringApplication.run()` with an XML source, we generally recommend that your primary +source is a `@Configuration` class. Usually the class that defines the `main` method +is also a good candidate as the primary `@Configuration`. + +TIP: Many Spring configuration examples have been published on the Internet that use XML +configuration. Always try to use the equivalent Java-base configuration if possible. +Searching for `enable*` annotations can be a good starting point. + + + +[[using-boot-importing-configuration]] +=== Importing additional configuration classes +You don't need to put all your `@Configuration` into a single class. The `@Import` +annotation can be used to import additional configuration classes. Alternatively, you +can use `@ComponentScan` to automatically pickup all Spring components, including +`@Configuration` classes. + + + +[[using-boot-importing-xml-configuration]] +=== Importing XML configuration +If you absolutely must use XML based configuration, we recommend that you still start +with a `@Configuration` class. You can then use an additional `@ImportResource` +annotation to load XML configuration files. + + + +[[using-boot-auto-configuration]] +== Auto-configuration +Spring Boot auto-configuration attempts to automatically configure your Spring +application based on the jar dependencies that you have added. For example, If +`HSQLDB` is on your classpath, and you have not manually configured any database +connection beans, then we will auto-configure an in-memory database. + +You need to opt-in to auto-configuration by adding the `@EnableAutoConfiguration` +annotation to one of your `@Configuration` classes. + +TIP: You should only ever add one `@EnableAutoConfiguration` annotation. We generally +recommend that you add it to your primary `@Configuration` class. + + + +[[using-boot-replacing-auto-configuration]] +=== Gradually replacing auto-configuration +Auto-configuration is noninvasive, at any point you can start to define your own +configuration to replace specific parts of the auto-configuration. For example, if +you add your own `DataSource` bean, the default embedded database support will back away. + +If you need to find out what auto-configuration is currently being applied, and why, +starting your application with the `--debug` switch. This will log an auto-configuration +report to the console. + + + +[[using-boot-disabling-specific-auto-configutation]] +=== Disabling specific auto-configuration +If you find that specific auto-configure classes are being applied that you don't want, +you can use the exclude attribute of `@EnableAutoConfiguration` to disable them. + +[source,java,indent=0] +---- + import org.springframework.boot.autoconfigure.*; + import org.springframework.boot.autoconfigure.jdbc.*; + import org.springframework.context.annotation.*; + + @Configuration + @EnableAutoConfiguration(exclude={EmbeddedDatabaseConfiguration.class}) + public class MyConfiguration { + } +---- + + + +[[using-boot-spring-beans-and-dependency-injection]] +== Spring Beans and dependency injection +You are free to use any the standard Spring Framework techniques to defines your beans +and their injected dependencies. For simplicity, we often find that using `@ComponentScan` +to find your beans, in combination with `@Autowired` constructor injection works well. + +If you structure your code as suggested above (locating your application class in a root +package), you can add `@ComponentScan` without any arguments. All of your application +components (`@Component`, `@Service`, `@Repoistory`, `@Controller` etc.) will be +automatically registered as Spring Beans. + +Here is an example `@Service` Bean that uses constructor injection to obtain a +required `RiskAssessor` bean. + +[source,java,indent=0] +---- + package com.example.service; + + import org.springframework.beans.factory.annotation.Autowired; + import org.springframework.stereotype.Service; + + @Service + public class DatabaseAccountService implements AccountService { + + private final RiskAssessor riskAssessor; + + @Autowired + public DatabaseAccountService(RiskAssessor riskAssessor) { + this.riskAssessor = riskAssessor; + } + + // ... + + } +---- + +TIP: Notice how using constructor injection allows the `riskAssessor` field to be marked +as `final`, indicating that it cannot be subsequently changed. + +[[using-boot-running-your-application]] +== Running your application +One of the biggest advantages of packaging your application as jar and using an embedded +HTTP server is that you can run your application as you would any other. Debugging Spring +Boot applications is also easy; you don't need any special IDE plugins or extensions. + +NOTE: This section only covers jar based packaging, If you choose to package your +application as a war file you should refer to your server and IDE documentation. + + + +[[using-boot-running-from-an-ide]] +=== Running from an IDE +You can run a Spring Boot application from your IDE as a simple Java application, however, +first you will need to import your project. Import steps will vary depending on your IDE +and build system. Most IDEs can import Maven projects directly, for example Eclipse users +can select `Import...` -> `Existing Maven Projects` from the `File` menu. + +If you can't directly import your project into your IDE, you may be able to generate IDE +meta-data using a build plugin. Maven includes plugins for +http://maven.apache.org/plugins/maven-eclipse-plugin/[Eclipse] and +http://maven.apache.org/plugins/maven-idea-plugin/[IDEA]; Gradle offers plugins +for http://www.gradle.org/docs/current/userguide/ide_support.html[various IDEs]. + +TIP: If you accidentally run a web application twice you will see a ``Port already in +use'' error. STS users can use the `Relauch` button rather than `Run` to ensure that +any existing instance is closed. + + + +[[using-boot-running-as-a-packaged-application]] +=== Running as a packaged application +If you use the Spring Boot Maven or Gradle plugins to create an executable jar you can +run your application using `java -jar`. For example: + +[indent=0,subs="attributes"] +---- + $ java -jar target/myproject-0.0.1-SNAPSHOT.jar +---- + +It is also possible to run a packaged application with remote debugging support enabled. +This allows you to attach a debugger to your packaged application: + +[indent=0,subs="attributes"] +---- + $ java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n \ + -jar target/myproject-0.0.1-SNAPSHOT.jar +---- + + + +[[using-boot-running-with-the-maven-plugin]] +=== Using the Maven plugin +The Spring Boot Maven plugin includes a `run` goal which can be used to quickly compile +and run your application. Applications run in an exploded form, and you can edit +resources for instant ``hot'' reload. + +[indent=0,subs="attributes"] +---- + $ mvn spring-boot:run +---- + + + +[[using-boot-running-with-the-gradle-plugin]] +=== Using the Gradle plugin +The Spring Boot Gradle plugin also includes a `run` goal which can be used to run +your application in an exploded form. The `bootRun` task is added whenever you import +the `spring-boot-plugin` + +[indent=0,subs="attributes"] +---- + $ gradle bootRun +---- + + + +[[using-boot-hot-swapping]] +=== Hot swapping +Since Spring Boot applications are just plain Java application, JVM hot-swapping should +work out of the box. JVM hot swapping is somewhat limited with the bytecode that it can +replace, for a more complete solution the +https://github.com/spring-projects/spring-loaded[Spring Loaded] project, or +http://zeroturnaround.com/software/jrebel/[JRebel] can be used. + +See the <> section for details. + + + +[[using-boot-packaging-for-production]] +== Packaging your application for production +Executable jars can be used for production deployment. As they are self contained, they +are also ideally suited for cloud-based deployment. + +For additional ``production ready'' features, such as health, auditing and metric REST +or JMX end-points; consider adding `spring-boot-actuator`. See +``<>'' for details. + + + +[[using-boot-whats-next]] +== What to read next +You should now have good understanding of how you can use Spring Boot along with some best +practices that you should follow. You can now go on to learn about specific +``<>'' in depth, or you +could skip ahead and read about the +``<>'' aspects of Spring +Boot. From 7a46ed0866005106a1332e3acfb5f9a78f4b674e Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 13 Mar 2014 13:28:16 -0700 Subject: [PATCH 3/4] Port "how-to" section to the reference manual Copy the existing markdown How-to readme content to the user manual, converting to asciidoc. See gh-295 --- spring-boot-docs/src/main/asciidoc/howto.adoc | 1227 +++++++++++++++++ .../main/asciidoc/spring-boot-features.adoc | 3 +- 2 files changed, 1229 insertions(+), 1 deletion(-) diff --git a/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-docs/src/main/asciidoc/howto.adoc index 81ac1973930..7290fdcec47 100644 --- a/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -15,3 +15,1230 @@ the `spring-boot` tag). We're also more than happy to extend this section; If you want to add a ``how-to'' you can send us a {github-code}[pull request]. -- + + + +[[howto-spring-boot-application]] +== Spring Boot application + + + +[[howto-troubleshoot-auto-configuration]] +=== Troubleshoot auto-configuration +The Spring Boot auto-configuration tries it's best to ``do the right thing'', but +sometimes things fail and it can be hard to tell why. + +There is a really useful `AutoConfigurationReport` available in any Spring Boot +`ApplicationContext`. You will see it if you enable `DEBUG` logging output. If you use +the `spring-boot-actuator` there is also an `autoconfig` endpoint that renders the report +in JSON. Use that to debug the application and see what features have been added (and +which not) by Spring Boot at runtime. + +Many more questions can be answered by looking at the source code and Javadocs. Some +rules of thumb: + +* Look for classes called `*AutoConfiguration` and read their sources, in particular the + `@Conditional*` annotations to find out what features they enable and when. Add + `--debug` to the command line or a System property `-Ddebug` to get a log on the + console of all the autoconfiguration decisions that were made in your app. In a running + Actuator app look at the `autoconfig` endpoint (`/autoconfig' or the JMX equivalent) for + the same information. +* Look for classes that are `@ConfigurationProperties` (e.g. + {sc-spring-boot-autoconfigure}/web/ServerProperties.{sc-ext}[`ServerProperties`] + and read from there the available external configuration options. The + `@ConfigurationProperties` has a `name` attribute which acts as a prefix to external + properties, thus `ServerProperties` has `name="server"` and its configuration properties + are `server.port`, `server.address` etc. In a running Actuator app look at the + `configprops` endpoint. +* Look for use of `RelaxedEnvironment` to pull configuration values explicitly out of the + `Environment`. It often is used with a prefix. +* Look for `@Value` annotations that bind directly to the `Environment`. This is less + flexible than the `RelaxedEnvironment` approach, but does allow some relaxed binding, + specifically for OS environment variables (so `CAPITALS_AND_UNDERSCORES` are synonyms + for `period.separated`). +* Look for `@ConditionalOnExpression` annotations that switch features on and off in + response to SpEL expressions, normally evaluated with place-holders resolved from the + `Environment`. + + + +[[howto-customize-the-environment-or-application-context]] +=== Customize the Environment or ApplicationContext before it starts +A `SpringApplication` has `ApplicationListeners` and `ApplicationContextInitializers` that +are used to apply customizations to the context or environment. Spring Boot loads a number +of such customizations for use internally from `META-INF/spring.factories`. There is more +than one way to register additional ones: + +* Programmatically per application by calling the `addListeners` and `addInitializers` + methods on `SpringApplication` before you run it. +* Declaratively per application by setting `context.initializer.classes` or + `context.listener.classes`. +* Declarative for all applications by adding a `META-INF/spring.factories` and packaging + a jar file that the applications all use as a library. + +The `SpringApplication` sends some special `ApplicationEvents` to the listeners (even +some before the context is created), and then registers the listeners for events published +by the `ApplicationContext` as well. See +``<>'' in the +``<>'' section for a complete list. + + + +[[howto-build-an-application-context-hierarchy]] +=== Build an ApplicationContext hierarchy (adding a parent or root context) +You can use the `ApplicationBuilder` class to create parent/child `ApplicationContext` +hierarchies. See ``<>'' +in the ``<>'' section for more information. + + + +[[howto-create-a-non-web-application]] +=== Create a non-web application +Not all Spring applications have to be web applications (or web services). If you want to +execute some code in a `main` method, but also bootstrap a Spring application to set up +the infrastructure to use, then it's easy with the `SpringApplication` features of Spring +Boot. A `SpringApplication` changes its `ApplicationContext` class depending on whether it +thinks it needs a web application or not. The first thing you can do to help it is to just +leave the servlet API dependencies off the classpath. If you can't do that (e.g. you are +running 2 applications from the same code base) then you can explicitly call +`SpringApplication.setWebEnvironment(false)`, or set the `applicationContextClass` +property (through the Java API or with external properties). +Application code that you want to run as your business logic can be implemented as a +`CommandLineRunner` and dropped into the context as a `@Bean` definition. + + + +[[howto-properties-and-configuration]] +== Properties & configuration + + + +[[howto-externalize-configuration]] +=== Externalize the configuration of SpringApplication +A `SpringApplication` has bean properties (mainly setters) so you can use its Java API as +you create the application to modify its behavior. Or you can externalize the +configuration using properties in `spring.main.*`. E.g. in `application.properties` you +might have. + +[indent=0,subs="verbatim,quotes,attributes"] +---- + spring.main.web_environment: false + spring.main.show_banner: false +---- + +and then the Spring Boot banner will not be printed on startup, and the application will +not be a web application. + +[[howto-change-the-location-of-external-properties]] +=== Change the location of external properties of an application +By default properties from different sources are added to the Spring `Environment` in a +defined order (see ``<>'' in +the ``<>'' section for the exact order). + +A nice way to augment and modify this is to add `@PropertySource` annotations to your +application sources. Classes passed to the `SpringApplication` static convenience +methods, and those added using `setSources()` are inspected to see if they have +`@PropertySources`, and if they do, those properties are added to the `Environment` early +enough to be used in all phases of the `ApplicationContext` lifecycle. Properties added +in this way have precedence over any added using the default locations, but have lower +priority than system properties, environment variables or the command line. + +You can also provide System properties (or environment variables) to change the behavior: + +* `spring.config.name` (`SPRING_CONFIG_NAME`), defaults to `application` as the root of + the file name. +* `spring.config.location` (`SPRING_CONFIG_LOCATION`) is file to load (e.g. a classpath + resource or a URL). A separate `Environment` property source is set up for this document + and it can be overridden by system properties, environment variables or the + command line. + +No matter what you set in the environment, Spring Boot will always load +`application.properties` as described above. If YAML is used then files with the ``.yml'' +extension are also added to the list by default. + +See {sc-spring-boot}/context/config/ConfigFileApplicationListener.{sc-ext}[`ConfigFileApplicationListener`] +for more detail. + + + +[[howto-use-short-command-line-arguments]] +=== Use ``short'' command line arguments +Some people like to use (for example) `--port=9000` instead of `--server.port=9000` to +set configuration properties on the command line. You can easily enable this by using +placeholders in `application.properties`, e.g. + +[indent=0,subs="verbatim,quotes,attributes"] +---- + server.port: ${port:8080} +---- + +NOTE: In this specific case the port binding will work in a PaaS environment like Heroku +and Cloud Foundry, since in those two platforms the `PORT` environment variable is set +automatically and Spring can bind to capitalized synonyms for `Environment` properties. + + + +[[howto-use-yaml-for-external-properties]] +=== Use YAML for external properties +YAML is a superset of JSON and as such is a very convenient syntax for storing external +properties in a hierarchical format. E.g. + +[source,yaml,indent=0,subs="verbatim,quotes,attributes"] +---- + spring: + application: + name: cruncher + datasource: + driverClassName: com.mysql.jdbc.Driver + url: jdbc:mysql://localhost/test + server: + port: 9000 +---- + +Create a file called `application.yml` and stick it in the root of your classpath, and +also add `snakeyaml` to your classpath (Maven co-ordinates `org.yaml:snakeyaml`, already +included if you use the `spring-boot-starter`). A YAML file is parsed to a Java +`Map` (like a JSON object), and Spring Boot flattens the maps so that it +is 1-level deep and has period-separated keys, a lot like people are used to with +`Properties` files in Java. + +The example YAML above corresponds to an `application.properties` file + +[indent=0,subs="verbatim,quotes,attributes"] +---- + spring.application.name: cruncher + spring.datasource.driverClassName: com.mysql.jdbc.Driver + spring.datasource.url: jdbc:mysql://localhost/test + server.port: 9000 +---- + +See ``<>'' in +the ``<>'' section for more information +about YAML. + +[[howto-set-active-spring-profiles]] +=== Set the active Spring profiles +The Spring `Environment` has an API for this, but normally you would set a System profile +(`spring.profiles.active`) or an OS environment variable (`SPRING_PROFILES_ACTIVE`). E.g. +launch your application with a `-D...` argument (remember to put it before the main class +or jar archive): + +[indent=0,subs="verbatim,quotes,attributes"] +---- + $ java -jar -Dspring.profiles.active=production demo-0.0.1-SNAPSHOT.jar +---- + +In Spring Boot you can also set the active profile in `application.properties`, e.g. + +[indent=0,subs="verbatim,quotes,attributes"] +---- + spring.profiles.active=production +---- + +A value set this way is replaced by the System property or environment variable setting, +but not by the `SpringApplicationBuilder.profiles()` method. Thus the latter Java API can +be used to augment the profiles without changing the defaults. + +See ``<>'' in +the ``<>'' section for more information. + + + +[[howto-change-configuration-depending-on-the-environment]] +=== Change configuration depending on the environment +A YAML file is actually a sequence of documents separated by `---` lines, and each +document is parsed separately to a flattened map. + +If a YAML document contains a `spring.profiles` key, then the profiles value +(comma-separated list of profiles) is fed into the Spring +`Environment.acceptsProfiles()` and if any of those profiles is active that document is +included in the final merge (otherwise not). + +Example: + +[source,yaml,indent=0,subs="verbatim,quotes,attributes"] +---- + server: + port: 9000 + --- + + spring: + profiles: development + server: + port: 9001 + + --- + + spring: + profiles: production + server: + port: 0 +---- + +In this example the default port is 9000, but if the Spring profile ``development'' is +active then the port is 9001, and if ``production'' is active then it is 0. + +The YAML documents are merged in the order they are encountered (so later values override +earlier ones). + +To do the same thing with properties files you can use `application-${profile}.properties` +to specify profile-specific values. + + + +[[howto-discover-build-in-options-for-external-properties]] +=== Discover built-in options for external properties +Spring Boot binds external properties from `application.properties` (or `.yml`) (and +other places) into an application at runtime. There is not (and technically cannot be) +an exhaustive list of all supported properties in a single location because contributions +can come from additional jar files on your classpath. + +A running application with the Actuator features has a `configprops` endpoint that shows +all the bound and bindable properties available through `@ConfigurationProperties`. + +The appendix includes an <> example with a list of the most common properties supported by +Spring Boot. The definitive list comes from searching the source code for +`@ConfigurationProperties` and `@Value` annotations, as well as the occasional use of +`RelaxedEnvironment`. + + + +[[howto-embedded-servlet-containers]] +== Embedded servlet containers + + + +[[howto-add-a-servlet-filter-or-servletcontextlistener]] +=== Add a Servlet, Filter or ServletContextListener to an application +`Servlet`, `Filter`, `ServletContextListener` and the other listeners supported by the +Servlet spec can be added to your application as `@Bean` definitions. Be very careful that +they don't cause eager initialization of too many other beans because they have to be +installed in the container very early in the application lifecycle (e.g. it's not a good +idea to have them depend on your `DataSource` or JPA configuration). You can work around +restrictions like that by initializing them lazily when first used instead of on +initialization. + +In the case of `Filters` and `Servlets` you can also add mappings and init parameters by +adding a `FilterRegistrationBean` or `ServletRegistrationBean` instead of or as well as +the underlying component. + + + +[[howto-change-the-http-port]] +=== Change the HTTP port +In a standalone application the main HTTP port defaults to `8080`, but can be set with +`server.port` (e.g. in `application.properties` or as a System property). Thanks to +relaxed binding of `Environment` values you can also use `SERVER_PORT` (e.g. as an OS +environment variable). + +To switch off the HTTP endpoints completely, but still create a `WebApplicationContext`, +use `server.port=-1` (this is sometimes useful for testing). + +For more details look at ``<>'' +in the ``<>'' section, or the +{sc-spring-boot-autoconfigure}/web/ServerProperties.{sc-ext}[`ServerProperties`] source +code. + + +[[howto-user-a-random-unassigned-http-port]] +=== Use a random unassigned HTTP port +To scan for a free port (using OS natives to prevent clashes) use `server.port=0`. + + + +[[howto-discover-the-http-port-at-runtime]] +=== Discover the HTTP port at runtime +You can access the port the server is running on from log output or from the +`EmbeddedWebApplicationContext` via its `EmbeddedServletContainer`. The best way to get +that and be sure that it has initialized is to add a `@Bean` of type +`ApplicationListener` and pull the container +out of the event wehen it is published. + + + +[[howto-configure-tomcat]] +=== Configure Tomcat +Generally you can follow the advice from +``<>'' about +`@ConfigurationProperties` (`ServerProperties` is the main one here), but also look at +`EmbeddedServletContainerCustomizer` and various Tomcat specific `*Customizers` that you +can add in one of those. The Tomcat APIs are quite rich so once you have access to the +`TomcatEmbeddedServletContainerFactory` you can modify it in a number of ways. Or the +nuclear option is to add your own `TomcatEmbeddedServletContainerFactory`. + + + +[[howto-terminate-ssl-in-tomcat]] +=== Terminate SSL in Tomcat +Use an `EmbeddedServletContainerCustomizer` and in that add a `TomcatConnectorCustomizer` +that sets up the connector to be secure: + +[source,java,indent=0,subs="verbatim,quotes,attributes"] +---- + @Bean + public EmbeddedServletContainerCustomizer containerCustomizer(){ + return new MyCustomizer(); + } + + // ... + + private static class MyCustomizer implements EmbeddedServletContainerCustomizer { + + @Override + public void customize(ConfigurableEmbeddedServletContainerFactory factory) { + if(factory instanceof TomcatEmbeddedServletContainerFactory) { + customizeTomcat((TomcatEmbeddedServletContainerFactory) factory)); + } + } + + public void customizeTomcat(TomcatEmbeddedServletContainerFactory factory) { + factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { + @Override + public void customize(Connector connector) { + connector.setPort(serverPort); + connector.setSecure(true); + connector.setScheme("https"); + connector.setAttribute("keyAlias", "tomcat"); + connector.setAttribute("keystorePass", "password"); + try { + connector.setAttribute("keystoreFile", + ResourceUtils.getFile("src/ssl/tomcat.keystore").getAbsolutePath()); + } catch (FileNotFoundException e) { + throw new IllegalStateException("Cannot load keystore", e); + } + connector.setAttribute("clientAuth", "false"); + connector.setAttribute("sslProtocol", "TLS"); + connector.setAttribute("SSLEnabled", true); + } + }); + } + + } +---- + + + +[[howto-use-jetty-instead-of-tomcat]] +=== Use Jetty instead of Tomcat +The Spring Boot starters (`spring-boot-starter-web` in particular) use Tomcat as an +embedded container by default. You need to exclude those dependencies and include the +Jetty ones instead. Spring Boot provides Tomcat and Jetty dependencies bundled together +as separate startes to help make this process as easy as possible. + +Example in Maven: + +[source,xml,indent=0,subs="verbatim,quotes,attributes"] +---- + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + org.springframework.boot + spring-boot-starter-jetty + +---- + +Example in Gradle: + +[source,groovy,indent=0,subs="verbatim,quotes,attributes"] +---- + configurations { + compile.exclude module: 'spring-boot-starter-tomcat' + } + + dependencies { + compile("org.springframework.boot:spring-boot-starter-web:1.0.0.RC3") + compile("org.springframework.boot:spring-boot-starter-jetty:1.0.0.RC3") + // ... + } +---- + + + +[[howto-configure-jetty]] +=== Configure Jetty +Generally you can follow the advice from +``<>'' about +`@ConfigurationProperties` (`ServerProperties` is the main one here), but also look at +`EmbeddedServletContainerCustomizer`. The Jetty APIs are quite rich so once you have +access to the `JettyEmbeddedServletContainerFactory` you can modify it in a number +of ways. Or the nuclear option is to add your own `JettyEmbeddedServletContainerFactory`. + + + +[[howto-use-tomcat-8]] +=== Use Tomcat 8 +Tomcat 8 works with Spring Boot, but the default is to use Tomcat 7 (so we can support +Java 1.6 out of the box). You should only need to change the classpath to use Tomcat 8 +for it to work. The {github-code}/spring-boot-samples/spring-boot-sample-websocket/pom.xml[websocket sample] +shows you how to do that in Maven. + + + +[[howto-use-jetty-9]] +=== Use Jetty 9 +Jetty 9 works with Spring Boot, but the default is to use Jetty 8 (so we can support +Java 1.6 out of the box). You should only need to change the classpath to use Jetty 9 +for it to work. + +If you are using the starter poms and parent you can just add the Jetty starter and +change the version properties, e.g. for a simple webapp or service: + +[source,xml,indent=0,subs="verbatim,quotes,attributes"] +---- + + 1.7 + 9.1.0.v20131115 + 3.1.0 + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + org.springframework.boot + spring-boot-starter-jetty + + +---- + + + +[[howto-spring-mvc]] +== Spring MVC + + + +[[howto-write-a-json-rest-service]] +=== Write a JSON REST service +Any Spring `@RestController` in a Spring Boot application should render JSON response by +default as long as Jackson2 is on the classpath. For example: + +[source,java,indent=0,subs="verbatim,quotes,attributes"] +---- + @RestController + public class MyController { + + @RequestMapping("/thing") + public MyThing thing() { + return new MyThing(); + } + + } +---- + +As long as `MyThing` can be serialized by Jackson2 (e.g. a normal POJO or Groovy object) +then `http://localhost:8080/thing` will serve a JSON representation of it by default. +Sometimes in a browser you might see XML responses (but by default only if `MyThing` was +a JAXB object) because browsers tend to send accept headers that prefer XML. + + + +[[howto-customize-the-jackson-objectmapper]] +=== Customize the Jackson ObjectMapper +Spring MVC (client and server side) uses `HttpMessageConverters` to negotiate content +conversion in an HTTP exchange. If Jackson is on the classpath you already get a default +converter with a vanilla `ObjectMapper`. Spring Boot has some features to make it easier +to customize this behavior. + +The smallest change that might work is to just add beans of type +`com.fasterxml.jackson.databind.Module` to your context. They will be registered with the +default `ObjectMapper` and then injected into the default message converter. To replace +the default `ObjectMapper` completely, define a `@Bean` of that type and mark it as +`@Primary`. + +In addition, if your context contains any beans of type `ObjectMapper` then all of the +`Module` beans will be registered with all of the mappers. So there is a global mechanism +for contributing custom modules when you add new features to your application. + +Finally, if you provide any `@Beans` of type `MappingJackson2HttpMessageConverter` then +they will replace the default value in the MVC configuration. Also, a convenience bean is +provided of type `HttpMessageConverters` (always available if you use the default MVC +configuration) which has some useful methods to access the default and user-enhanced +message converters. + +See also the ``<>'' section and the +{sc-spring-boot-autoconfigure}/web/WebMvcAutoConfiguration.{sc-ext}[`WebMvcAutoConfiguration`] +source code for more details. + + + +[[howto-customize-the-responsebody-rendering]] +=== Customize the @ResponseBody rendering +Spring uses `HttpMessageConverters` to render `@ResponseBody` (or responses from +`@RestControllers`). You can contribute additional converters by simply adding beans of +that type in a Spring Boot context. If a bean you add is of a type that would have been +included by default anyway (like `MappingJackson2HttpMessageConverter` for JSON +conversions) then it will replace the default value. A convenience bean is provided of +type `HttpMessageConverters` (always available if you use the default MVC configuration) +which has some useful methods to access the default and user-enhanced message converters +(useful, for example if you want to manually inject them into a custom `RestTemplate`). + +As in normal MVC usage, any `WebMvcConfigurerAdapter` beans that you provide can also +contribute converters by overriding the `configureMessageConverters` method, but unlike +with normal MVC, you can supply only additional converters that you need (because Spring +Boot uses the same mechanism to contribute its defaults). Finally, if you opt-out of the +Spring Boot default MVC configuration by providing your own `@EnableWebMvc` configuration, +then you can take control completely and do everything manually using +`getMessageConverters` from `WebMvcConfigurationSupport`. + +See the {sc-spring-boot-autoconfigure}/web/WebMvcAutoConfiguration.{sc-ext}[`WebMvcAutoConfiguration`] +source code for more details. + + + +[[howto-switch-off-the-spring-mvc-dispatcherservlet]] +=== Switch off the Spring MVC DispatcherServlet +Spring Boot wants to serve all content from the root of your application `/` down. If you +would rather map your own servlet to that URL you can do it, but of course you may lose +some of the other Boot MVC features. To add your own servlet and map it to the root +resource just declare a `@Bean` of type `Servlet` and give it the special bean name +`dispatcherServlet` (You can also create a bean of a different type with that name if +you want to switch it off and not replace it). + + + +[[howto-switch-off-default-mvc-configuration]] +=== Switch off the Default MVC configuration +The easiest way to take complete control over MVC configuration is to provide your own +`@Configuration` with the `@EnableWebMvc` annotation. This will leave all MVC +configuration in your hands. + + + +[[howto-logging]] +== Logging + + + +[[howto-configure-logback-for-loggin]] +=== Configure Logback for logging +Spring Boot has no mandatory logging dependence, except for the `commons-logging` API, of +which there are many implementations to choose from. To use http://logback.qos.ch[Logback] +you need to include it, and some bindings for `commons-logging` on the classpath. The +simplest way to do that is through the starter poms which all depend on +`spring-boot-start-logging`. For a web application you only need +`spring-boot-starter-web` since it depends transitively on the logging starter. +For example, using Maven: + +[source,xml,indent=0,subs="verbatim,quotes,attributes"] +---- + + org.springframework.boot + spring-boot-starter-web + +---- + +Spring Boot has a `LoggingSystem` abstraction that attempts to select a system depending +on the contents of the classpath. If Logback is available it is the first choice. So if +you put a `logback.xml` in the root of your classpath it will be picked up from there. +Spring Boot provides a default base configuration that you can include if you just want +to set levels, e.g. + +[source,xml,indent=0,subs="verbatim,quotes,attributes"] +---- + + + + + +---- + +If you look at the default `logback.xml` in the spring-boot jar you will see that it uses +some useful System properties which the `LoggingSystem` takes care of creating for you. +These are: + +* `${PID}` the current process ID. +* `${LOG_FILE}` if `logging.file` was set in Boot's external configuration. +* `${LOG_PATH` if `logging.path` was set (representing a directory for + log files to live in). + +Spring Boot also provides some nice ANSI colour terminal output on a console (but not in +a log file) using a custom Logback converter. See the default `base.xml` configuration +for details. + +If Groovy is on the classpath you should be able to configure Logback with +`logback.groovy` as well (it will be given preference if present). + + + +[[howto-configure-log4j-for-logging]] +=== Configure Log4j for logging +Spring Boot supports http://logging.apache.org/log4j/1.x/[Log4j] for logging +configuration, but it has to be on the classpath. If you are using the starter poms for +assembling dependencies that means you have to exclude logback and then include log4j +back. If you aren't using the starter poms then you need to provide `commons-logging` +(at least) in addition to Log4j. + +The simplest path to using Log4j is probably through the starter poms, even though it +requires some jiggling with excludes, e.g. in Maven: + +[source,xml,indent=0,subs="verbatim,quotes,attributes"] +---- + + org.springframework.boot + spring-boot-starter-web + + + ${project.groupId} + spring-boot-starter-logging + + + + + org.springframework.boot + spring-boot-starter-log4j + +---- + +NOTE: The use of the log4j starter to gather together the dependencies for common logging +requirements (e.g. including having Tomcat use `java.util.logging` but configure the +output using Log4j). See the Actuator Log4j Sample for more detail and to see it in +action. + + + +[[howto-data-access]] +== Data Access + + + +[[howto-configure-a-datasource]] +=== Configure a DataSource +To override the default settings just define a `@Bean` of your own of type `DataSource`. +See ``<>'' in the +``<>'' section and the +{sc-spring-boot-autoconfigure}/jdbc/DataSourceAutoConfiguration.{sc-ext}[`DataSourceAutoConfiguration`] +class for more details. + + + +[[howto-use-spring-data-repositories]] +=== Use Spring Data repositories +Spring Data can create implementations for you of `@Repository` interfaces of various +flavours. Spring Boot will handle all of that for you as long as those `@Repositories` +are included in the same package (or a sub-package) of your `@EnableAutoConfiguration` +class. + +For many applications all you will need is to put the right Spring Data dependencies on +your classpath (there is a `spring-boot-starter-data-jpa` for JPA and for Mongodb you +only need to add `spring-datamongodb`), create some repository interfaces to handle your +`@Entity` objects. Examples are in the {github-code}/spring-boot-samples/spring-boot-sample-data-jpa[JPA sample] +or the {github-code}/spring-boot-samples/spring-boot-sample-data-mongodb[Mongodb sample]. + +Spring Boot tries to guess the location of your `@Repository` definitions, based on the +`@EnableAutoConfiguration` it finds. To get more control, use the `@EnableJpaRepositories` +annotation (from Spring Data JPA). + + + +[[howto-separate-entity-definitions-from-spring-configuration]] +=== Separate @Entity definitions from Spring configuration +Spring Boot tries to guess the location of your `@Entity` definitions, based on the +`@EnableAutoConfiguration` it finds. To get more control, you can use the `@EntityScan` +annotation, e.g. + +[source,java,indent=0,subs="verbatim,quotes,attributes"] +---- + @Configuration + @EnableAutoConfiguration + @EntityScan(basePackageClasses=City.class) + public class Application { + + //... + + } +---- + + + +[[howto-configure-jpa-properties]] +=== Configure JPA properties +Spring JPA already provides some vendor-independent configuration options (e.g. for SQL +logging) and Spring Boot exposes those, and a few more for hibernate as external +configuration properties. The most common options to set are: + +[indent=0,subs="verbatim,quotes,attributes"] +---- + spring.jpa.hibernate.ddl-auto: create-drop + spring.jpa.hibernate.naming_strategy: org.hibernate.cfg.ImprovedNamingStrategy + spring.jpa.database: H2 + spring.jpa.show-sql: true +---- + +(Because of relaxed data binding hyphens or underscores should work equally well as +property keys.) The `ddl-auto` setting is a special case in that it has different +defaults depending on whether you are using an embedded database (`create-drop`) or not +(`none`). In addition all properties in `spring.jpa.properties.*` are passed through as +normal JPA properties (with the prefix stripped) when the local `EntityManagerFactory` is +created. + +See {sc-spring-boot-autoconfigure}/orm/jpa/HibernateJpaAutoConfiguration.{sc-ext}[`HibernateJpaAutoConfiguration`] +and {sc-spring-boot-autoconfigure}/orm/jpa/JpaBaseConfiguration.{sc-ext}[`JpaBaseConfiguration`] +for more details. + + + +[[howto-use-traditional-persistence-xml]] +=== Use a traditional persistence.xml +Spring doesn't require the use of XML to configure the JPA provider, and Spring Boot +assumes you want to take advantage of that feature. If you prefer to use `persistence.xml` +then you need to define your own `@Bean` of type `LocalEntityManagerFactoryBean`, and set +the persistence unit name there. + +See +https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java[`JpaBaseConfiguration`] +for the default settings. + + + +[[howto-database-initialization]] +== Database initialization +An SQL database can be initialized in different ways depending on what your stack is. Or +of course you can do it manually as long as the database is in a server. + + + +[[howto-initialize-a-database-using-jpa]] +=== Initialize a database using JPA +JPA has features for DDL generation, and these can be set up to run on startup against the +database. This is controlled through two external properties: + +* `spring.jpa.generate-ddl` (boolean) switches the feature on and off and is vendor + independent. +* `spring.jpa.hibernate.ddl-auto` (enum) is a Hibernate feature that controls the + behavior in a more fine-grained way. See below for more detail. + + + +[[howto-initialize-a-database-using-hibernate]] +=== Initialize a database using Hibernate +You can set `spring.jpa.hibernate.ddl-auto` explicitly and the standard Hibernate property +values are `none`, `validate`, `update`, `create-drop`. Spring Boot chooses a default +value for you based on whether it thinks your database is embedded (default `create-drop`) +or not (default `none`). An embedded database is detected by looking at the `Connection` +type: `hsqldb`, `h2` and `derby` are embedded, the rest are not. Be careful when switching +from in-memory to a ``real'' database that you don't make assumptions about the existence of +the tables and data in the new platform. You either have to set `ddl-auto` expicitly, or +use one of the other mechanisms to initialize the database. + +In addition, a file named `import.sql` in the root of the classpath will be executed on +startup. This can be useful for demos and for testing if you are carefuil, but probably +not something you want to be on the classpath in production. It is a Hibernate feature +(nothing to do with Spring). + + + +[[howto-intialize-a-database-using-spring-jdbc]] +=== Initialize a database using Spring JDBC +Spring JDBC has a `DataSource` initializer feature. Spring Boot enables it by default and +loads SQL from the standard locations `schema.sql` and `data.sql` (in the root of the +classpath). In addition Spring Boot will load a file `schema-${platform}.sql` where +`platform` is the vendor name of the database (`hsqldb`, `h2`, `oracle`, `mysql`, +`postgresql` etc.). Spring Boot enables the failfast feature of the Spring JDBC +initializer by default, so if the scripts cause exceptions the application will fail. + +To disable the failfast you can set `spring.datasource.continueOnError=true`. This can be +useful once an application has matured and been deployed a few times, since the scripts +can act as ``poor man's migrations'' -- inserts that fail mean that the data is already +there, so there would be no need to prevent the application from running, for instance. + + + +[[howto-initialize-a-spring-batch-database]] +=== Initialize a Spring Batch database +If you are using Spring Batch then it comes pre-packaged with SQL initialization scripts +for most popular database platforms. Spring Boot will detect your database type, and +execute those scripts by default, and in this case will switch the fail fast setting to +false (errors are logged but do not prevent the application from starting). This is +because the scripts are known to be reliable and generally do not contain bugs, so errors +are ignorable, and ignoring them makes the scripts idempotent. You can switch off the +initialization explicitly using `spring.batch.initializer.enabled=false`. + + + +[[howto-use-a-higher-level-database-migration-tool]] +=== Use a higher level datababse migration tool +Spring Boot works fine with higher level migration tools http://flywaydb.org/[Flyway] +(SQL-based) and http://www.liquibase.org/[Liquibase] (XML). In general we prefer +Flyway because it is easier on the eyes, and it isn't very common to need platform +independence: usually only one or at most couple of platforms is needed. + + + +[[howto-batch-applications]] +== Batch applications + + + +[[howto-execute-spring-batch-jobs-on-startup]] +=== Execute Spring Batch jobs on startup +Spring Batch autoconfiguration is enabled by adding `@EnableBatchProcessing` +(from Spring Batch) somewhere in your context. + +By default it executes *all* `Jobs` in the application context on startup (see +{sc-spring-boot-autoconfigure}/batch/JobLauncherCommandLineRunner.{sc-ext}[JobLauncherCommandLineRunner] +for details). You can narrow down to a specific job or jobs by specifying +`spring.batch.job.names` (comma separated job name patterns). + +If the application context includes a `JobRegistry` then the jobs in +`spring.batch.job.names` are looked up in the registry instead of being autowired from the +context. This is a common pattern with more complex systems where multiple jobs are +defined in child contexts and registered centrally. + +See +{sc-spring-boot-autoconfigure}/batch/BatchAutoConfiguration.{sc-ext}[BatchAutoConfiguration] +and +https://github.com/spring-projects/spring-batch/blob/master/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/EnableBatchProcessing.java[@EnableBatchProcessing] +for more details. + + + +[[howto-actuator]] +== Actuator + + + +[[howto-change-the-http-port-or-address-of-the-actuator-endpoints]] +=== Change the HTTP port or address of the actuator endpoints +In a standalone application the Actuator HTTP port defaults to the same as the main HTTP +port. To make the application listen on a different port set the external property +`management.port`. To listen on a completely different network address (e.g. if you have +an internal network for management and an external one for user applications) you can +also set `management.address` to a valid IP address that the server is able to bind to. + +For more detail look at the +{sc-spring-boot-actuator}/autoconfigure/ManagementServerProperties.{sc-ext}[`ManagementServerProperties`] +source code and +``<>'' +in the ``<>'' section. + + + +[[howto-customize-the-whitelabel-error-page]] +=== Customize the ``whitelabel'' error page +The Actuator installs a ``whitelabel'' error page that you will see in browser client if +you encounter a server error (machine clients consuming JSON and other media types should +see a sensible response with the right error code). To switch it off you can set +`error.whitelabel.enabled=false`, but normally in addition or alternatively to that you +will want to add your own error page replacing the whitelabel one. If you are using +Thymeleaf you can do this by adding an `error.html` template. In general what you need is +a `View` that resolves with a name of `error`, and/or a `@Controller` that handles the +`/error` path. Unless you replaced some of the default configuration you should find a +`BeanNameViewResolver` in your `ApplicationContext` so a `@Bean` with id `error` would be +a simple way of doing that. +Look at {sc-spring-boot-actuator}/autoconfigure/ErrorMvcAutoConfiguration.{sc-ext}[`ErrorMvcAutoConfiguration`] for more options. + + + +[[howto-security]] +== Security + + + +[[howto-secure-an-application]] +=== Secure an application +If Spring Security is on the classpath then web applications will be secure by default +(``basic'' authentication on all endpoints) . To add method-level security to a web +application you can simply `@EnableGlobalMethodSecurity` with your desired settings. + +The default `AuthenticationManager` has a single user (username ``user'' and password +random, printed at INFO when the application starts up). You can change the password by +providing a `security.user.password`. This and other useful properties are externalized +via `SecurityProperties`. + + + +[[howto-switch-off-spring-boot-security-configuration]] +=== Switch off the Spring Boot security configuration +If you define a `@Configuration` with `@EnableWebSecurity` anywhere in your application +it will switch off the default webapp security settings in Spring Boot. To tweak the +defaults try setting properties in `security.*` (see +{sc-spring-boot-autoconfigure}/security/SecurityProperties.{sc-ext}[`SecurityProperties`] +for details of available settings). + + + +[[howto-change-the-authenticationmanager-and-add-user-accounts]] +=== Change the AuthenticationManager and add user accounts +If you provide a `@Bean` of type `AuthenticationManager` the default one will not be +created, so you have the full feature set of Spring Security available (e.g. +http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#jc-authentication[various authentication options]). + +Spring Security also provides a convenient `AuthenticationManagerBuilder` which can be +used to build an `AuthenticationManager` with common options. The recommended way to +use this in a webapp is to inject it into a void method in a +`WebSecurityConfigurerAdapter`, e.g. + +[source,java,indent=0,subs="verbatim,quotes,attributes"] +---- + @Configuration + @Order(0) + public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Autowired + protected void init(AuthenticationManagerBuilder builder) { + builder.inMemoryAuthentication().withUser("barry"); // ... etc. + } + + // ... other stuff for application security + + } +---- + +The configuration class that does this should declare an `@Order` so that it is used +before the default one in Spring Boot (which has very low precedence). + + + +[[howto-enable-https]] +=== Enable HTTPS +Ensuring that all your main endpoints are only available over HTTPS is an important +chore for any application. If you are using Tomcat as a servlet container, then the +Spring Boot will add Tomcat's own `RemoteIpValve` automatically if it detects some +environment settings, and you should be able to rely on the `HttpServletRequest` to +report whether or not it is secure (even downstream of the real SSL termination). The +standard behavior is determined by the presence or absence of certain request headers +(`x-forwarded-for` and `x-forwarded-proto`), whose names are conventional, so it should +work with most front end proxies. You switch on the valve by adding some entries to +`application.properties`, e.g. + +[indent=0] +---- + server.tomcat.remote_ip_header: x-forwarded-for + server.tomcat.protocol_header: x-forwarded-proto +---- + +(The presence of either of those properties will switch on the valve. Or you can add the +`RemoteIpValve` yourself by adding a `TomcatEmbeddedServletContainerFactory` bean.) + +Spring Security can also be configured to require a secure channel for all (or some +requests). To switch that on in a Spring Boot application you just need to set +`security.require_https` to `true` in `application.properties`. + + + +[[howto-hotswapping]] +== Hot swapping + + + +[[howto-reload-static-content]] +=== Reload static content +There are several options for hot reloading. Running in an IDE (especially with debugging +on) is a good way to do development (all modern IDEs allow reloading of static resources +and usually also hot-swapping of Java class changes). The +<> also +support running from the command line with reloading of static files. You can use that +with an external css/js compiler process if you are writing that code with higher level +tools. + + + +[[howto-reload-thymeleaf-content]] +=== Reload Thymeleaf templates without restarting the container +If you are using Thymeleaf, then set `spring.thymeleaf.cache` to `false`. See +{sc-spring-boot-autoconfigure}/thymeleaf/ThymeleafAutoConfiguration.{sc-ext}[`ThymeleafAutoConfiguration`] +for other template customization options. + + + +[[howto-reload-java-classes-without-restarting]] +=== Reload Java classes without restarting the container +Modern IDEs (Eclipse, IDEA etc.) all support hot swapping of bytecode, so if you make a +change that doesn't affect class or method signatures it should reload cleanly with no +side effects. + +https://github.com/spring-projects/spring-loaded[Spring Loaded] goes a little further in +that it can reload class definitions with changes in the method signatures. With some +customization it can force an `ApplicationContext` to refresh itself (but there is no +general mechanism to ensure that would be safe for a running application anyway, so it +would only ever be a development time trick probably). + + + +[[howto-build]] +== Build + + + +[[howto-build-an-executable-archive-with-ant]] +=== Build an executable archive with Ant +To build with Ant you need to grab dependencies and compile and then create a jar or war +archive as normal. To make it executable: + +. Use the appropriate launcher as a `Main-Class`, e.g. `JarLauncher` for a jar file, and + specify the other properties it needs as manifest entries, principally a `Start-Class`. + +. Add the runtime dependencies in a nested "lib" directory (for a jar) and the + `provided` (embedded container) dependencies in a nested `lib-provided` directory. + Remember *not* to compress the entries in the archive. + +. Add the `spring-boot-loader` classes at the root of the archive (so the `Main-Class` + is available). + +Example: + +[source,xml,indent=0,subs="verbatim,quotes,attributes"] +---- + + + + + + + + + + + + + + +---- + +The Actuator Sample has a `build.xml` that should work if you run it with + +[indent=0,subs="verbatim,quotes,attributes"] +---- + $ ant -lib /ivy-2.2.jar +---- + +after which you can run the application with + +[indent=0,subs="verbatim,quotes,attributes"] +---- + $ java -jar target/*.jar +---- + + + +[[howto-traditional-deployment]] +== Traditional deployment + + + +[[howto-create-a-deployable-war-file]] +=== Create a deployable war file +Use the `SpringBootServletInitializer` base class, which is picked up by Spring's +Servlet 3.0 support on deployment. Add an extension of that to your project and build a +war file as normal. For more detail, see the +http://spring.io/guides/gs/convert-jar-to-war[``Converting a jar Project to a war''] guide +on the spring.io website. + +The war file can also be executable if you use the Spring Boot build tools. In that case +the embedded container classes (to launch Tomcat for instance) have to be added to the +war in a `lib-provided` directory. The tools will take care of that as long as the +dependencies are marked as "provided" in Maven or Gradle. Here's a Maven example +{github-code}/spring-boot-samples/spring-boot-sample-traditional/pom.xml[in the Boot Samples]. + + + +[[howto-create-a-deployable-war-file-for-older-containers]] +=== Create a deployable war file for older servlet containers +Older Servlet containers don't have support for the `ServletContextInitializer` bootstrap +process used in Servlet 3.0. You can still use Spring and Spring Boot in these containers +but you are going to need to add a `web.xml` to your application and configure it to load +an `ApplicationContext` via a `DispatcherServlet`. + + + +[[howto-convert-an-existing-application-to-spring-boot]] +=== Convert an existing application to Spring Boot +For a non-web application it should be easy (throw away the code that creates your +`ApplicationContext` and replace it with calls to `SpringApplication` or +`SpringApplicationBuilder`). Spring MVC web applications are generally amenable to first +creating a deployable war application, and then migrating it later to an executable war +and/or jar. Useful reading is in the http://spring.io/guides/gs/convert-jar-to-war/[Getting +Started Guide on Converting a jar to a war]. + +Create a deployable war by extending `SpringBootServletInitializer` (e.g. in a class +called `Application`), and add the Spring Boot `@EnableAutoConfiguration` annotation. +Example: + +[source,java,indent=0,subs="verbatim,quotes,attributes"] +---- + @Configuration + @EnableAutoConfiguration + @ComponentScan + public class Application extends SpringBootServletInitializer { + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(Application.class); + } + + } +---- + +Remember that whatever you put in the `sources` is just a Spring `ApplicationContext` and +normally anything that already works should work here. There might be some beans you can +remove later and let Spring Boot provide its own defaults for them, but it should be +possible to get something working first. + +Static resources can be moved to `/public` (or `/static` or `/resources` or +`/META-INFO/resources`) in the classpath root. Same for `messages.properties` (Spring Boot +detects this automatically in the root of the classpath). + +Vanilla usage of Spring `DispatcherServlet` and Spring Security should require no further +changes. If you have other features in your application, using other servlets or filters, +for instance then you may need to add some configuration to your `Application` context, +replacing those elements from the `web.xml` as follows: + +* A `@Bean` of type `Servlet` or `ServletRegistrationBean` installs that bean in the + container as if it was a `` and `` in `web.xml`. +* A `@Bean` of type `Filter` or `FilterRegistrationBean` behaves similarly (like a + `` and ``. +* An `ApplicationContext` in an XML file can be added to an `@Import` in your + `Application`. Or simple cases where annotation configuration is heavily used already + can be recreated in a few lines as `@Bean` definitions. + +Once the war is working we make it executable by adding a `main` method to our +`Application`, e.g. + +[source,java,indent=0,subs="verbatim,quotes,attributes"] +---- + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +---- + +Applications can fall into more than one category: + +* Servlet 3.0 applications with no `web.xml`. +* Applications with a `web.xml`. +* Applications with a context hierarchy. +* Applications without a context hierarchy. + +All of these should be amenable to translation, but each might require slightly different +tricks. + +Servlet 3.0 applications might translate pretty easily if they already use the Spring +Servlet 3.0 initializer support classes. Normally all the code from an existing +`WebApplicationInitializer` can be moved into a `SpringBootServletInitializer`. If your +existing application has more than one `ApplicationContext` (e.g. if it uses +`AbstractDispatcherServletInitializer`) then you might be able to squash all your context +sources into a single `SpringApplication`. The main complication you might encounter is if +that doesn't work and you need to maintain the context hierarchy. See the +<> for +examples. An existing parent context that contains web-specific features will usually +need to be broken up so that all the `ServletContextAware` components are in the child +context. + +Applications that are not already Spring applications might be convertible to a Spring +Boot application, and the guidance above might help, but your mileage may vary. diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 5dfc7790d55..dc3955f3fd0 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -291,7 +291,8 @@ properties). ---- TIP: You can also use this technique to create ``short'' variants of existing Spring Boot -properties. +properties. See the ``<>'' how-to +for details. From a1a62785be9de41af59dc786f854dd55aa036d3e Mon Sep 17 00:00:00 2001 From: Josh Long Date: Thu, 13 Mar 2014 13:25:33 -0700 Subject: [PATCH 4/4] Add cloud deployment documentation Add a "cloud deployment" section to the Spring Boot reference manual. See gh-295 --- .../src/main/asciidoc/cloud-deployment.adoc | 245 ++++++++++++++++++ .../main/asciidoc/documentation-overview.adoc | 4 + spring-boot-docs/src/main/asciidoc/index.adoc | 3 +- .../asciidoc/production-ready-features.adoc | 4 +- 4 files changed, 254 insertions(+), 2 deletions(-) create mode 100644 spring-boot-docs/src/main/asciidoc/cloud-deployment.adoc diff --git a/spring-boot-docs/src/main/asciidoc/cloud-deployment.adoc b/spring-boot-docs/src/main/asciidoc/cloud-deployment.adoc new file mode 100644 index 00000000000..c133673193b --- /dev/null +++ b/spring-boot-docs/src/main/asciidoc/cloud-deployment.adoc @@ -0,0 +1,245 @@ +[[cloud-deployment]] += Deploying to the cloud + +[partintro] +-- +Spring Boot's executable jars are ready-made for most popular cloud PaaS +(platform-as-a-service) providers. These providers tend to require that you +_`bring your own container'_; they manage application processes (not Java applications +specifically), so they need some intermediary layer that adapts _your_ application to the +_cloud's_ notion of a running process. + +Two popular cloud providers, Heroku and Cloud Foundry, employ a ``buildpack'' approach. +The buildpack wraps your deployed code in whatever is needed to _start_ your +application: it might be a JDK and a call to `java`, it might be an embedded webserver, +or it might be a full fledged application server. A buildpack is pluggable, but ideally +you should be able to get by with as few customizations to it as possible. +This reduces the footprint of functionality that is not under your control. It minimizes +divergence between deployment and production environments. + +Ideally, your application, like a Spring Boot executable jar, has everything that it needs +to run packaged within it. + +In this section we'll look at what it takes to get the +<> in the ``Getting Started'' section up and running in the Cloud. +-- + + + +[[cloud-deployment-cloud-foundry]] +== Cloud Foundry +Cloud Foundry provides default buildpacks that come into play if no other buildpack is +specified. The Cloud Foundry buildpack has excellent support for Spring applications, +including Spring Boot. You can deploy stand-alone executable jar applications, as well as +traditional `war` packaged applications. + +Once you've built your application (using, for example, `mvn clean install`) and +http://docs.cloudfoundry.org/devguide/installcf/[installed the `cf` command line tool], +simply answer the `cf push` command's prompts as follows: + +[indent=0,subs="verbatim,quotes,attributes"] +---- + $ cf push --path target/demo-0.0.1-SNAPSHOT.jar + + Name> *_$YOURAPP_* + Instances> *1* + Memory Limit> *256M* + + Creating _$YOURAPP_... *OK* + + 1: _$YOURAPP_ + 2: none + Subdomain> *_$YOURAPP_* + + 1: cfapps.io + 2: none + Domain> *cfapps.io* + + Creating route _$YOURAPP_.cfapps.io... OK + Binding _$YOURAPP_.cfapps.io to _$YOURAPP_... OK + + Create services for application?> *n* + Bind other services to application?> *n* + Save configuration?> *y* +---- + +At this point `cf` will start uploading your application: + +[indent=0,subs="verbatim,quotes,attributes"] +---- + Saving to manifest.yml... *OK* + Uploading $YOURAPP... *OK* + Preparing to start _$YOURAPP_... *OK* + -----> Downloaded app package (8.7M) + -----> Java Buildpack source: system + -----> Downloading Open JDK 1.7.0_51 from .../openjdk-1.7.0_51.tar.gz (*1.4s*) + Expanding Open JDK to .java-buildpack/open_jdk (*1.3s*) + -----> Downloading Spring Auto Reconfiguration 0.8.7 from .../auto-reconfiguration-0.8.7.jar (*0.0s*) + -----> Uploading droplet (*43M*) + Checking status of app '_$YOURAPP_'... + 0 of 1 instances running (1 starting) + 0 of 1 instances running (1 starting) + 1 of 1 instances running (1 running) + Push successful! App '_$YOURAPP_' available at http://_$YOURAPP_.cfapps.io +---- + +NOTE: Here we are substituting `$YOURAPP` for whatever value you give `cf` when it asks +for the `name` of your application. + +Once Cloud Foundry acknowledges that your application has been deployed, you should be +able to hit the application at the URI provided: +`http://$YOURAPP.cfapps.io/`. + + + +[[cloud-deployment-cloud-foundry-services]] +=== Binding to services +By default, meta-data about the running application as well as service connection +information is exposed to the application as environment variables (for example: +`$VCAP_SERVICES`). This architecture decision is due to Cloud Foundry's polyglot +(any language and platform can be supported as a buildpack) nature; process-scoped +environment variables are language agnostic. + +Environment variables don't always make for the easiest API so Spring Boot automatically +extracts then and flattens the data into properties that can be accessed through +Spring's `Environment` abstraction: + +[source,java,indent=0] +---- + @Component + class MyBean implements EnvironmentAware { + + private String instanceId; + + @Override + public void setEnvironment(Environment environment) { + this.instanceId = environment.getProperty("vcap.application.instance_id"); + } + + // ... + + } +---- + +All Cloud Foundry properties are prefixed with `vcap`. You can use vcap properties to +access application information (such as the public URL of the application) and service +information (such as database credentials). See `VcapApplicationListener` Javdoc for +complete details. + +TIP: The http://spring.io/projects/spring-cloud[Spring Cloud] project is a better fit +for tasks such as configuring a DataSource; and you can also use Spring Cloud with +Heroku too! + + + +[[cloud-deployment-heroku]] +== Heroku +Heroku is another popular PaaS platform. To customize Heroku builds, you provide a +`Procfile`, which provides the incantation required to deploy an application. Heroku +assigns a `port` for the Java application to use and then ensures that routing to the +external URI works. + +You must configure your application to listen on the correct port. This is a breeze with +Spring Boot. Here's the `Procfile` for our starter REST application: + +[indent=0] +---- + web: java -Dserver.port=$PORT -jar target/demo-0.0.1-SNAPSHOT.jar +---- + +Spring Boot makes `-D` arguments available as properties accessible from a Spring +`Environment` instance. The `server.port` configuration property is fed to the embedded +Tomcat or Jetty instance which then uses it when it starts up. The `$PORT` environment +variable is assigned to us by the Heroku PaaS. + +Heroku by default will use Java 1.6. This is fine as long as your Maven or Gradle build +is set to use the same version (Maven users can use the `java.version` property). If you +want to use JDK 1.7, create a new file adjacent to your `pom.xml` and `Procfile`, +called `system.properties`. In this file add the following: + +[source,java] +---- +java.runtime.version=1.7 +---- + +This should be everything you need. The most common workflow for Heroku deployments is to +`git push` the code to production. + +[indent=0,subs="verbatim,quotes,attributes"] +---- + $ git push heroku master + + Initializing repository, *done*. + Counting objects: 95, *done*. + Delta compression using up to 8 threads. + Compressing objects: 100% (78/78), *done*. + Writing objects: 100% (95/95), 8.66 MiB | 606.00 KiB/s, *done*. + Total 95 (delta 31), reused 0 (delta 0) + + -----> Java app detected + -----> Installing OpenJDK 1.7... *done* + -----> Installing Maven 3.0.3... *done* + -----> Installing settings.xml... *done* + -----> executing /app/tmp/cache/.maven/bin/mvn -B + -Duser.home=/tmp/build_0c35a5d2-a067-4abc-a232-14b1fb7a8229 + -Dmaven.repo.local=/app/tmp/cache/.m2/repository + -s /app/tmp/cache/.m2/settings.xml -DskipTests=true clean install + + [INFO] Scanning for projects... + Downloading: http://repo.spring.io/... + Downloaded: http://repo.spring.io/... (818 B at 1.8 KB/sec) + .... + Downloaded: http://s3pository.heroku.com/jvm/... (152 KB at 595.3 KB/sec) + [INFO] Installing /tmp/build_0c35a5d2-a067-4abc-a232-14b1fb7a8229/target/... + [INFO] Installing /tmp/build_0c35a5d2-a067-4abc-a232-14b1fb7a8229/pom.xml ... + [INFO] ------------------------------------------------------------------------ + [INFO] *BUILD SUCCESS* + [INFO] ------------------------------------------------------------------------ + [INFO] Total time: 59.358s + [INFO] Finished at: Fri Mar 07 07:28:25 UTC 2014 + [INFO] Final Memory: 20M/493M + [INFO] ------------------------------------------------------------------------ + + -----> Discovering process types + Procfile declares types -> *web* + + -----> Compressing... *done*, 70.4MB + -----> Launching... *done*, v6 + http://agile-sierra-1405.herokuapp.com/ *deployed to Heroku* + + To git@heroku.com:agile-sierra-1405.git + * [new branch] master -> master +---- + +That should be it! Your application should be up and running on Heroku. + + + +[[cloud-deployment-cloudbees]] +== CloudBees +CloudBees provides cloud-based ``continuous integration'' and ``continuous delevery'' +services as well as Java PaaS hosting. https://github.com/msgilligan[Sean Gilligan] +has contributed an excellent +https://github.com/CloudBees-community/springboot-gradle-cloudbees-sample[Spring Boot +sample application] to the CloudBees community GitHub repository. The project includes +an extensive https://github.com/CloudBees-community/springboot-gradle-cloudbees-sample/blob/master/README.asciidoc[README] +that covers the steps that you need to follow when deploying to CloudBees. + + + +[[cloud-deployment-whats-next]] +== What to read next +Check out the http://www.cloudfoundry.com/[Cloud Foundry], https://www.heroku.com/[Heroku] +and http://www.cloudbees.com[CloudBees] web sites for more information about the kinds of +features that a PaaS can offer. These are just three of the more popular Java PaaS +providers, since Spring Boot is so amenable to cloud-based deployment you free to +consider other providers as well. + +The next section goes on to cover the <>; +or you can jump ahead to read about +<>. + + + + diff --git a/spring-boot-docs/src/main/asciidoc/documentation-overview.adoc b/spring-boot-docs/src/main/asciidoc/documentation-overview.adoc index 3292b6788e9..524e2cb13c4 100644 --- a/spring-boot-docs/src/main/asciidoc/documentation-overview.adoc +++ b/spring-boot-docs/src/main/asciidoc/documentation-overview.adoc @@ -110,6 +110,10 @@ When your ready to push your Spring Boot application to production, we've got == Advanced topics Lastly, we have a few topics for the more advanced user. +* *Deploy to the cloud:* +<> | +<> | +<> * *Build tool plugins:* <> | <> diff --git a/spring-boot-docs/src/main/asciidoc/index.adoc b/spring-boot-docs/src/main/asciidoc/index.adoc index 607b2dd214c..a0264a15421 100644 --- a/spring-boot-docs/src/main/asciidoc/index.adoc +++ b/spring-boot-docs/src/main/asciidoc/index.adoc @@ -1,5 +1,5 @@ = Spring Boot Reference Guide -Phillip Webb; Dave Syer; +Phillip Webb; Dave Syer; Josh Long; :doctype: book :toc: :toclevels: 4 @@ -33,6 +33,7 @@ include::getting-started.adoc[] include::using-spring-boot.adoc[] include::spring-boot-features.adoc[] include::production-ready-features.adoc[] +include::cloud-deployment.adoc[] include::spring-boot-cli.adoc[] include::build-tool-plugins.adoc[] include::howto.adoc[] diff --git a/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 57545d6ea4d..5da6cea8147 100644 --- a/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -743,5 +743,7 @@ If you want to explore some of the concepts discussed in this chapter, you can t look at the actuator {github-code}/spring-boot-samples[sample applications]. You also might want to read about graphing tools such as http://graphite.wikidot.com/[Graphite]. -Otherwise, you can continue on, to read about Spring Boot's +Otherwise, you can continue on, to read about <> or jump ahead +for some in depth information about Spring Boot's <>.