Spring JMS Integration Gateway Example 12 minute read
A detailed step-by-step tutorial on how to connect to a JMS broker using a Spring Integration Gateway and Spring Boot.
锘??xml version="1.0" encoding="utf-8" standalone="yes"?> In our first lesson, you will get introduced to the concepts of Enterprise Application Integration. You will learn about the and Enterprise integration patterns that can be applied to simplify integration between different platforms and the Integration strategies that can be followed for this purpose. Finally, we will discuss how and why to implement a Message driven architecture and how to achieve both Synchronous and asynchronous communication among nodes. In this lesson, you will get to understand how Spring Integration works under the hood. The core concepts of Spring Integration messaging system (like message channels and endpoints) will be introduced. Additionally, the components that build the framework will be discussed, including the channel adapters, transformers, filters, routers etc. Finally, the two distinct methods of communication (synchronous and asynchronous) are explained and the lesson ends with a discussion on error handling. In this lesson, we will focus on the integration with external web services. Spring Integration comes with the necessary functionality (adapters, channels etc.) to support web services out of the box. A full example is built from scratch in order to better understand the topic. In this lesson, we will focus on integrating our application with JMS messaging. For this purpose, we will use Active MQ, which will be our broker. We will show examples of sending and receiving JMS messages by using the Spring Integration JMS channel adapters. Following these examples, we will see some ways of customizing these invocations by configuring message conversion and destination resolution. In this lesson, we will wrap everything up by providing a complete application that uses several of the components provided by Spring Integration in order to provide a service to its users. We will discuss the system architecture, the actual implementation and the relevant error handling. In this lesson, we will examine different mechanisms of monitoring or gathering more information about what is going on within the messaging system. Some of these mechanisms consist of managing or monitoring the application through MBeans, which are part of the JMX specification. Another mechanism discussed in this chapter is how we will implement the EIP idempotent receiver pattern using a metadata store. Finally, the last mechanism described is the control bus. This will let us send messages that will invoke operations on components in the application context. Enterprise integration is too complex to be solved with a simple 'cookbook' approach. Instead, patterns can provide guidance by documenting the kind of experience that usually lives only in architects' heads: they are accepted solutions to recurring problems within a given context. Patterns are abstract enough to apply to most integration technologies, but specific enough to provide hands-on guidance to designers and architects. Patterns also provide a vocabulary for developers to efficiently describe their solution. Patterns are not 'invented'; they are harvested from repeated use in practice. If you have built integration solutions, it is likely that you have used some of these patterns, maybe in slight variations and maybe calling them by a different name. The purpose of this site is not to "invent" new approaches, but to present a coherent collection of relevant and proven patterns, which in total form an integration pattern language. Despite the 700+ pages, our book covers only a fraction of patterns (and the problems to be solved) in the integration space. The current patterns focus on Messaging, which forms the basis of most other integration patterns. We have started to harvest more patterns but are realizing (once again) how much work documenting these patterns really is. So please stay tuned. We have documented 65 messaging patterns, organized as follows: A detailed step-by-step tutorial on how to connect to a JMS broker using a Spring Integration Gateway and Spring Boot. A detailed step-by-step tutorial on how to connect to Apache ActiveMQ Artemis using Spring JMS and Spring Boot. A detailed step-by-step tutorial on how to publish/subscribe to a JMS topic using Spring JMS and Spring Boot. A detailed step-by-step tutorial on how to connect to an ActiveMQ JMS broker using Spring Integration and Spring Boot. A detailed step-by-step tutorial on how a Spring JMS listener works in combination with Spring Boot. A detailed step-by-step tutorial on how to use JmsTemplate in combination with Spring JMS and Spring Boot. A detailed step-by-step tutorial on how to implement a message selector using Spring JMS and Spring Boot. A detailed step-by-step tutorial on how to implement a message converter using Spring JMS and Spring Boot. A detailed step-by-step tutorial on how to use a Spring Boot admin UI to manage Spring Batch jobs. A detailed step-by-step tutorial on how to implement a Spring Batch Tasklet using Spring Boot. A detailed step-by-step tutorial on how to implement a Hello World Spring Batch job using Spring Boot.
榪欎釜闂鐨勬柟妗堝垯鏄泦緹ら変富錛屼竴涓泦緹や腑錛屽彧鏈変竴涓狶EADER錛岀敱LEADER璐熻矗鎵ц瀹氭椂浠誨姟宸ヤ綔銆傚綋LEADER琚彇娑堟椂錛屼細鍦ㄥ墿涓嬬殑瀹炰緥涓啀閫塋EADER銆?br />
鎸佹湁鍒嗗竷寮忛攣鐨勫疄渚嬪垯鏄疞EADER銆?br />
SPRING INTEGRATION JDBC 鍒欏凡鎻愪緵鐩稿叧鍔熻兘銆?br />
pom.xml
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
</dependency>
LeaderElectionIntegrationConfig.java
import java.util.concurrent.CopyOnWriteArrayList;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.jdbc.lock.DefaultLockRepository;
import org.springframework.integration.jdbc.lock.JdbcLockRegistry;
import org.springframework.integration.jdbc.lock.LockRepository;
import org.springframework.integration.support.leader.LockRegistryLeaderInitiator;
import com.paul.integration.leader.ControlBusGateway;
import com.paul.integration.leader.MyCandidate;
@Configuration
public class LeaderElectionIntegrationConfig {
@Bean
public List<String> needToStartupAdapterList(){
return new CopyOnWriteArrayList<>();
}
@Bean
public DefaultLockRepository defaultLockRepository(DataSource dataSource){
DefaultLockRepository defaultLockRepository =
new DefaultLockRepository(dataSource);
// defaultLockRepository.setTimeToLive(60_000);
return defaultLockRepository;
}
@Bean
public JdbcLockRegistry jdbcLockRegistry(LockRepository lockRepository){
return new JdbcLockRegistry(lockRepository);
}
@Bean
public MyCandidate myCandidate(
ControlBusGateway controlBusGateway,
List<String> needToStartupAdapterList
) {
return new MyCandidate(controlBusGateway, needToStartupAdapterList);
}
@Bean
public LockRegistryLeaderInitiator leaderInitiator() {
return new LockRegistryLeaderInitiator(
jdbcLockRegistry(null), myCandidate(null, null)
);
}
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.integration.leader.Context;
import org.springframework.integration.leader.DefaultCandidate;
import com.novacredit.mcra.mcracommon.integration.gateway.ControlBusGateway;
public class MyCandidate extends DefaultCandidate{
private static final Logger LOG = LoggerFactory.getLogger(MyCandidate.class);
private List<String> needToStartupAdapterList;
private ControlBusGateway controlBusGateway;
public MyCandidate(
ControlBusGateway controlBusGateway,
List<String> needToStartupAdapterList
) {
this.controlBusGateway = controlBusGateway;
this.needToStartupAdapterList = needToStartupAdapterList;
}
@Override
public void onGranted(Context context) {
super.onGranted(context);
LOG.info("*** Leadership granted ***");
LOG.info("STARTING MONGODB POLLER");
needToStartupAdapterList
.forEach(
c -> {
// c = "@'testIntegrationFlow.org.springframework.integration.config."
// + "SourcePollingChannelAdapterFactoryBean#0'";
String command = c + ".start()";
LOG.info("-----{}", command);
controlBusGateway.sendCommand(command);
}
);
LOG.info("STARTUP MESSAGE SENT");
}
@Override
public void onRevoked(Context context) {
super.onRevoked(context);
LOG.info("*** Leadership revoked ***");
LOG.info("STOPPING MONGODB POLLER");
needToStartupAdapterList
.forEach(
c -> {
// c = "@'testIntegrationConfig.testIntegrationFlow."
// + "mongoMessageSource.inboundChannelAdapter'";
String command = c + ".stop()";
LOG.info("-----{}", command);
// controlBusGateway.sendCommand(command);
}
);
LOG.info("SHUTDOWN MESSAGE SENT");
}
}
ControlBusIntegrationConfig.java
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.integration.dsl.MessageChannels;
import org.springframework.integration.gateway.GatewayProxyFactoryBean;
import org.springframework.integration.handler.LoggingHandler;
import org.springframework.messaging.MessageChannel;
import com.paul.integration.gateway.ControlBusGateway;
@Configuration
public class ControlBusIntegrationConfig {
@Bean
public MessageChannel controlBusChannel() {
return MessageChannels.direct().get();
}
@Bean
public IntegrationFlow controlBusFlow() {
return IntegrationFlows.from(controlBusChannel())
.log(LoggingHandler.Level.INFO, "controlBusChannel")
.controlBus()
.get();
}
@Bean
public GatewayProxyFactoryBean controlBusGateway() {
GatewayProxyFactoryBean gateway = new GatewayProxyFactoryBean(ControlBusGateway.class);
gateway.setDefaultRequestChannel(controlBusChannel());
gateway.setDefaultRequestTimeout(300l);
gateway.setDefaultReplyTimeout(300l);
return gateway;
}
}
ControlBusGateway.java
public void sendCommand(String command);
}
鍚勪釜搴旂敤瀹炰緥榪愯鏃訛紝鍏朵腑鐨凩ockRegistryLeaderInitiator浼氳嚜鍔ㄨ繍琛岋紝鎶㈠ずLEADER鏁版嵁錛屾渶緇堝彧鏈変竴涓疄渚嬪ず鍙栥備箣鍚庡啀鎵цMyCandidate涓殑浠g爜銆?br />
]]>
寮曞叆浜嗘柊鍚嶈瘝錛歋upplier銆丗unction涓嶤onsumer銆傚疄闄呬笂榪欏嚑涓被鍙涓篈dapter錛屽鏋滀箣鍓嶅凡緇忔湁瀛樺湪鐨凷ervice綾伙紝涓旀柟娉曞悕涓哄悇縐嶅悇鏍鳳紝鍙互閲嶆柊鍖呰鎴怱upplier銆丗unction涓嶤onsumer錛屽茍鍦ㄥ浐瀹氱殑鏂規硶鍚嶏細apply/get/accept涓皟鐢⊿ervice鐨勬柟娉曘?br />Supplier
褰撳湪閰嶇疆鏂囦歡涓敞鍏ユ綾誨瀷鐨凚ean錛屽茍鍦╯pring.cloud.stream.function.definition鍔犲叆姝ean鐨勫悕縐幫紝SPRING CLOUD STREAM灝變細甯綘鐢熸垚涓涓狾utput MessageChannel錛屽茍榪炴帴涓婃Bean錛屽悗緇彧闇瑕佸湪BINDDING涓姞鍏ュ搴旂殑Destination Name錛屽嵆鍙悜BROKER鍙戞秷鎭簡銆?br />Consumer
褰撳湪閰嶇疆鏂囦歡涓敞鍏ユ綾誨瀷鐨凚ean錛屽茍鍦╯pring.cloud.stream.function.definition鍔犲叆姝ean鐨勫悕縐幫紝SPRING CLOUD STREAM灝變細甯綘鐢熸垚涓涓狪nput MessageChannel錛屽茍榪炴帴涓婃Bean錛屽悗緇彧闇瑕佸湪BINDDING涓姞鍏ュ搴旂殑Destination Name錛屽嵆鍙敹鍒癇ROKER鎺ㄩ佸叧浜庢Destination鐨勬秷鎭簡銆?br />Function
褰撳湪閰嶇疆鏂囦歡涓敞鍏ユ綾誨瀷鐨凚ean錛屽茍鍦╯pring.cloud.stream.function.definition鍔犲叆姝ean鐨勫悕縐幫紝SPRING CLOUD STREAM灝變細甯綘鐢熸垚涓涓狪nput鍜孫utput MessageChannel錛屽茍榪炴帴涓婃Bean錛屽悗緇彧闇瑕佸湪BINDDING涓垎鍒Input鍜孫utput MessageChannel鍔犲叆瀵瑰簲鐨凞estination Name1/Name2錛屽嵆鍙敹鍒癇ROKER鎺ㄩ佸叧浜庢Destination鐨勬秷鎭紝涔熷彲浠ュ悜BROKER鍙戞秷鎭簡銆?br />涓嶴PRING INTEGRATION鐨勬暣鍚?/h2>濡傛灉瑕佸娑堟伅榪涜澶嶆潅澶勭悊錛屽鎷嗗垎娑堟伅銆佽仛鍚堟秷鎭両F ELSE娑堟伅絳夛紝灝辮鍊熷姪SPRING INTEGRATION浜嗐?br />
public IntegrationFlow upperCaseFlow(LoanService loanService) {
return IntegrationFlows
//turn this IntegrationFlow as a gateway, here is a Function interface
//with loadCheckerFunction as bean name
.from(LoadCheckerFunction.class, gateway -> gateway.beanName("loadCheckerFunction"))
.handle(loanService, "check")
.logAndReply(LoggingHandler.Level.WARN);
}
public interface LoadCheckerFunction extends Function<Loan, Loan>{
}
IntegrationFlows.from(Class<?> serviceInterface)鏄彲浠ュ皢鏈琁ntegrationFlow鍖呰鎴恠erviceInterface鐨勫疄鐜扮被錛屽鏋滆皟鐢ㄦ鎺ュ彛錛屾渶緇堜細榪斿洖IntegrationFlow鏈鍚庝竴涓楠ょ殑瀹炰綋錛屽鏋滆繖涓猻erviceInterface鏄疐unction鐨勮瘽錛屽垰濂藉拰SPRING CLOUD STREAM瀵規帴涓娿?br />
鍚庣畫鍦╯pring.cloud.stream.function.definition鍔犲叆姝ean鐨勫悕縐發oadCheckerFunction錛孲PRING CLOUD STREAM灝變細甯綘鐢熸垚涓涓狪nput鍜孫utput MessageChannel錛屽茍榪炴帴涓婃Bean錛屽啀鍦˙INDDING涓垎鍒Input鍜孫utput MessageChannel鍔犲叆瀵瑰簲鐨凞estination Name1/Name2錛屽嵆鍙敹鍒癇ROKER鎺ㄩ佸叧浜庢Destination鐨勬秷鎭紝涔熷彲浠ュ悜BROKER鍙戞秷鎭?br />
application.yaml
# spring.cloud.stream.poller.fixed-delay=1000
# This setting can control which function method in our code will be triggered if there are multiple
# spring.cloud.function.definition=supplyLoan
# Give the autogenerated binding a friendlier name
spring:
application:
name: loan-check-rabbit
banner:
location: classpath:/banner-rabbit.txt
cloud:
stream:
function.definition: loadCheckerFunction
#BindingProperties
bindings:
loadCheckerFunction-in-0:
destination: queue.pretty.log.messages
binder: local_rabbit
loadCheckerFunction-out-0:
destination: queue.pretty.approved.messages
binder: local_rabbit
#BinderProperties
binders:
local_rabbit:
type: rabbit
environment:
spring:
rabbitmq:
host: 10.80.27.69
port: 5672
username: guest
password: guest
virtual-host: my-virtual-hostReference
https://spring.io/blog/2019/10/25/spring-cloud-stream-and-spring-integration
]]>
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.integration.dsl.Transformers;
import org.springframework.integration.http.dsl.Http;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class SpringIntegrationEnricherApplication {
public static void main(String[] args) {
SpringApplication.run(SpringIntegrationEnricherApplication.class, args);
}
@Bean
public IntegrationFlow jsonEnricherFlow(RestTemplate restTemplate) {
return IntegrationFlows.from(Function.class)
.transform(Transformers.fromJson(Map.class))
.enrich((enricher) -> enricher
.<Map<String, ?>>requestPayload((message) ->
((List<?>) message.getPayload().get("attributeIds"))
.stream()
.map(Object::toString)
.collect(Collectors.joining(",")))
.requestSubFlow((subFlow) ->
subFlow.handle(
Http.outboundGateway("/attributes?id={ids}", restTemplate)
.httpMethod(HttpMethod.GET)
.expectedResponseType(Map.class)
.uriVariable("ids", "payload")))
.propertyExpression("attributes", "payload.attributes"))
.<Map<String, ?>, Map<String, ?>>transform(
(payload) -> {
payload.remove("attributeIds");
return payload;
})
.transform(Transformers.toJson())
.get();
}
}
https://stackoverflow.com/questions/58205432/spring-integration-enrich-transform-message-using-rest-call
https://www.tabnine.com/web/assistant/code/rs/5c781b6ae70f87000197ab9f#L312
]]>
public class SpringIntegrationDslHttpRetryApplication {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext =
SpringApplication.run(SpringIntegrationDslHttpRetryApplication.class, args);
Function<Object, Object> function = applicationContext.getBean(Function.class);
function.apply("foo");
}
@Bean
public IntegrationFlow httpRetryFlow() {
return IntegrationFlows.from(Function.class)
.handle(Http.outboundGateway("http://localhost:11111")
.httpMethod(HttpMethod.GET)
.expectedResponseType(String.class),
e -> e.advice(retryAdvice()))
.get();
}
@Bean
public RequestHandlerRetryAdvice retryAdvice() {
return new RequestHandlerRetryAdvice();
}
}
logging.level.org.springframework.retry=debug
Reference:
https://docs.spring.io/spring-integration/reference/html/handler-advice.html#retry-advice
https://stackoverflow.com/questions/49784360/configure-error-handling-and-retry-for-http-outboundgateway-spring-dsl
https://stackoverflow.com/questions/50262862/requesthandlerretryadvice-with-httprequestexecutingmessagehandler-not-working
https://stackoverflow.com/questions/63689856/spring-integration-http-outbound-gateway-retry-based-on-reply-content
https://blog.csdn.net/cunfen8879/article/details/112552420
]]>
鍙鍦↗AVA BEAN涓渶瑕侀獙璇佺殑瀛楁鍔燖NotNull榪欑鏍囩錛岀劧鍚庡湪SERVISE涓殑杈撳叆鍙傛暟涓姞@Valid鏍囩錛屽垯灝辨縺媧婚獙璇佹祦紼嬨?br />涔熷彲浠ョ紪紼嬬殑鏂瑰紡鑷繁楠岃瘉錛?br />
//@Validated
public class MqMessageCcdValidator {
private static final Logger LOGGER = LoggerFactory.getLogger(MqMessageCcdValidator.class);
@Autowired
private Validator validator;
@ServiceActivator
public MqMessage<CcdRequest> validate(/* @Valid */ Message<MqMessage<CcdRequest>> requestMessage) {
Set<ConstraintViolation<MqMessage<CcdRequest>>> set = validator.validate(requestMessage.getPayload());
if(CollectionUtils.isNotEmpty(set)) {
CompositeException compositeException = new CompositeException();
set.forEach(
constraintViolation -> {
LOGGER.info("{}", constraintViolation);
ReqInfoValidationException exception =
new ReqInfoValidationException(constraintViolation.getMessage());
compositeException.addException(exception);
}
);
throw new MessageHandlingException(requestMessage, compositeException);
}
return requestMessage.getPayload();
}
}
鑷畾涔夐獙璇佽鍒?br />鍙敤鏍囩鏉ュ仛錛屼互涓嬩負楠岃瘉鎵嬫満鍙風殑瑙勫垯錛?br />
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.ReportAsSingleViolation;
import javax.validation.constraints.Pattern;
@Retention(RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
@Constraint(validatedBy = {})
@ReportAsSingleViolation
@Pattern(regexp = "^1[3-9]\\d{9}$")
public @interface ChinaPhone {
String message() default "Invalid Chinese mobile No.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
濡傛灉姣旇緝澶嶆潅鐨勯獙璇佽鍒欙紝鍒欏弬瑙侊細
https://reflectoring.io/bean-validation-with-spring-boot/#implementing-a-custom-validator
How to use Java Bean Validation in Spring Boot
https://nullbeans.com/how-to-use-java-bean-validation-in-spring-boot/
Complete Guide to Validation With Spring Boot
https://reflectoring.io/bean-validation-with-spring-boot/
Spring JMS Validate Messages using JSR-303 Bean Validation
https://memorynotfound.com/spring-jms-validate-messages-jsr-303-bean-validation/
Spring REST Validation Example
https://mkyong.com/spring-boot/spring-rest-validation-example/
Spring Boot 鏁村悎 Bean Validation 鏍¢獙鏁版嵁
https://blog.csdn.net/wangzhihao1994/article/details/108403732
]]>
鏈変竴涓富嫻佺▼銆佷笁涓瓙嫻佺▼鍜屼竴涓仛鍚堟祦紼嬶紝鑱氬悎嫻佺▼浼氳仛鍚堜笁涓瓙嫻佺▼鐨勪駭鐗╋紝閫氱煡涓繪祦紼嬶紝鍐嶅線涓嬭蛋銆?br />騫朵笖涓繪祦紼嬩細鎰熺煡瀛愭祦紼嬬殑閿欒錛屽茍浼氫氦緇欑浉搴旈敊璇鐞嗘祦紼嬪鐞嗭紝涓斿皢緇撴灉鍐嶄氦緇欒仛鍚堟祦紼嬨?br />
瀵瑰簲SPRING INTEGRATION 鐨凷CATTERGATHER妯″紡錛?br />
public IntegrationFlow scatterGatherAndExecutorChannelSubFlow(TaskExecutor taskExecutor) {
return f -> f
.scatterGather(
scatterer -> scatterer
.applySequence(true)
.recipientFlow(f1 -> f1.transform(p -> "Sub-flow#1"))
.recipientFlow(f2 -> f2
.channel(c -> c.executor(taskExecutor))
.transform(p -> {
throw new RuntimeException("Sub-flow#2");
})),
null,
s -> s.errorChannel("scatterGatherErrorChannel"));
}
@ServiceActivator(inputChannel = "scatterGatherErrorChannel")
public Message<?> processAsyncScatterError(MessagingException payload) {
return MessageBuilder.withPayload(payload.getCause().getCause())
.copyHeaders(payload.getFailedMessage().getHeaders())
.build();
}
https://github.com/adnanmamajiwala/spring-integration-sample/tree/master/dsl-scatter-gather/src/main/java/com/si/dsl/scattergather
https://docs.spring.io/spring-integration/docs/5.1.x/reference/html/#scatter-gather
]]>
https://stackoverflow.com/questions/50608415/cwsia0112e-the-property-name-keep-alive-is-not-a-valid-java-identifier
]]>
public IntegrationFlow provisionUserFlow() {
return
IntegrationFlows.from("input.channel")
.publishSubscribeChannel(Executors.newCachedThreadPool(),
s -> s.applySequence(true)
.subscribe(f -> f.enrichHeaders(e -> e.header(MessageHeaders.ERROR_CHANNEL, "errorChannel", true))
.handle(provisionerA, "provision")
.channel("aggregatorChannel")
)
.subscribe(f -> f.enrichHeaders(e -> e.header(MessageHeaders.ERROR_CHANNEL, "errorChannel", true))
.handle(provisionerB, "provision")
.channel("aggregatorChannel"))
)
.get();
}
@Bean
public IntegrationFlow aggregateFlow() {
return IntegrationFlows.from("aggregatorChannel")
.channel( aggregatorChannel)
.aggregate( a -> a.processor( collect, "aggregatingMethod"))
.get();
}
@Transformer( inputChannel = "errorChannel", outputChannel = "aggregatorChannel")
public Message<?> errorChannelHandler(ErrorMessage errorMessage) throws RuntimeException {
Message<?> failedMessage = ((MessagingException) errorMessage.getPayload()).getFailedMessage();
Exception exception = (Exception) errorMessage.getPayload();
return MessageBuilder.withPayload( exception.getMessage())
.copyHeadersIfAbsent( failedMessage.getHeaders() )
.build();
}
https://stackoverflow.com/q/46495127/11790720
]]>
public IntegrationFlow parallelSplitRouteAggregateFlow() {
return IntegrationFlows
.from(Http.inboundGateway("/trigger"))
.handle((p, h) -> Arrays.asList(1, 2, 3))
.split()
.channel(MessageChannels.executor(Executors.newCachedThreadPool()))
.<Integer, Boolean>route(o -> o % 2 == 0, m -> m
.subFlowMapping(true, sf -> sf.gateway(oddFlow()))
.subFlowMapping(false, sf -> sf.gateway(evenFlow())))
.aggregate()
.get();
}
@Bean
public IntegrationFlow oddFlow() {
return flow -> flow.<Integer>handle((payload, headers) -> "odd");
}
@Bean
public IntegrationFlow evenFlow() {
return flow -> flow.<Integer>handle((payload, headers) -> "even");
}
https://stackoverflow.com/questions/50121384/spring-integration-parallel-split-route-aggregate-flow-fails-due-to-one-way-mess
]]>
import java.util.Random;
import javax.jms.ConnectionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.integration.annotation.IntegrationComponentScan;
import org.springframework.integration.channel.PublishSubscribeChannel;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.integration.dsl.core.Pollers;
import org.springframework.integration.dsl.jms.Jms;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.MessagingException;
/**
* Show how to handle error in spring integration flow.
* Please note, errorChannel in spring integration only applicable to
* error thrown in asynch component.
*
* @author zakyalvan
*/
@SpringBootApplication
@IntegrationComponentScan
public class ErrorHandlingApplication {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(ErrorHandlingApplication.class)
.web(false)
.run(args);
Runtime.getRuntime().addShutdownHook(new Thread(() -> applicationContext.close()));
System.out.println("Pres enter key to exit");
System.in.read();
System.exit(0);
}
@Autowired
private ConnectionFactory connectionFactory;
@Bean
public MessageSource<Integer> randomIntegerMessageSource() {
return () -> MessageBuilder.withPayload(new Random().nextInt()).build();
}
@Bean
public IntegrationFlow withErrorFlow() {
return IntegrationFlows.from(randomIntegerMessageSource(), spec -> spec.poller(Pollers.fixedDelay(1000)))
.handle(Jms.outboundGateway(connectionFactory)
.requestDestination("processor.input")
.replyContainer(spec -> spec.sessionTransacted(true)))
.get();
}
@Autowired
@Qualifier("errorChannel")
private PublishSubscribeChannel errorChannel;
@Bean
public IntegrationFlow errorHandlingFlow() {
return IntegrationFlows.from(errorChannel)
.handle(message -> System.out.println("@@@@@@@@@@@@@@@@@@@@@" + ((MessagingException) message.getPayload()).getFailedMessage().getPayload()))
.get();
}
}
]]>
騫傜瓑鍨嬶紝鍚屼竴涓狹ESSAGE錛屽MESSAGE ID閮戒竴鏍鳳紝鍦∕ESSAGING緋葷粺涓笉綆¤繍琛屽灝戞錛岀粨鏋滈兘涓鏍鳳紝涓哄暐錛熷洜涓洪噸澶嶇殑MESSAGE錛岄兘琚拷鐣ヤ簡銆?br />
鏂規錛?br />
娑堟伅琚鐞嗗悗錛屼粠娑堟伅涓彇鍑篒D錛屾斁鍏ETA-DATA-STORE涓紝鍚庣畫澶勭悊娑堟伅鏃訛紝瑕佷粠META-DATA-STORE涓鏌ユ槸鍚︽湁鍊箋?br />
涓嬮潰榪欎釜鏂規錛孖D鐨勫瓨鍌ㄥ拰鍒ゆ柇鏄惁閲嶅娑堟伅閮藉湪涓涓狪NTERCEPTOR涓悶瀹氥?br />
https://stackoverflow.com/questions/50401460/spring-integration-dsl-configure-idempotent-receiver-to-identify-duplicates
https://www.javacodegeeks.com/2015/09/monitoring-and-management.html
claim-check
灝哅ESSAGE鐨凱AYLOAD瀛樺湪STORE涓紝榪斿洖涓涓狪D錛岃繖涓狪D鍗砪laim-check錛屽鏋滈渶瑕佸彇MESSAGE鐨凞ETAIl鏃訛紝鍙粠STORE涓彇鍑篗ESSAGE銆?br />https://github.com/spring-projects/spring-integration/blob/master/src/reference/asciidoc/claim-check.adoc
]]>Introduction to Enterprise Application Integration
Spring Integration Fundamentals
Spring Integration and Web Services
Enterprise Messaging
Spring Integration Full Example
Monitoring and Management
]]>
]]>
Spring Integration 涓枃鎵嬪唽 (2)
]]>
SPRING INTEGRATION鏄疄鐜頒簡EIP妯″紡鐨勪竴縐嶆鏋訛紝鍗充嬌鐢–HANNEL鍜孞MS-INBOUND-ADAPTER銆丣MS-OUTBOUND-ADAPTER錛屽畬鍏ㄨ劚紱諱簡JmsTemplate鐨凙PI銆?br />
濡傛灉闇瑕佸疄鐜拌繖縐嶅満鏅細浠嶣ROKER鍙栦竴鏉℃秷鎭紝澶勭悊娑堟伅錛屼笖澶勭悊閫斾腑涓嶈鍐嶄粠BROKER鍐嶅彇娑堟伅錛屽鐞嗗畬鍚庡啀鍙栨秷鎭紝鍐嶅鐞嗐?br />
榪欐牱瑕佹眰鎵嬪姩寮濮嬪拰鍋滄JMS LISTENER錛屽嵆鎵嬪姩寮濮嬪拰鍋滄JMS-INBOUND-ADAPTER銆丣MS-OUTBOUND-ADAPTER銆?br />
@InboundChannelAdapter(value = "loaderResponseChannel")
public MessageSource loaderResponseSource() throws Exception {
return Jms
.inboundAdapter(oracleConnectionFactory())
.configureJmsTemplate(
t -> t.deliveryPersistent(true)
.jmsMessageConverter(jacksonJmsMessageConverter())
).destination(jmsInbound).get();
}
褰撲嬌鐢ˊInboundChannelAdapter鏃訛紝浼氳嚜鍔ㄦ敞鍐屼竴涓猄ourcePollingChannelAdapter 錛屼絾榪欎釜鍚嶅瓧姣旇緝闀匡細configrationName.loaderResponseSource.inboundChannelAdapter銆?br />
鍛煎彨榪欎釜瀹炰緥鐨剆tart()鍜宻top()鏂規硶鍗沖彲銆?br />
public IntegrationFlow controlBusFlow() {
return IntegrationFlows.from("controlBus")
.controlBus()
.get();
}
Message operation = MessageBuilder.withPayload("@configrationName.loaderResponseSource.inboundChannelAdapter.start()").build();
operationChannel.send(operation)
https://stackoverflow.com/questions/45632469/shutdown-spring-integration-with-jms-inboundadapter
https://docs.spring.io/spring-integration/docs/5.0.7.RELEASE/reference/html/system-management-chapter.html#control-bus
https://github.com/spring-projects/spring-integration-java-dsl/blob/master/src/test/java/org/springframework/integration/dsl/test/jms/JmsTests.java
https://stackoverflow.com/questions/50428552/how-to-stop-or-suspend-polling-after-batch-job-fail
]]>Messaging Patterns
https://www.enterpriseintegrationpatterns.com/patterns/messaging/index.html
]]>Spring JMS Integration Gateway Example 12 minute read
Spring JMS Artemis Example 6 minute read
Spring JMS Topic Example 5 minute read
Spring JMS Integration Example12 minute read
Spring JMS Listener Example 7 minute read
Spring JMS JmsTemplate Example 7 minute read
Spring JMS Message Selector Example 5 minute read
Spring JMS Message Converter Example5 minute read
Spring Batch Admin Example 11 minute read
Spring Batch Tasklet Example 7 minute read
Spring Batch Example 11 minute read
]]>
Let's take a look on the samples howto use that based on ActiveMQ JMS.
https://bitbucket.org/tomask79/spring-integration-java-dsl/src/master/
1.spring integration 's architecture
涓昏鎻愪緵涓や釜鍔熻兘錛?/p>
鍦ㄧ郴緇熷唴鎻愪緵瀹炵幇杞婚噺綰с佷簨浠墮┍鍔ㄤ氦浜掕涓虹殑妗嗘灦
鍦ㄧ郴緇熼棿鎻愪緵涓縐嶅熀浜庨傞厤鍣ㄧ殑騫沖彴錛屼互鏀寔鐏墊椿鐨勭郴緇熼棿浜や簰
2.spring integration瀵逛簬浼佷笟闆嗘垚妯″紡鐨勬敮鎸?/p>
2.1Message錛氫竴涓俊鎭殑鍗曞厓錛岄氬父鏈夋秷鎭ご錛坔eader錛夊拰娑堟伅鍐呭錛坧ayload錛夌粍鎴?/p>
2.2Message channel錛氭秷鎭鐞嗚妭鐐逛箣闂寸殑榪炴帴錛岃礋璐e皢Message浠庣敓浜ц呬紶杈撳埌娑堣垂鑰呫?/p>
鏍規嵁娑堣垂鑰呯殑澶氬皯錛屽彲鍒嗕負point to point鍜宲ublish-subscribe涓ょ
鏍規嵁娑堟伅浼犺緭鏂瑰紡鐨勪笉鍚岋紝鍒嗕負鍚屾鍜屽紓姝ヤ袱縐?/p>
2.3Message Endpoint錛氭秷鎭鐞嗚妭鐐癸紝娑堟伅浠庤妭鐐硅繘鍏ラ氶亾錛屼篃鏄粠鑺傜偣紱誨紑閫氶亾
鍑犱釜甯歌鐨凪essage EndPoint錛?/p>
CHANNEL ADAPTER錛岀敤浜庤繛鎺ヨ閫傞厤鍣ㄧ殑鐗圭偣鏄崟鍚戞秷鎭祦鐨勶紝瑕佷箞鏄秷鎭氳繃璇ラ傞厤鍣ㄨ繘鍏ラ氶亾錛岃涔堟槸娑堟伅閫氳繃璇ラ傞厤鍣ㄧ寮閫氶亾
MESSAGING GATEWAY錛屽鐞嗙殑娑堟伅嫻佸拰Channel Adapter涓嶅悓錛屼笉鏄崟鍚戠殑錛屽嵆鏈夎繘鍏ヨ鑺傜偣鐨勬秷鎭紝涔熶細浠庤鑺傜偣鍙戝嚭娑堟伅銆?br />
SERVICE ACTIVATOR錛岃鑺傜偣璋冪敤鏈嶅姟鏉ュ鐞嗚緭鍏ョ殑娑堟伅錛屽茍灝嗘湇鍔¤繑鍥炵殑鏁版嵁鍙戦佸埌杈撳嚭閫氶亾銆傚湪spring integration涓紝璋冪敤鐨勬柟娉曡闄愬畾涓烘湰鍦版柟娉曡皟鐢ㄣ?br />
ROUTER錛岃礬鐢卞櫒錛屽皢杈撳叆鐨勬秷鎭礬鐢卞埌鏌愪釜杈撳嚭閫氶亾涓?/p>
SPLITTER錛屽皢杈撳叆鐨勬秷鎭媶鍒嗘垚瀛愭秷鎭?br />
AGGREGATOR錛屽皢杈撳叆鐨勫涓秷鎭悎騫朵負涓涓秷鎭?br />
3.瑙傜湅涔︿腑渚嬪瓙hello-world鎬濊?/p>
嫻嬭瘯gateway鏃訛紝涓嬮潰浠g爜鍚戦氶亾names鍐呮斁鍏ユ秷鎭痺orld錛?/p>
鐒跺悗service-activator浠巒ames閫氶亾涓幏寰楁秷鎭痺orld錛岃皟鐢ㄦ柟娉晄ayHello榪斿洖鍊煎埌緇檊ateway錛?/p>
瑙i噴錛歡ateway鏈変竴涓猻ervice錛峣nterface鐨勫睘鎬э紝榪欎釜灞炴ф寚鍚戜竴涓猧nterface銆傚綋鎴戜滑鐢ㄤ竴涓帴鍙e0鏄庝竴涓猤ateway鏃訛紝spring integration浼氳嚜鍔ㄥ府鎴戜滑鐢熸垚璇ユ帴鍙g殑浠g悊綾伙紝榪欐牱褰撴垜浠線gateway鍙戦佹秷鎭椂錛宻pring integration浼氶氳繃浠g悊綾繪妸娑堟伅杞彂鍒癲efault錛峳equest錛峜hannel涓幓