Integration Graph
Starting with version 4.3, Spring Integration provides access to an application’s runtime object model, which can, optionally, include component metrics.
It is exposed as a graph, which may be used to visualize the current state of the integration application.
The o.s.i.support.management.graph
package contains all the required classes to collect, build, and render the runtime state of Spring Integration components as a single tree-like Graph
object.
The IntegrationGraphServer
should be declared as a bean to build, retrieve, and refresh the Graph
object.
The resulting Graph
object can be serialized to any format, although JSON is flexible and convenient to parse and represent on the client side.
A Spring Integration application with only the default components would expose a graph as follows:
{
"contentDescriptor" : {
"providerVersion" : "5.3.0.RELEASE",
"providerFormatVersion" : 1.2,
"provider" : "spring-integration",
"name" : "myAppName:1.0"
},
"nodes" : [ {
"nodeId" : 1,
"componentType" : "null-channel",
"integrationPatternType" : "null_channel",
"integrationPatternCategory" : "messaging_channel",
"properties" : { },
"sendTimers" : {
"successes" : {
"count" : 1,
"mean" : 0.0,
"max" : 0.0
},
"failures" : {
"count" : 0,
"mean" : 0.0,
"max" : 0.0
}
},
"receiveCounters" : {
"successes" : 0,
"failures" : 0
},
"name" : "nullChannel"
}, {
"nodeId" : 2,
"componentType" : "publish-subscribe-channel",
"integrationPatternType" : "publish_subscribe_channel",
"integrationPatternCategory" : "messaging_channel",
"properties" : { },
"sendTimers" : {
"successes" : {
"count" : 1,
"mean" : 7.807002,
"max" : 7.807002
},
"failures" : {
"count" : 0,
"mean" : 0.0,
"max" : 0.0
}
},
"name" : "errorChannel"
}, {
"nodeId" : 3,
"componentType" : "logging-channel-adapter",
"integrationPatternType" : "outbound_channel_adapter",
"integrationPatternCategory" : "messaging_endpoint",
"properties" : { },
"output" : null,
"input" : "errorChannel",
"sendTimers" : {
"successes" : {
"count" : 1,
"mean" : 6.742722,
"max" : 6.742722
},
"failures" : {
"count" : 0,
"mean" : 0.0,
"max" : 0.0
}
},
"name" : "errorLogger"
} ],
"links" : [ {
"from" : 2,
"to" : 3,
"type" : "input"
} ]
}
Version 5.2 has deprecated the legacy metrics in favor of Micrometer meters as discussed Metrics Management.
While not shown above, the legacy metrics (under the stats child node) will continue to appear in the graph, but with an extra child node "deprecated" : "stats are deprecated in favor of sendTimers and receiveCounters" .
|
With some JSON serializers, you can suppress the inclusion of legacy statistics using several techniques; for example, with Jackson, you can register a SimpleModule
configured with a NullSerializer
with the ObjectMapper
:
objectMapper.registerModule(new SimpleModule()
.addSerializer(IntegrationNode.Stats.class, NullSerializer.instance));
The resulting json contains "stats" : null
.
In the preceding example, the graph consists of three top-level elements.
The contentDescriptor
graph element contains general information about the application providing the data.
The name
can be customized on the IntegrationGraphServer
bean or in the spring.application.name
application context environment property.
Other properties are provided by the framework and let you distinguish a similar model from other sources.
The links
graph element represents connections between nodes from the nodes
graph element and, therefore, between integration components in the source Spring Integration application.
For example, from a MessageChannel
to an EventDrivenConsumer
with some MessageHandler
or from an AbstractReplyProducingMessageHandler
to a MessageChannel
.
For convenience and to let you determine a link’s purpose, the model includes the type
attribute.
The possible types are:
-
input
: Identifies the direction fromMessageChannel
to the endpoint,inputChannel
, orrequestChannel
property -
output
: The direction from theMessageHandler
,MessageProducer
, orSourcePollingChannelAdapter
to theMessageChannel
through anoutputChannel
orreplyChannel
property -
error
: FromMessageHandler
onPollingConsumer
orMessageProducer
orSourcePollingChannelAdapter
to theMessageChannel
through anerrorChannel
property; -
discard
: FromDiscardingMessageHandler
(such asMessageFilter
) to theMessageChannel
through anerrorChannel
property. -
route
: FromAbstractMappingMessageRouter
(such asHeaderValueRouter
) to theMessageChannel
. Similar tooutput
but determined at run-time. May be a configured channel mapping or a dynamically resolved channel. Routers typically retain only up to 100 dynamic routes for this purpose, but you can modify this value by setting thedynamicChannelLimit
property.
The information from this element can be used by a visualization tool to render connections between nodes from the nodes
graph element, where the from
and to
numbers represent the value from the nodeId
property of the linked nodes.
For example, the link
element can be used to determine the proper port
on the target node.
The following “text image” shows the relationships between the types:
+---(discard) | +----o----+ | | | | | | (input)--o o---(output) | | | | | | +----o----+ | +---(error)
The nodes
graph element is perhaps the most interesting, because its elements contain not only the runtime components with their componentType
instances and name
values but can also optionally contain metrics exposed by the component.
Node elements contain various properties that are generally self-explanatory.
For example, expression-based components include the expression
property that contains the primary expression string for the component.
To enable the metrics, add an @EnableIntegrationManagement
to a @Configuration
class or add an <int:management/>
element to your XML configuration.
See Metrics and Management for complete information.
The nodeId
represents a unique incremental identifier to let you distinguish one component from another.
It is also used in the links
element to represent a relationship (connection) of this component to others, if any.
The input
and output
attributes are for the inputChannel
and outputChannel
properties of the AbstractEndpoint
, MessageHandler
, SourcePollingChannelAdapter
, or MessageProducerSupport
.
See the next section for more information.
Starting with version 5.1, the IntegrationGraphServer
accepts a Function<NamedComponent, Map<String, Object>> additionalPropertiesCallback
for population of additional properties on the IntegrationNode
for a particular NamedComponent
.
For example you can expose the SmartLifecycle
autoStartup
and running
properties into the target graph:
server.setAdditionalPropertiesCallback(namedComponent -> {
Map<String, Object> properties = null;
if (namedComponent instanceof SmartLifecycle) {
SmartLifecycle smartLifecycle = (SmartLifecycle) namedComponent;
properties = new HashMap<>();
properties.put("auto-startup", smartLifecycle.isAutoStartup());
properties.put("running", smartLifecycle.isRunning());
}
return properties;
});
Graph Runtime Model
Spring Integration components have various levels of complexity.
For example, any polled MessageSource
also has a SourcePollingChannelAdapter
and a MessageChannel
to which to periodically send messages from the source data.
Other components might be middleware request-reply components (such as JmsOutboundGateway
) with a consuming AbstractEndpoint
to subscribe to (or poll) the requestChannel
(input
) for messages, and a replyChannel
(output
) to produce a reply message to send downstream.
Meanwhile, any MessageProducerSupport
implementation (such as ApplicationEventListeningMessageProducer
) wraps some source protocol listening logic and sends messages to the outputChannel
.
Within the graph, Spring Integration components are represented by using the IntegrationNode
class hierarchy, which you can find in the o.s.i.support.management.graph
package.
For example, you can use the ErrorCapableDiscardingMessageHandlerNode
for the AggregatingMessageHandler
(because it has a discardChannel
option) and can produce errors when consuming from a PollableChannel
by using a PollingConsumer
.
Another example is CompositeMessageHandlerNode
— for a MessageHandlerChain
when subscribed to a SubscribableChannel
by using an EventDrivenConsumer
.
The @MessagingGateway (see Messaging Gateways) provides nodes for each of its method, where the name attribute is based on the gateway’s bean name and the short method signature.
Consider the following example of a gateway:
|
@MessagingGateway(defaultRequestChannel = "four")
public interface Gate {
void foo(String foo);
void foo(Integer foo);
void bar(String bar);
}
The preceding gateway produces nodes similar to the following:
{
"nodeId" : 10,
"name" : "gate.bar(class java.lang.String)",
"stats" : null,
"componentType" : "gateway",
"integrationPatternType" : "gateway",
"integrationPatternCategory" : "messaging_endpoint",
"output" : "four",
"errors" : null
},
{
"nodeId" : 11,
"name" : "gate.foo(class java.lang.String)",
"stats" : null,
"componentType" : "gateway",
"integrationPatternType" : "gateway",
"integrationPatternCategory" : "messaging_endpoint",
"output" : "four",
"errors" : null
},
{
"nodeId" : 12,
"name" : "gate.foo(class java.lang.Integer)",
"stats" : null,
"componentType" : "gateway",
"integrationPatternType" : "gateway",
"integrationPatternCategory" : "messaging_endpoint",
"output" : "four",
"errors" : null
}
You can use this IntegrationNode
hierarchy for parsing the graph model on the client side as well as to understand the general Spring Integration runtime behavior.
See also Programming Tips and Tricks for more information.
Version 5.3 introduced an IntegrationPattern
abstraction and all out-of-the-box components, which represent an Enterprise Integration Pattern (EIP), implement this abstraction and provide an IntegrationPatternType
enum value.
This information can be useful for some categorizing logic in the target application or, being exposed into the graph node, it can be used by a UI to determine how to draw the component.
Integration Graph Controller
If your application is web-based (or built on top of Spring Boot with an embedded web container) and the Spring Integration HTTP or WebFlux module (see HTTP Support and WebFlux Support, respectively) is present on the classpath, you can use a IntegrationGraphController
to expose the IntegrationGraphServer
functionality as a REST service.
For this purpose, the @EnableIntegrationGraphController
and @Configuration
class annotations and the <int-http:graph-controller/>
XML element are available in the HTTP module.
Together with the @EnableWebMvc
annotation (or <mvc:annotation-driven/>
for XML definitions), this configuration registers an IntegrationGraphController
@RestController
where its @RequestMapping.path
can be configured on the @EnableIntegrationGraphController
annotation or <int-http:graph-controller/>
element.
The default path is /integration
.
The IntegrationGraphController
@RestController
provides the following services:
-
@GetMapping(name = "getGraph")
: To retrieve the state of the Spring Integration components since the lastIntegrationGraphServer
refresh. Theo.s.i.support.management.graph.Graph
is returned as a@ResponseBody
of the REST service. -
@GetMapping(path = "/refresh", name = "refreshGraph")
: To refresh the currentGraph
for the actual runtime state and return it as a REST response. It is not necessary to refresh the graph for metrics. They are provided in real-time when the graph is retrieved. Refresh can be called if the application context has been modified since the graph was last retrieved. In that case, the graph is completely rebuilt.
You can set security and cross-origin restrictions for the IntegrationGraphController
with the standard configuration options and components provided by the Spring Security and Spring MVC projects.
The following example achieves those goals:
<mvc:annotation-driven />
<mvc:cors>
<mvc:mapping path="/myIntegration/**"
allowed-origins="http://localhost:9090"
allowed-methods="GET" />
</mvc:cors>
<security:http>
<security:intercept-url pattern="/myIntegration/**" access="ROLE_ADMIN" />
</security:http>
<int-http:graph-controller path="/myIntegration" />
The following example shows how to do the same thing with Java configuration:
@Configuration
@EnableWebMvc // or @EnableWebFlux
@EnableWebSecurity // or @EnableWebFluxSecurity
@EnableIntegration
@EnableIntegrationGraphController(path = "/testIntegration", allowedOrigins="http://localhost:9090")
public class IntegrationConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/testIntegration/**").hasRole("ADMIN")
// ...
.formLogin();
}
//...
}
Note that, for convenience, the @EnableIntegrationGraphController
annotation provides an allowedOrigins
attribute.
This provides GET
access to the path
.
For more sophistication, you can configure the CORS mappings by using standard Spring MVC mechanisms.