Getting Started with Spring MVC Hibernate on Heroku

Last Updated: 27 March 2014

java

Table of Contents

This quickstart will get you going with a Spring MVC Hibernate application that uses a Postgres database service, deployed to Heroku. For general information on how to develop and architect apps for use on Heroku, see Architecting Applications for Heroku.

If you have questions about Java on Heroku, consider discussing them in the Java on Heroku forums.

Sample code for the demo application is available on GitHub. Edits and enhancements are welcome. Just fork the repository, make your changes and send us a pull request.

Prerequisites

Create a Java app that uses Spring MVC and Hibernate

If you don’t already have a Spring MVC Hibernate app, the easiest way to create one is with Spring Roo. Spring Roo is a RAD tool that lets you quickly build Spring MVC applications with a complete model, view and controller layer, including relational database integration.

Option 1. Clone the sample app

If you don’t want to install Spring Roo, you can clone the sample app:

$ git clone https://github.com/heroku/devcenter-spring-mvc-hibernate.git
Cloning into petclinic...
remote: Counting objects: 205, done.
remote: Compressing objects: 100% (100/100), done.
remote: Total 205 (delta 93), reused 205 (delta 93)
Receiving objects: 100% (205/205), 98.55 KiB, done.
Resolving deltas: 100% (93/93), done.

This will check out the completed app. To step back to the starting point, do:

$ git revert starting-point

Now you can skip forward to “Modify Database Configuration”.

Option 2. Create the app using Spring Roo

Install Spring Roo if you don’t already have it. Then create a directory for your app and generate the app using the clinic.roo script:

$ mkdir petclinic && cd petclinic
$ roo script --file clinic.roo

   / __ \/ __ \/ __ \
  / /_/ / / / / / / /
 / _, _/ /_/ / /_/ /
/_/ |_|\____/\____/    1.1.4.RELEASE [rev f787ce7]


Welcome to Spring Roo. For assistance press TAB or type "hint" then hit ENTER.
project --topLevelPackage com.springsource.petclinic
Created ROOT/pom.xml
Created SRC_MAIN_JAVA
Created SRC_MAIN_RESOURCES
...
Updated SRC_MAIN_RESOURCES/log4j.properties
Script required 41 second(s) to execute

By default, the generated app sets up the Hypersonic in-memory database. However, it is strongly recommended to use the same database locally as in production. So we will switch the application over to using Postgres with this Roo command:

$ roo persistence setup --provider HIBERNATE --database POSTGRES
...
Updated SRC_MAIN_RESOURCES/META-INF/spring/database.properties
Please update your database details in src/main/resources/META-INF/spring/database.properties.
Updated ROOT/pom.xml [removed dependency org.hsqldb:hsqldb:1.8.0.10; added dependency postgresql:postgresql:8.4-702.jdbc3]
Updated SRC_MAIN_RESOURCES/META-INF/spring/applicationContext.xml
Updated SRC_MAIN_RESOURCES/META-INF/persistence.xml
...

Finally, let’s create a git repo and commit this baseline of our application:

$ git init
$ echo target > .gitignore
$ git add .
$ git commit -m init

Modify database configuration

The web app generated by Spring Roo expects you to set database connection properties in the file src/main/resources/META-INF/spring/database.properties. However, it is not a good idea to hardcode database configuration into a file that is part of your project. Instead, we will edit the Spring configuration to read the configuration from an environment variable.

Heroku automatically provisions a small database when you create a Java application and sets the DATABASE_URL environment variable to a URL of the format

postgres://user:password@hostname:port/dbname

You can also provision a larger database service yourself using the heroku addons command. Either way, the database connection information will be stored in the DATABASE_URL variable.

Create a new URI spring bean initialized with this environment variable by adding this to src/main/resources/META-INF/spring/applicationContext.xml:

<bean class="java.net.URI" id="dbUrl">
    <constructor-arg value="${DATABASE_URL}"/>
</bean>

Edit the dataSource section in src/main/resources/META-INF/spring/applicationContext.xml and replace the property place holders with the following:

<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
    <property name="driverClassName" value="${database.driverClassName}"/>
    <property name="url" value="#{ 'jdbc:postgresql://' + @dbUrl.getHost() + ':' + @dbUrl.getPort() + @dbUrl.getPath() }"/>
    <property name="username" value="#{ @dbUrl.getUserInfo().split(':')[0] }"/>
    <property name="password" value="#{ @dbUrl.getUserInfo().split(':')[1] }"/>
    ...

To run your app locally set the DATABASE_URL variable in your local environment to point to your local postgres database, for example:

$ export DATABASE_URL=postgres://scott:tiger@localhost:5432/myapp

Add Jetty Runner

Jetty Runner lets you easily execute your web app as a standard Java application (without having to deploy it to a container). It’s a simple jar that you can copy down from the central Maven repository to the target directory as part of you build. We’ll use the maven-dependency-plugin to do this by adding the following plugin configuration at the end of the plugins section of pom.xml:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.3</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals><goal>copy</goal></goals>
            <configuration>
                <artifactItems>
                    <artifactItem>
                        <groupId>org.mortbay.jetty</groupId>
                        <artifactId>jetty-runner</artifactId>
                        <version>7.4.5.v20110725</version>
                        <destFileName>jetty-runner.jar</destFileName>
                    </artifactItem>
                </artifactItems>
            </configuration>
        </execution>
    </executions>
</plugin>

Declare process types with Procfile

Use a Procfile, a text file in the root directory of your application, to explicitly declare what command should be executed to start a web dyno. In this case, you want to execute the Jetty Runner.

Here’s a Procfile for the sample app we’ve been working on:

web: java $JAVA_OPTS -jar target/dependency/jetty-runner.jar --port $PORT target/*.war

This declares a single process type, web, and the command needed to run it. The name “web” is important here. It declares that this process type will be attached to the HTTP routing stack of Heroku, and receive web traffic when deployed.

Optionally Choose a JDK

By default, OpenJDK 1.6 is installed with your app. However, you can choose to use a newer JDK by specifying java.runtime.version=1.7 in the system.properties file.

Here’s what a system.properties file looks like:

java.runtime.version=1.7

You can specify 1.6, 1.7, or 1.8 (1.8 is in beta) for Java 6, 7, or 8 (with lambdas), respectively.

Run your app locally

Let’s run the app locally first to test that it all works. You must have a Postgres database up and running and accessible on the DATABASE_URL you specified above.

Build your app

$ mvn package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building petclinic 0.1.0.BUILD-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
...
[INFO] --- maven-dependency-plugin:2.3:copy (default) @ petclinic ---
[INFO] Configured Artifact: org.mortbay.jetty:jetty-runner:7.4.5.v20110725:jar
[INFO] Copying jetty-runner-7.4.5.v20110725.jar to /Users/jjoergensen/dev/tmp/spring-roo-petclinic/target/dependency/jetty-runner.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 20.466s
[INFO] Finished at: Mon Aug 29 20:56:03 PDT 2011
[INFO] Final Memory: 9M/81M
[INFO] ------------------------------------------------------------------------

Start your app

Note: you can also start your app using foreman to execute the Procfile. Read more about foreman and Procfiles.

$ java -jar target/dependency/jetty-runner.jar target/*.war

Test it

Go to http://localhost:8080 and test it out by creating a new record.

Store your app in Git

We now have the application with it’s dependencies declared in pom.xml, and a Procfile. Let’s put it into Git:

$ git add .
$ git commit -m "Ready to deploy"

Deploy your application to Heroku

Create the app:

$ heroku create
Creating high-lightning-129... done, stack is cedar
http://high-lightning-129.herokuapp.com/ | git@heroku.com:high-lightning-129.git
Git remote heroku added

Deploy your code:

$ git push heroku master
Counting objects: 227, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (117/117), done.
Writing objects: 100% (227/227), 101.06 KiB, done.
Total 227 (delta 99), reused 220 (delta 98)

-----> Heroku receiving push
-----> Java app detected
-----> Installing Maven 3.0.3..... done
-----> Installing settings.xml..... done
-----> executing .maven/bin/mvn -B -Duser.home=/tmp/build_1jems2so86ck4 -s .m2/settings.xml -DskipTests=true clean install
       [INFO] Scanning for projects...
       [INFO]
       [INFO] ------------------------------------------------------------------------
       [INFO] Building petclinic 0.1.0.BUILD-SNAPSHOT
       [INFO] ------------------------------------------------------------------------
       ...
       [INFO] ------------------------------------------------------------------------
       [INFO] BUILD SUCCESS
       [INFO] ------------------------------------------------------------------------
       [INFO] Total time: 36.612s
       [INFO] Finished at: Tue Aug 30 04:03:02 UTC 2011
       [INFO] Final Memory: 19M/287M
       [INFO] ------------------------------------------------------------------------
-----> Discovering process types
       Procfile declares types -> web
-----> Compiled slug size is 62.7MB
-----> Launching... done, v5
       http://pure-window-800.herokuapp.com deployed to Heroku

Congratulations! Your web app should now be up and running on Heroku.

Visit your application

You’ve deployed your code to Heroku, and specified the process types in a Procfile. You can now instruct Heroku to execute a process type. Heroku does this by running the associated command in a dyno - a lightweight container which is the basic unit of composition on Heroku.

Let’s ensure we have one dyno running the web process type:

$ heroku ps:scale web=1

You can check the state of the app’s dynos. The heroku ps command lists the running dynos of your application:

$ heroku ps
=== web: `java $JAVA_OPTS -jar target/dependency/jetty-runner.jar --port $PORT target/*.war`
web.1: up for 6m

Here, one dyno is running.

We can now visit the app in our browser with heroku open.

$ heroku open
Opening pure-window-800... done

Dyno sleeping and scaling

Having only a single web dyno running will result in the dyno going to sleep after one hour of inactivity. This causes a delay of a few seconds for the first request upon waking. Subsequent requests will perform normally.

To avoid this, you can scale to more than one web dyno. For example:

$ heroku ps:scale web=2

For each application, Heroku provides 750 free dyno-hours. Running your app at 2 dynos would exceed this free, monthly allowance, so let’s scale back:

$ heroku ps:scale web=1

View the logs

Heroku treats logs as streams of time-ordered events aggregated from the output streams of all the dynos running the components of your application. Heroku’s Logplex provides a single channel for all of these events.

View information about your running app using one of the logging commands, heroku logs:

$ heroku logs
...
2012-09-11T19:12:27+00:00 app[web.1]: 2012-09-11 19:12:27,217 [main] INFO org.springframework.web.servlet.DispatcherServlet - FrameworkServlet 'petclinic': initialization completed in 573 ms
2012-09-11T19:12:27+00:00 app[web.1]: 2012-09-11 19:12:27.240:INFO::Started SelectChannelConnector@0.0.0.0:38895 STARTING
2012-09-11T19:12:28+00:00 heroku[web.1]: State changed from starting to up

Next steps

  • Visit the Java category to learn more about developing and deploying Java applications.
  • Read How Heroku Works for a technical overview of the concepts you’ll encounter while writing, configuring, deploying and running applications.