Spring Standalone Project

27 August 2014

Creating a Spring standalone application is a challenge to me without using Spring Boot. I used to have web.xml to bootstrap my application but being standalone left me thinking which XML or configuration file will bootstrap it.

I'm prototyping maven-archetype-generate and will add Spring dependencies later on hoping I will achieve my goal.

mvn archetype:generate

$ mvn archetype:generate -DgroupId=com.manalo.rabbitmq -DartifactId=rabbitmq -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom
[INFO]
[INFO] maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom
[INFO]
[INFO] --- maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Batch mode
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-quickstart:1.0
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: com.manalo.rabbitmq
[INFO] Parameter: packageName, Value: com.manalo.rabbitmq
[INFO] Parameter: package, Value: com.manalo.rabbitmq
[INFO] Parameter: artifactId, Value: rabbitmq
[INFO] Parameter: basedir, Value: /home/drmanalo/workspace
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: /home/drmanalo/workspace/rabbitmq
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1:54.171s
[INFO] Finished at: Wed Aug 26 19:34:57 BST 2014
[INFO] Final Memory: 14M/150M
[INFO] ------------------------------------------------------------------------

mvn eclipse:eclipse

I guess we all need a decent IDE to edit our Java codes therefore run mvn eclipse:eclipse within the root folder where pom.xml resides to download all the dependencies and prepare an importable Eclipse project. You can use mvn eclipse:clean if you decided not to use Eclipse IDE any longer.

$ mvn eclipse:eclipse
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building rabbitmq 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] maven-eclipse-plugin:2.9:eclipse (default-cli) @ rabbitmq
[INFO]
[INFO] maven-eclipse-plugin:2.9:eclipse (default-cli) @ rabbitmq
[INFO]
[INFO] --- maven-eclipse-plugin:2.9:eclipse (default-cli) @ rabbitmq ---
[INFO] Using Eclipse Workspace: /home/drmanalo/workspace
[INFO] Adding default classpath container: org.eclipse.jdt.launching.JRE_CONTAINER
[INFO] Not writing settings - defaults suffice
[INFO] Wrote Eclipse project for "rabbitmq" to /home/drmanalo/workspace/rabbitmq.
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.194s
[INFO] Finished at: Wed Aug 26 19:37:19 BST 2014
[INFO] Final Memory: 9M/150M
[INFO] ------------------------------------------------------------------------

Updated pom.xml

The dependency spring-context defines the actual Spring Injection Container and has a small number of dependencies: spring-core, spring-expression, spring-aop and spring-beans. These augment the container by enabling support for some of the core Spring technologies:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.manalo.rabbitmq</groupId>
	<artifactId>rabbitmq</artifactId>
	<packaging>jar</packaging>
	<version>1.0-SNAPSHOT</version>
	<name>rabbitmq</name>
	<url>http://maven.apache.org</url>
	<properties>
		<spring.version>3.2.4.RELEASE</spring.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
	</dependencies>
</project>

After updating your pom.xml, run mvn compile to download Spring dependencies.

App.java

package com.manalo.rabbitmq;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

	public static void main(String[] args) {

		AbstractApplicationContext context = new ClassPathXmlApplicationContext(
				"spring-config.xml");

		HelloWorld hello = context.getBean(HelloWorld.class);
		hello.printHello();

		context.close();

	}

}

spring-config.xml

You will notice the above code is loading spring-config.xml so we need to create this file.

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

	<bean id="helloBean" class="com.manalo.rabbitmq.HelloWorld">
		<property name="name" value="Dhonnee" />
	</bean>

</beans>

HelloWorld.java

package com.manalo.rabbitmq;

public class HelloWorld {

	private String name;

	public void setName(String name) {
		this.name = name;
	}

	public void printHello() {
		System.out.println("Hello " + name + "!");
	}

}

mvn exec:java

You can use maven to test your main class but you will need to edit pom.xml to execute a certain goal.

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.3.2</version>
            <executions>
                <execution>
                    <goals>
                        <goal>java</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <mainClass>com.manalo.rabbitmq.App</mainClass>
            </configuration>
        </plugin>
    </plugins>
</build>

After editing pom.xml, you can now run mvn exec:java and it will execute the nominated mainClass.

$ mvn exec:java
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building rabbitmq 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- exec-maven-plugin:1.3.2:java (default-cli) @ rabbitmq ---
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@52d9ce81: defining beans [helloBean]; root of factory hierarchy
Hello Dhonnee!
Aug 27, 2014 10:07:11 PM org.springframework.context.support.AbstractApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@8894f9e: startup date [Wed Aug 27 22:07:11 BST 2014]; root of context hierarchy
Aug 27, 2014 10:07:11 PM org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons
INFO: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@52d9ce81: defining beans [helloBean]; root of factory hierarchy
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.142s
[INFO] Finished at: Wed Aug 27 22:07:11 BST 2014
[INFO] Final Memory: 9M/213M
[INFO] ------------------------------------------------------------------------

mvn compile

If you want to run mvn compile to update dependencies, you will fail due to missing plugin. Edit pom.xml again to add these lines within <plugins>. This also fixed my Eclipse being funny whenever I'm doing Maven -> Update Project. The issue is it reverts back my JRE System Library to J2SE-1.5.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
        <source>1.7</source>
        <target>1.7</target>
    </configuration>
</plugin>

mvn package

If you want to have a runnable jar, you can use Eclipse's Export -> Java -> Runnable JAR file to achieve this. But if you're like me who love console, you might want to issue mvn package or even mvn install therefore you will have to edit your pom.xml again.

<pluginRepositories>
    <pluginRepository>
        <id>onejar-maven-plugin.googlecode.com</id>
        <url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
    </pluginRepository>
</pluginRepositories>

Then whithin <plugins>, insert these lines too.

<plugin>
    <groupId>org.dstovall</groupId>
    <artifactId>onejar-maven-plugin</artifactId>
    <version>1.3.0</version>
    <executions>
        <execution>
            <configuration>
                <mainClass>com.manalo.rabbitmq.App</mainClass>
            </configuration>
            <goals>
                <goal>one-jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

You can now package your mvn project into a runnable jar using mvn package. First it will download all the onejar dependencies but you should see BUILD SUCCESS at the very end of your console.

$ mvn package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building rabbitmq 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.3:resources (default-resources) @ rabbitmq ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 1 resource
================= some output texts were removed =============================
[INFO] Using One-Jar to create a single-file distribution
[INFO] Implementation Version: 1.0-SNAPSHOT
[INFO] Using One-Jar version: 0.96
[INFO] More info on One-Jar: http://one-jar.sourceforge.net/
[INFO] License for One-Jar:  http://one-jar.sourceforge.net/one-jar-license.txt
[INFO] One-Jar file: /home/drmanalo/workspace/rabbitmq/target/rabbitmq-1.0-SNAPSHOT.one-jar.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 13.904s
[INFO] Finished at: Fri Aug 27 22:54:19 BST 2014
[INFO] Final Memory: 11M/150M
[INFO] ------------------------------------------------------------------------

Compliments to jayway.com for onejar.

Downloadable resources