我想使用 java DSL 重写以下 xml 示例
XML 配置:
<int:channel id="findUserServiceChannel"/>
<int:channel id="findUserByUsernameServiceChannel"/>
<!-- See also:
https://docs.spring.io/spring-integration/reference/htmlsingle/#gateway-proxy
https://www.enterpriseintegrationpatterns.com/MessagingGateway.html -->
<int:gateway id="userGateway" default-request-timeout="5000"
default-reply-timeout="5000"
service-interface="org.springframework.integration.samples.enricher.service.UserService">
<int:method name="findUser" request-channel="findUserEnricherChannel"/>
<int:method name="findUserByUsername" request-channel="findUserByUsernameEnricherChannel"/>
<int:method name="findUserWithUsernameInMap" request-channel="findUserWithMapEnricherChannel"/>
</int:gateway>
<int:enricher id="findUserEnricher"
input-channel="findUserEnricherChannel"
request-channel="findUserServiceChannel">
<int:property name="email" expression="payload.email"/>
<int:property name="password" expression="payload.password"/>
</int:enricher>
<int:enricher id="findUserByUsernameEnricher"
input-channel="findUserByUsernameEnricherChannel"
request-channel="findUserByUsernameServiceChannel"
request-payload-expression="payload.username">
<int:property name="email" expression="payload.email"/>
<int:property name="password" expression="payload.password"/>
</int:enricher>
<int:enricher id="findUserWithMapEnricher"
input-channel="findUserWithMapEnricherChannel"
request-channel="findUserByUsernameServiceChannel"
request-payload-expression="payload.username">
<int:property name="user" expression="payload"/>
</int:enricher>
<int:service-activator id="findUserServiceActivator"
ref="systemService" method="findUser"
input-channel="findUserServiceChannel"/>
<int:service-activator id="findUserByUsernameServiceActivator"
ref="systemService" method="findUserByUsername"
input-channel="findUserByUsernameServiceChannel"/>
<bean id="systemService"
class="org.springframework.integration.samples.enricher.service.impl.SystemService"/>
现在我有以下内容:
配置:
@Configuration
@EnableIntegration
@IntegrationComponentScan
public class Config {
@Bean
public SystemService systemService() {
return new SystemService();
}
@Bean
public IntegrationFlow findUserEnricherFlow(SystemService systemService) {
return IntegrationFlows.from("findUserEnricherChannel")
.<User>handle((p, h) -> systemService.findUser(p))
.get();
}
@Bean
public IntegrationFlow findUserByUsernameEnricherFlow(SystemService systemService) {
return IntegrationFlows.from("findUserByUsernameEnricherChannel")
.<User>handle((p, h) -> systemService.findUserByUsername(p.getUsername()))
.get();
}
@Bean
public IntegrationFlow findUserWithUsernameInMapFlow(SystemService systemService) {
return IntegrationFlows.from("findUserWithMapEnricherChannel")
.<Map<String, Object>>handle((p, h) -> {
User user = systemService.findUserByUsername((String) p.get("username"));
Map<String, Object> map = new HashMap<>();
map.put("username", user.getUsername());
map.put("email", user.getEmail());
map.put("password", user.getPassword());
return map;
})
.get();
}
}
服务接口:
@MessagingGateway
public interface UserService {
/**
* Retrieves a user based on the provided user. User object is routed to the
* "findUserEnricherChannel" channel.
*/
@Gateway(requestChannel = "findUserEnricherChannel")
User findUser(User user);
/**
* Retrieves a user based on the provided user. User object is routed to the
* "findUserByUsernameEnricherChannel" channel.
*/
@Gateway(requestChannel = "findUserByUsernameEnricherChannel")
User findUserByUsername(User user);
/**
* Retrieves a user based on the provided username that is provided as a Map
* entry using the mapkey 'username'. Map object is routed to the
* "findUserWithMapChannel" channel.
*/
@Gateway(requestChannel = "findUserWithMapEnricherChannel")
Map<String, Object> findUserWithUsernameInMap(Map<String, Object> userdata);
}
和目标服务:
public class SystemService {
public User findUser(User user) {
...
}
public User findUserByUsername(String username) {
...
}
}
主要方法:
public static void main(String[] args) {
ConfigurableApplicationContext ctx = new SpringApplication(MyApplication.class).run(args);
UserService userService = ctx.getBean(UserService.class);
User user = new User("some_name", null, null);
System.out.println("Main:" + userService.findUser(user));
System.out.println("Main:" + userService.findUserByUsername(user));
Map<String, Object> map = new HashMap<>();
map.put("username", "vasya");
System.out.println("Main:" + userService.findUserWithUsernameInMap(map));
}
输出:
2019-08-30 14:09:29.956 INFO 12392 --- [ main] enricher.MyApplication : Started MyApplication in 2.614 seconds (JVM running for 3.826)
2019-08-30 14:09:29.966 INFO 12392 --- [ main] enricher.SystemService : Calling method 'findUser' with parameter User{username='some_name', password='null', email='null'}
Main:User{username='some_name', password='secret', email='some_name@springintegration.org'}
2019-08-30 14:09:29.967 INFO 12392 --- [ main] enricher.SystemService : Calling method 'findUserByUsername' with parameter: some_name
Main:User{username='some_name', password='secret', email='some_name@springintegration.org'}
2019-08-30 14:09:29.967 INFO 12392 --- [ main] enricher.SystemService : Calling method 'findUserByUsername' with parameter: vasya
Main:{password=secret, email=vasya@springintegration.org, username=vasya}
如您所见,一切正常,但我在配置中进行转换。我不确定我是否必须这样做,因为 xml 配置没有这样的转换,并且一切都以某种方式使用内部魔法工作。这是正确的方法还是我应该使用一些内部DSL魔法进行转换?
附言
我想Config
类可以以某种方式简化。我的意思是findUserByUsernameEnricherFlow
findUserWithUsernameInMapFlow
方法
更新
我意识到我并不真正了解XML配置的工作原理:
让我们考虑方法Userservice#findUserWithUsernameInMap
方法它具有以下界面:
Map<String, Object> findUserWithUsernameInMap(Map<String, Object> userdata);
它最终调用findUserByUsername
SystemService
方法:
public User findUserByUsername(String username)
由于客户端代码可以使用Userservice
因此内部有 2 个转换:
在 TO 的路上(在
SystemService#findUserByUsername
调用之前(,因为Userservice#findUserWithUsernameInMap
接受Map<String, Object>
但SystemService#findUserByUsername
接受字符串在返回途中(
SystemService#findUserByUsername
调用后(,因为SystemService#findUserByUsername
返回用户但Userservice#findUserWithUsernameInMap
返回Map<String, Object>
这些转换在 xml 配置中的确切位置声明?
我有一个建议,请求-有效载荷-表达式用于使TO转变。看起来它可以使用与对象相同的方式与地图一起工作。但BACK转型根本不清楚。确定配置有
<int:property name="user" expression="payload"/>
但我不知道这是什么意思。
<int:enricher>
的Java DSL 等效项是.enrich()
。 所以,你的findUserEnricherFlow
应该是这样的:
@Bean
public IntegrationFlow findUserEnricherFlow(SystemService systemService) {
return IntegrationFlows.from("findUserEnricherChannel")
.enrich((enricher) -> enricher
.requestChannel("findUserServiceChannel")
.propertyExpression("email", "payload.email")
.propertyExpression("password", "payload.password"))
.get();
}
您仍然可以简单地将问题指向一种网关方法和一个更丰富的方法......
最终,我能够将xml重写为java DSL。不幸的是,它有点冗长:
配置:
@Configuration
@EnableIntegration
@IntegrationComponentScan
public class Config {
@Bean
public SystemService systemService() {
return new SystemService();
}
//first flow
@Bean
public IntegrationFlow findUserEnricherFlow() {
return IntegrationFlows.from("findUserEnricherChannel")
.enrich(enricherSpec ->
enricherSpec.requestChannel("findUserServiceChannel")
.<User>propertyFunction("email", (message) ->
(message.getPayload()).getEmail()
).<User>propertyFunction("password", (message) ->
(message.getPayload()).getPassword()
))
.get();
}
@Bean
public IntegrationFlow findUserServiceFlow(SystemService systemService) {
return IntegrationFlows.
from("findUserServiceChannel")
.<User>handle((p, h) -> systemService.findUser(p))
.get();
}
//second flow
@Bean
public IntegrationFlow findUserByUsernameEnricherFlow() {
return IntegrationFlows.from("findUserByUsernameEnricherChannel")
.enrich(enricherSpec ->
enricherSpec.requestChannel("findUserByUsernameRequestChannel")
.<User>requestPayload(userMessage -> userMessage.getPayload().getUsername())
.<User>propertyFunction("email", (message) ->
(message.getPayload()).getEmail()
).<User>propertyFunction("password", (message) ->
(message.getPayload()).getPassword()
))
.get();
}
@Bean
public IntegrationFlow findUserByUsernameServiceFlow(SystemService systemService) {
return IntegrationFlows.from("findUserByUsernameRequestChannel")
.<String>handle((p, h) -> systemService.findUserByUsername(p))
.get();
}
//third flow
@Bean
public IntegrationFlow findUserWithUsernameInMapEnricherFlow() {
return IntegrationFlows.from("findUserWithMapEnricherChannel")
.enrich(enricherSpec ->
enricherSpec.requestChannel("findUserWithMapRequestChannel")
.<Map<String, User>>requestPayload(userMessage -> userMessage.getPayload().get("username"))
.<User>propertyFunction("user", Message::getPayload)
).get();
}
@Bean
public IntegrationFlow findUserWithUsernameInMapServiceFlow(SystemService systemService) {
return IntegrationFlows.from("findUserWithMapRequestChannel")
.<String>handle((p, h) -> systemService.findUserByUsername(p))
.get();
}
}
我还在UserService
中添加了一些注释:
@MessagingGateway
public interface UserService {
/**
* Retrieves a user based on the provided user. User object is routed to the
* "findUserEnricherChannel" channel.
*/
@Gateway(requestChannel = "findUserEnricherChannel")
User findUser(User user);
/**
* Retrieves a user based on the provided user. User object is routed to the
* "findUserByUsernameEnricherChannel" channel.
*/
@Gateway(requestChannel = "findUserByUsernameEnricherChannel")
User findUserByUsername(User user);
/**
* Retrieves a user based on the provided username that is provided as a Map
* entry using the mapkey 'username'. Map object is routed to the
* "findUserWithMapChannel" channel.
*/
@Gateway(requestChannel = "findUserWithMapEnricherChannel")
Map<String, Object> findUserWithUsernameInMap(Map<String, Object> userdata);
}
所有来源都可以在这里找到:https://github.com/gredwhite/spring-integration/tree/master/complete/src/main/java/enricher
我还发现:
@Bean
public IntegrationFlow findUserEnricherFlow(SystemService systemService) {
return IntegrationFlows.from("findUserEnricherChannel")
.enrich(enricherSpec ->
enricherSpec//.requestChannel("findUserServiceChannel")
.<User>propertyFunction("email", (message) ->
(message.getPayload()).getEmail()
).<User>propertyFunction("password", (message) ->
(message.getPayload()).getPassword()
))
.get();
}
@Bean
public IntegrationFlow findUserServiceFlow(SystemService systemService) {
return IntegrationFlows.
from("findUserServiceChannel")
.<User>handle((p, h) -> systemService.findUser(p))
.get();
}
可以用更简洁的方式重写:
@Bean
public IntegrationFlow findUserEnricherFlow(SystemService systemService) {
return IntegrationFlows.from("findUserEnricherChannel")
.enrich(enricherSpec ->
enricherSpec//.requestChannel("findUserServiceChannel")
.<User>propertyFunction("email", (message) ->
(message.getPayload()).getEmail()
).<User>propertyFunction("password", (message) ->
(message.getPayload()).getPassword()
))
.<User>handle((p, h) -> systemService.findUser(p))
.get();
}
还有一个选择:
@Bean
public IntegrationFlow findUserEnricherFlow(SystemService systemService) {
return IntegrationFlows.from("findUserEnricherChannel")
.enrich(enricherSpec ->
enricherSpec.requestSubFlow(flow -> flow.<User>handle((p, h) -> systemService.findUser(p))
).<User>propertyFunction("email", (message) ->
(message.getPayload()).getEmail()
).<User>propertyFunction("password", (message) ->
(message.getPayload()).getPassword()
))
.get();
}