Spring Boot集成控制反转

2023-11-19

Most of the time, dependency injection is the first thing that comes to mind whenever the concept of inversion of control is brought up. For this article, I’d like to shed some light on method invocation as well, which is the concept being heavily utilized by Spring Integration.

在大多数情况下,每当提出控制反转的概念时,首先就会想到依赖注入。 对于本文,我也想对方法调用进行一些说明,这是Spring Integration大量使用的概念。

类型级耦合和系统级耦合 (Type-Level Coupling and System-Level Coupling)

Before diving into the code, let’s first talk about the types of coupling inversion of control solves: type-level coupling and system-level coupling.

在深入研究代码之前,让我们首先讨论控制解决方案的耦合反转类型:类型级耦合和系统级耦合。

Type-level coupling is probably the most understood — it’s coupling between types, and it’s solved by using dependency injection. I bet most of you know this already, but let me include an example below demonstrating the concept for clarity.

类型级别的耦合可能是最被理解的-它是类型之间的耦合,可以通过使用依赖注入来解决。 我敢打赌,你们大多数人已经知道了这一点,但让我在下面提供一个示例,以说明其概念。

Suppose we have an OrderService class, and it’s being instantiated in other classes.

假设我们有一个OrderService类,并且正在其他类中对其进行实例化。

Code with type-level coupling (in this case, unambiguous type coupling):

具有类型级别耦合的代码(在这种情况下,是明确的类型耦合):

class OrderService {
  
  // a change in OrderService constructor will affect 
  // all other classes that instantiates OrderService. 
  // A problem that Dependency Injection solves. 
  public OrderService() {
  }
}




class OrderController() {
  
  private OrderService orderService;
  
  public OrderController() {
    this.orderService = new OrderService();
  } 
}


class ReportController() {
  
  private OrderService orderService;
  
  public ReportController() {
    this.orderService = new OrderService();
  }
}

A change in the constructor of the OrderService will affect every other class that instantiates OrderService.

OrderService的构造函数的更改将影响实例化OrderService所有其他类。

With dependency injection — where the creation of concrete instances is deferred to the framework that’s achieved by creating a bean of OrderService and autowiring using either XML or Java DSL — this won’t be a problem.

通过依赖注入-具体实例的创建将推迟到通过创建OrderService Bean并使用XML或Java DSL自动装配实现的框架上,这将不是问题。

@Service
class OrderService {
  // Dependency Injection: Solution to Type Level Coupling
}


@RestController
class OrderController() {
  
  @Autowired
  private OrderService orderService;
  
}


@RestController
class ReportController() {
  
  @Autowired
  private OrderService orderService;
  
}

方法调用 (Method Invocation)

So much for dependency injection — let’s now dive into method invocation, which solves system-level coupling.

依赖注入的内容已经非常多了-现在让我们深入探讨方法调用,它解决了系统级耦合。

Imagine we’re dealing with multiple systems connected to each other using our previous example of the OrderService class:

想象一下,使用前面的OrderService类示例来处理多个相互连接的系统:

@Service
class WarehouseService {
  
  public void updateInventory(...) {
    ...
  }


}


@Service 
class OrderService {
    
   // warehouseService is coupled to OrderService (System Level Coupling)
   // if for some reason warehouseService is unavailable, we won't be able to place an order
   @Autowired
   private WarehouseService warehouseService;
   
   @Transactional
   public void placeOrder(...) {
    ...
    warehouseService.updateInventory(...);
   }
  
}

Given the above, if for some reason the warehouseService is unavailable, then we won’t be able to place an order. This might be the current business rule, but what if the business decided to at least put the order’s on hold whenever the warehouse service is unavailable?

鉴于上述情况,如果出于某些原因warehouseService不可用,那么我们将无法下订单。 这可能是当前的业务规则,但是如果业务决定至少在仓库服务不可用时暂停订单,该怎么办?

This is where Spring Integration’s method invocation comes in handy by resolving the system-level coupling.

通过解决系统级耦合,Spring Integration的方法调用就可以派上用场了。

I’ll be demonstrating a simple solution (for demo purposes) wherein the Order would be successfully placed on the orderQueue, regardless if the warehouseService is available or not.

我将演示一个简单的解决方案(出于演示目的),其中Order将成功放置在orderQueue ,而不管warehouseService是否可用。

package com.orderservice;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.integration.annotation.*;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.jms.*;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.messaging.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import javax.jms.ConnectionFactory;


@SpringBootApplication
public class Main {


    @Autowired
    private ConnectionFactory connectionFactory;


    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(Main.class, args);
        OrderService orderService = context.getBean("orderService", OrderService.class);
        orderService.placeOrder("Order is Placed on Queue");
    }


    @Bean
    public MessageChannel inputChannel() {
        return new DirectChannel();
    }


    @Bean
    @ServiceActivator(inputChannel = "inputChannel")
    public MessageHandler jsmOutboundAdapter() {
        JmsTemplate template = new DynamicJmsTemplate();
        template.setConnectionFactory(this.connectionFactory);
        JmsSendingMessageHandler handler = new JmsSendingMessageHandler(template);
        handler.setDestinationName("orderQueue");
        return handler;
    }


}


@Service
class OrderService {


    @Autowired
    private WarehouseService warehouseService;


    @Transactional
    public void placeOrder(String message) {
        warehouseService.updateInventory(message);
    }


}


@MessageEndpoint
class WarehouseService {


    @Publisher(channel = "inputChannel")
    public String updateInventory(String message) {
        return message;
    }
}

As we can see here, we’re still using the warehouseService, but now even when the warehouse service is unavailable, we’d still be able to process the order once the warehouse service becomes available again. Running the code above will place an order to the orderQueue.

正如我们在这里看到的那样,我们仍在使用warehouseService ,但是现在即使仓库服务不可用,一旦仓库服务再次可用,我们仍然能够处理订单。 运行上面的代码将向orderQueue

ActiveMQ admin console
ActiveMQ管理控制台

One message enqueued! You might’ve noticed that the number of consumers is 0. It’s because we haven’t yet created the warehouseService itself, and given this scenario, we can conclude that the OrderService works despite being unaware of the warehouseService.

一条消息入队! 您可能已经注意到,消费者数量为0 。 这是因为我们尚未创建warehouseService本身,并且在这种情况下,我们可以得出结论,尽管不知道warehouseService也可以使用OrderService

实施“ warehouseService” (Implementing the ‘warehouseService’)

We now have resolved the system-level coupling we were previously using with Spring Integration, which heavily utilizes method invocation. If you’re still here, though, then join me implementing the warehouseService.

现在,我们已经解决了以前与Spring Integration一起使用的系统级耦合,该耦合大量利用了方法调用。 但是,如果您仍然在这里,请与我一起实现warehouseService

package com.warehouseservice;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.integration.annotation.*;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.jms.*;
import org.springframework.jms.listener.SimpleMessageListenerContainer;
import org.springframework.messaging.MessageChannel;
import org.springframework.transaction.annotation.Transactional;


import javax.jms.ConnectionFactory;


@SpringBootApplication
@PropertySource(value="application-dev.properties") // unnecessary if on separate project, demo purposes
public class Main {


    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }


    @Bean
    public JmsInboundGateway jmsInboundGateway(ConnectionFactory connectionFactory) {
        JmsInboundGateway gateway = new JmsInboundGateway(
                simpleMessageListenerContainer(connectionFactory),
                channelPublishingJmsMessageListener());
        gateway.setRequestChannel(inputChannel());


        return gateway;
    }


    @Bean
    public SimpleMessageListenerContainer simpleMessageListenerContainer(
            ConnectionFactory connectionFactory) {
        SimpleMessageListenerContainer container =
                new SimpleMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        container.setDestinationName("orderQueue");
        return container;
    }


    @Bean
    public ChannelPublishingJmsMessageListener channelPublishingJmsMessageListener() {
        ChannelPublishingJmsMessageListener channelPublishingJmsMessageListener =
                new ChannelPublishingJmsMessageListener();
        channelPublishingJmsMessageListener.setExpectReply(true);


        return channelPublishingJmsMessageListener;
    }


    @Bean
    public MessageChannel inputChannel() {
        return new DirectChannel();
    }


}


@MessageEndpoint
class WarehouseService {


    @ServiceActivator(inputChannel = "inputChannel")
    @Transactional
    public void updateInventory(String message) {
        System.out.println(message);
    }


}

Let’s now run the warehouseService we’ve created and check the ActiveMQ.

现在让我们来运行warehouseService我们已经创建并检查ActiveMQ的。

ActiveMQ admin console
ActiveMQ管理控制台

We have one consumer, one message enqueued, and one message dequeued.

我们有一个使用者,一条消息入队,一条消息出队。

Once again, we’ve seen the beauty of Spring Integration’s method invocation, allowing us to declaratively mark updateInventory with @ServiceActivator to process the message from orderQueue.

再次,我们看到了Spring Integration方法调用的美妙之处,它允许我们使用@ServiceActivator声明性地标记updateInventory以处理来自orderQueue的消息。

结论 (Conclusion)

I hope you’ve enjoyed this article.

希望您喜欢这篇文章。

Happy coding!

编码愉快!

翻译自: https://medium.com/better-programming/spring-boot-integration-inversion-of-control-d65c1a1dcf2a

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Boot集成控制反转 的相关文章

随机推荐

  • E9流程节点表分析

    E9流程节点表分析 流程节点分析 流程节点分析 新建流程审批节点时节点信息会存储到数据库 SELECT FROM workflow nodebase 流程节点表 ISREJECT 0为不可以退回 1为可以退回 ISSTAR 1 为开始节点
  • ​什么是晶振?晶振是怎么制成的?晶振的内部结构,晶振的工作应用以及影响晶振频率相关的参数介绍

    什么是晶振 定义 晶振一般指石英晶体振荡器 也叫晶体振荡器 晶体振荡器是一种使用逆压电效应的电子振荡器电路 即当电场施加在某些材料上时 它会产生机械变形 因此 它利用压电材料的振动晶体的机械共振来产生具有非常精确频率的电信号 晶体振荡器具有
  • Spring的IOC原理[通俗解释一下]

    1 IoC理论的背景 我们都知道 在采用面向对象方法设计的软件系统中 它的底层实现都是由N个对象组成的 所有的对象通过彼此的合作 最终实现系统的业务逻辑 图1 软件系统中耦合的对象 如果我们打开机械式手表的后盖 就会看到与上面类似的情形 各
  • Power BI:切片器联动的一些问题

    问题1 联动切片器选中子项后父项未能显示全部 如下所示 切片器原始状态为 Province和City来源同一张表 当选中了City中的某一项时 变为 父项也发生了变化 但我们希望无论子项选择什么 父项应该始终显示全部 解决办法 City切片
  • javaweb本地启动很快,服务器上面启动特别慢

    在JVM环境中解决 打开 JAVA PATH jre lib security java security这个文件 找到下面的内容 securerandom source file dev urandom替换成 securerandom s
  • 卷麻了,00后测试用例写的比我还好,简直无地自容......

    经常看到无论是刚入职场的新人 还是工作了一段时间的老人 都会对编写测试用例感到困扰 例如 如何编写测试用例 作为一个测试新人 刚开始接触测试 对于怎么写测试用例很是头疼 无法接触需求 只能站在用户角度去做测试 但是这样情况会导致不能全方位测
  • python中深拷贝与浅拷贝的详细解释

    在Python中 当我们对一个对象进行拷贝时 有两种方式 浅拷贝和深拷贝 浅拷贝创建了一个新的对象 其中包含原始对象的引用 而深拷贝则创建了一个完全独立的新对象 其中包含原始对象所有数据的副本 这意味着在原始对象和拷贝对象之间进行更改时 浅
  • 小记 Java stream 中 peek()

    peek 函数 接受一个函数作为参数 这个函数会被应用到每个元素上 并将结果元素映射成一个新的元素 相比于类似 foreach 更类似于lambda中的map函数 map函数 接受一个函数作为参数 这个函数会被应用到每个元素上 并将返回值映
  • ElementUI的自定义模板

    ElementUI自定义模板的使用 前言 一 ElementUI的Input重要属性 二 使用步骤 1 上实例 转自Element官网 2 介绍几个重要参数方法 3 基于以上的介绍 做一个带提示的搜索输入框 总结 前言 ElementUI对
  • 一个java程序员4年4个工作的经历

    今天看到一个帖子说程序员怎么提升自己的技能 里面说了十多项 对自己感觉能有用的有以下几点 读书 读代码 读博客 写博客 回答别人的问题 参加一个开源项目 参加培训 研讨会 回答问题当中给自己的思考 一个毕业生 做java转正了4k 一个室友
  • 为什么要选择云原生数据库

    为什么要选择云原生数据库 前言 1 传统数据库 1 1 传统数据库概念 1 2 传统数据库优缺点 1 2 1 优点 1 2 2 缺点 2 云原生数据库 2 1 云原生数据库概念 2 2 云化代表未来 2 3 云原生数据库的优势 2 3 1
  • 【MATLAB】字符串的处理及矩阵的初步学习

    欢迎访问我的个人网站 reality2ideal xyz 内容在CSDN和个人网站上同步更新 字符串处理 字符串矩阵 gt gt ch 123456 qwerty ch 2 6 char 数组 123456 qwerty 字符串矩阵的列数要
  • 转载:R语言绘图—图形标题、坐标轴设置

    R语言绘图是通过函数命令及相应参数设置实现的 如plot x y plot为绘图函数命令 x y则是绘图参数 指定了绘图的数据向量 但这种最基本的绘图设置很难满足个性化绘图的要求 我们需要根据需要对图形元素进行设置 图形元素是各类图形的基本
  • 生成带干扰线的验证码

    import java awt Color import java awt Font import java awt Graphics2D import java awt Transparency import java awt image
  • vue吸顶导航栏_vue2组件系列第四十二节:NavBar 导航栏

    NavBar就是程序顶部的内容 相当于网站里的面包屑的作用 准备工作 创建一个页面 NavBar vue 在router js里配置NavBar页面的路由 path navbar name navbar component gt impor
  • 左右手坐标系区别和联系

    本文是分析 所谓的右手坐标系转换为左手坐标系需要的 z轴取反 x轴取反 或者改变摄像机位置 渲染绕序改变 其中的进一步的原因 参考文章 https msdn microsoft com en us library bb204853 28VS
  • 真伪定时器

    首先观察一下下面两组代码区别在哪里 第一组代码 setInterval gt 1 5s 的同步逻辑 1000 第二组代码 function fn setTimeout gt 1 5s 的同步逻辑 fn 1000 fn 两组代码都有定时功能
  • Java实体类详解及使用方法

    在Java编程中 实体类 Entity Class 是一种经常使用的类类型 实体类用于表示真实世界中的对象 通常与数据库中的表格相对应 本文将详细介绍Java实体类的概念 特点以及使用方法 什么是实体类 实体类是指用于表示和存储真实世界中的
  • 【论文精读】A view-free image stitching network based on global homography-基于全局单应的无视图图像拼接网络

    论文链接地址 代码链接地址 关于本文的代码 我已经调试过了 在调试过程中遇到的错误 我也做了一些总结 有需要的可以参考这篇博文 A view free image stitching network based on global homo
  • Spring Boot集成控制反转

    Most of the time dependency injection is the first thing that comes to mind whenever the concept of inversion of control