Files
spring-integration/src/reference/asciidoc/graph.adoc
Artem Bilan 90ac259da7 INT-4520 Make IntegrationGraphServer customizable (#2608)
* INT-4520 Make IntegrationGraphServer customizable

JIRA: https://jira.spring.io/browse/INT-4520

* * Polishing according PR comments
2018-10-24 15:02:52 -04:00

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.