Spring-Boot minimizes the configuration needed to configure a Spring application. It does this using so-called Spring-Boot starters.
Above this Spring-Boot allows the inversion of the typical deployment. Usually a container is provided in which a Spring application is run in. Even if in theory an application server or a servlet container can host multiple applications, it is more a reality that usually one container hosts only a single application. With Spring-Boot this concept is inverted and the application provides the container it needs. So if your application provides a Spring rest-controller (A class annotated with @Controller) Spring-Boot detects this and automatically configures a servlet-engine to run the Controller in.
With the Spring-Boot starter that is now part of BlazeDS 4.7.3-SNAPSHOT this concept is extended to BlazeDS. This makes it possible to create a Spring application in which individual Spring services are exposed via BlazeDS just by adding one Maven dependency, providing a services-config.xml in the classpath and annotating at least one service with @RemotingDestination.
The basic setup of a Spring-Boot application is handled by the spring-boot-maven-plugin which is configured in a war Maven module.
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.flex.blazeds.examples</groupId>
<artifactId>blazeds-spring-boot-example</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>war</packaging>
<build>
<plugins>
<!-- Make Spring-Boot build an executable war -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.3.3.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
<!--
We are building a servlet 3.0 application we don't
need a web.xml, so we have to disable a check on the
plugin.
-->
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!--
This will pull in and configure the servlet engine as
well as the BlazeDS server.
-->
<dependency>
<groupId>org.apache.flex.blazeds</groupId>
<artifactId>blazeds-spring-boot-starter</artifactId>
<version>4.7.3-SNAPSHOT</version>
</dependency>
</dependencies>
</project> |
Important to note that the classifier of "exec" produces an executable war. Executable wars are normal war archived, but they come with a bootloader, that allows to run the war as an executable jar from the commandline. Without this option you would be creating a simple war that you have to manually deploy in a servlet engine. The second important thing is that usually war files have to provide a web.xml inside, this is no longer required with servlet 3.0 and as our Spring-Boot application is automatically a servlet 3.0 application, we have to tell the war plugin not to complain about the missing web.xml file.
Last but most important is a reference to the blazeds-spring-boot-starter artifact, which pulls in all the BlazeDS magic.
After creating this pom, we have generally setup the Spring-Boot part of the application. In order to activate the magic of the BlazeDS starter, we also need to provide a services-config.xml in the classpath. This is located in src/main/resources/META-INF/flex/services-config.xml.
Here an example services-config.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<services-config>
<services>
<service id="remoting-service" class="flex.messaging.services.RemotingService">
<adapters>
<adapter-definition
id="java-object"
class="flex.messaging.services.remoting.adapters.JavaAdapter"
default="true"/>
</adapters>
<default-channels>
<channel ref="websocketAmf"/>
<channel ref="longPollingAmf"/>
<channel ref="shortPollingAmf"/>
</default-channels>
</service>
</services>
<channels>
<channel-definition id="websocketAmf" class="mx.messaging.channels.StreamingAMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/websocket-amf"
class="flex.messaging.endpoints.StreamingAMFEndpoint"/>
<properties>
<server-to-client-heartbeat-millis>5000</server-to-client-heartbeat-millis>
<add-no-cache-headers>true</add-no-cache-headers>
</properties>
</channel-definition>
<channel-definition id="longPollingAmf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/long-polling-amf"
class="flex.messaging.endpoints.AMFEndpoint"/>
<properties>
<polling-enabled>true</polling-enabled>
<wait-interval-millis>0</wait-interval-millis>
<polling-interval-millis>1000</polling-interval-millis>
<max-waiting-poll-requests>100</max-waiting-poll-requests>
<piggybacking-enabled>true</piggybacking-enabled>
<add-no-cache-headers>true</add-no-cache-headers>
</properties>
</channel-definition>
<channel-definition id="shortPollingAmf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/short-polling-amf"
class="flex.messaging.endpoints.AMFEndpoint"/>
<properties>
<polling-enabled>true</polling-enabled>
<polling-interval-millis>3000</polling-interval-millis>
<piggybacking-enabled>true</piggybacking-enabled>
<add-no-cache-headers>true</add-no-cache-headers>
</properties>
</channel-definition>
</channels>
<flex-client>
<!-- Make sure clients are automatically expired -->
<timeout-minutes>720</timeout-minutes>
</flex-client>
<logging>
<!--
Logging inside BlazeDS is completely turned off.
The UniversalExceptionTranslator will handle logging
of exceptions inside Spring.
-->
<target class="flex.messaging.log.ConsoleTarget" level="None"/>
</logging>
</services-config> |
This config consists of two important parts:
As soon as this file is in place, BlazeDS is completely setup. But till now we would not be able to access a single Spring service. In order to register a Spring service as remoting destination we need to annotate that service with the RemotingDestination annotation:
import org.springframework.flex.remoting.RemotingDestination;
import org.springframework.stereotype.Service;
@Service("movementService")
@RemotingDestination
public class MovementServiceImpl {
public MovementServiceImpl() {
}
public void stop() {
System.out.println("Stop");
}
public void moveForward() {
System.out.println("Forward");
}
public void moveLeft() {
System.out.println("Left");
}
public void moveRight() {
System.out.println("Right");
}
public void moveBack() {
System.out.println("Back");
}
}
|
On the Flex side, we only have to configure a simple RemoteObject object:
<fx:Declarations>
<s:RemoteObject id="movementService"
destination="movementService"
endpoint="http://localhost:8080/messagebroker/short-polling-amf"
fault="onFault(event)">
<s:method name="stop" result="onResult(event)"/>
<s:method name="moveForward" result="onResult(event)"/>
<s:method name="moveLeft" result="onResult(event)"/>
<s:method name="moveRight" result="onResult(event)"/>
<s:method name="moveBack" result="onResult(event)"/>
</s:RemoteObject>
</fx:Declarations> |
With this in place, calling the remote method is as easy as this:
protected function onForwardClick(event:MouseEvent):void {
movementService.moveForward();
} |
Enjoy and have fun with this cool new addition to BlazeDS.
This feature is a first version. It will definitely not fit in 100% of the use-cases, but it's a good start and it makes using BlazeDS insanely easy. |