* INT-4520 Make IntegrationGraphServer customizable JIRA: https://jira.spring.io/browse/INT-4520 * * Polishing according PR comments
305 lines
13 KiB
Plaintext
305 lines
13 KiB
Plaintext
[[integration-graph]]
|
|
=== 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:
|
|
|
|
====
|
|
[source,json]
|
|
----
|
|
{
|
|
"contentDescriptor": {
|
|
"providerVersion": "4.3.0.RELEASE",
|
|
"providerFormatVersion": 1.0,
|
|
"provider": "spring-integration",
|
|
"name": "myApplication"
|
|
},
|
|
"nodes": [
|
|
{
|
|
"nodeId": 1,
|
|
"name": "nullChannel",
|
|
"stats": null,
|
|
"componentType": "channel"
|
|
},
|
|
{
|
|
"nodeId": 2,
|
|
"name": "errorChannel",
|
|
"stats": null,
|
|
"componentType": "publish-subscribe-channel"
|
|
},
|
|
{
|
|
"nodeId": 3,
|
|
"name": "_org.springframework.integration.errorLogger",
|
|
"stats": {
|
|
"duration": {
|
|
"count": 0,
|
|
"min": 0.0,
|
|
"max": 0.0,
|
|
"mean": 0.0,
|
|
"standardDeviation": 0.0,
|
|
"countLong": 0
|
|
},
|
|
"errorCount": 0,
|
|
"standardDeviationDuration": 0.0,
|
|
"countsEnabled": true,
|
|
"statsEnabled": true,
|
|
"loggingEnabled": false,
|
|
"handleCount": 0,
|
|
"meanDuration": 0.0,
|
|
"maxDuration": 0.0,
|
|
"minDuration": 0.0,
|
|
"activeCount": 0
|
|
},
|
|
"componentType": "logging-channel-adapter",
|
|
"output": null,
|
|
"input": "errorChannel"
|
|
}
|
|
],
|
|
"links": [
|
|
{
|
|
"from": 2,
|
|
"to": 3,
|
|
"type": "input"
|
|
}
|
|
]
|
|
}
|
|
----
|
|
====
|
|
|
|
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 from `MessageChannel` to the endpoint, `inputChannel`, or `requestChannel` property
|
|
* `output`: The direction from the `MessageHandler`, `MessageProducer`, or `SourcePollingChannelAdapter` to the `MessageChannel` through an `outputChannel` or `replyChannel` property
|
|
* `error`: From `MessageHandler` on `PollingConsumer` or `MessageProducer` or `SourcePollingChannelAdapter` to the `MessageChannel` through an `errorChannel` property;
|
|
* `discard`: From `DiscardingMessageHandler` (such as `MessageFilter`) to the `MessageChannel` through an `errorChannel` property.
|
|
* `route`: From `AbstractMappingMessageRouter` (such as `HeaderValueRouter`) to the `MessageChannel`.
|
|
Similar to `output` 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 the `dynamicChannelLimit` 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.
|
|
You can control exactly which components in the framework collect statistics.
|
|
See <<metrics-management>> for complete information.
|
|
See the `stats` attribute from the `o.s.i.errorLogger` component in the JSON example shown earlier.
|
|
In this case, The `nullChannel` and `errorChannel` do not provide statistics information, because the configuration for this example was as follows:
|
|
|
|
====
|
|
[source,java]
|
|
----
|
|
@Configuration
|
|
@EnableIntegration
|
|
@EnableIntegrationManagement(statsEnabled = "_org.springframework.integration.errorLogger.handler",
|
|
countsEnabled = "!*",
|
|
defaultLoggingEnabled = "false")
|
|
public class ManagementConfiguration {
|
|
|
|
@Bean
|
|
public IntegrationGraphServer integrationGraphServer() {
|
|
return new IntegrationGraphServer();
|
|
}
|
|
|
|
}
|
|
----
|
|
====
|
|
|
|
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:
|
|
|
|
====
|
|
[source,java]
|
|
----
|
|
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`.
|
|
|
|
NOTE: The `@MessagingGateway` (see <<gateway>>) 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:
|
|
|
|
====
|
|
[source,java]
|
|
----
|
|
@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:
|
|
|
|
====
|
|
[source,json]
|
|
|
|
----
|
|
{
|
|
"nodeId" : 10,
|
|
"name" : "gate.bar(class java.lang.String)",
|
|
"stats" : null,
|
|
"componentType" : "gateway",
|
|
"output" : "four",
|
|
"errors" : null
|
|
},
|
|
{
|
|
"nodeId" : 11,
|
|
"name" : "gate.foo(class java.lang.String)",
|
|
"stats" : null,
|
|
"componentType" : "gateway",
|
|
"output" : "four",
|
|
"errors" : null
|
|
},
|
|
{
|
|
"nodeId" : 12,
|
|
"name" : "gate.foo(class java.lang.Integer)",
|
|
"stats" : null,
|
|
"componentType" : "gateway",
|
|
"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>> for more information.
|
|
|
|
=== 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>> and <<webflux>>, 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 last `IntegrationGraphServer` refresh.
|
|
The `o.s.i.support.management.graph.Graph` is returned as a `@ResponseBody` of the REST service.
|
|
* `@GetMapping(path = "/refresh", name = "refreshGraph")`: To refresh the current `Graph` 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:
|
|
|
|
====
|
|
[source,xml]
|
|
----
|
|
<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:
|
|
|
|
====
|
|
[source,java]
|
|
----
|
|
@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.
|