Spring Boot 知识点

Spring Boot 知识点

开启异步线程池

使用注解,可以更便捷的使用基于 Executor 框架的线程池。Spring Boot 框架中提供了一个 AsyncConfigurer 接口以及一个默认的 AsyncConfigurerSupport 实现。通过实现该接口,或继承该实现,可以自定义自己的线程池和异常处理操作。

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
	
	@Override
	public Executor getAsyncExecutor() {
		
		ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 60, 
				TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(2000));
		
		return executor;
	}

}

使用 @EnableAsync 注解启动线程池,之后就可以使用 @Async 注解来标识需要在单独线程中执行的任务了。

@Service
public class AsyncServiceImpl implements AsyncService {

	@Override
	@Async
	public void doSomething() {

		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("doSomething " + Thread.currentThread().getId()
				+ " " + Thread.currentThread().getName());
	}

}
异步消息

多系统之间的消息传递,可以通过读写公共文件、读写同一个数据库,但这些方式延迟高、锁操作频繁,并不适合高并发、高响应的业务场景。所以,基于生产者/消费者模式,Java 引入了消息服务(JMS,Java Message Service)。

消息服务的两种模式

  • 点对点,从一个系统将消息传递到另一个指定的系统。
  • 发布/订阅,消息会发布到不同的主题,系统按需订阅自己需要的主题。

常见消息中间件

  • ActiveMQ,由 Apache 软件基金会研发的纯 Java 程序,是一个操作系统支持 Java 虚拟机就可以运行的消息组件。现在有 ClassicArtemis 两个版本的,可以去官网下载安装

    要使用 ActiveMQ 中间件,需要添加如下依赖:

    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-activemq</artifactId>
    </dependency>
    
    <dependency>
    	<groupId>org.messaginghub</groupId>
    	<artifactId>pooled-jms</artifactId>
    </dependency>
    

    而后,配置中间件的地址、账户及密码等信息,便可以使用自动装配的 JmsTemplate 实例进行消息的发送,并用 @JmsListener 注解监听队列中接收到的消息。

    spring.activemq.broker-url=tcp://localhost:61616
    spring.activemq.user=admin
    spring.activemq.password=admin
    spring.jms.pub-sub-domain=true
    spring.jms.template.default-destination=activemq.default.destination
    spring.activemq.pool.enabled=true
    spring.activemq.pool.max-connections=5
    spring.activemq.packages.trusted=com.test.activemq.domain
    

    在下载安装并启动创建的中间件时,注意本地硬盘空间使用率超过默认的 90% 时,便会阻塞消息的传递。

  • Kafka,是一种高吞吐量的分布式发布订阅消息系统,使用 Scala 和 Java 编写,可以在官网下载安装所需版本。

  • RabbitMQ,同其他消息中间件一样,该组件也支持 AMQP(Advance Message Queuing Protocol)消息协议,去官网下载安装后,在工程中引入下面的依赖便可以使用该中间件。

    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    

    之后,便可以对 RabbitMQ 进行相关的配置,使用 RabbitTemplate 实例进行消息的发送,使用 @RabbitListener 注解来监听队列中的消息,进行后续处理。另外实现 ConfirmCallback 接口来提供消息推送成功确认回调。

    spring.rabbitmq.addresses=localhost
    spring.rabbitmq.port=5672
    spring.rabbitmq.username=guest
    spring.rabbitmq.password=guest
    spring.rabbitmq.publisher-confirm-type=CORRELATED
    
  • RocketMQ,由阿里巴巴自研后捐赠给 Apache 基金会的分布式消息中间件,可以去官网下载所需版本。

定时任务

在 Spring Boot 框架中开启定时任务十分简单,直接使用 @EnableScheduling 注解开启定时任务执行功能。如此,容器中的所有 Bean 都会被扫描,@Scheduled 注解标注的方法会被识别为定时任务。

WebSocket

WebSocket 是基于 TCP 协议的全双工通信协议,使得服务器可以主动向浏览器客户端发送消息。

在 Spring Boot 中,添加下面的依赖:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

然后使用 @ServerEndpoint 注解注册一个服务端点,该注解同 @RequestMapping 类似,会声明该端点的相对路径。添加端点注解后,还需要创建一个 ServerEndpointExporter 实例用来检测并注册他们。

@Service
@ServerEndpoint("/websocket")
public class WebSocketServiceImpl {
	
	private static CopyOnWriteArraySet<WebSocketServiceImpl> websocketSet = 
										new CopyOnWriteArraySet<>();

	private Session session;

	//实际工程中应当将该方法单独放在一个配置类中
	@Bean
	public ServerEndpointExporter serverEndpointExporter() {
		return new ServerEndpointExporter();
	}

	@OnOpen
	public void open(Session session) {
		System.out.println("open");
		
		this.session = session;
		websocketSet.add(this);
		
	}
	
	@OnMessage
	public void onMessage(String message, Session session) {
		try {
			for (Iterator<WebSocketServiceImpl> iterator = websocketSet.iterator(); 
								iterator.hasNext();) {
				WebSocketServiceImpl webSocketServiceImpl = iterator.next();
				webSocketServiceImpl.sendMsg(message);
			}
		} catch (Exception e) {
			
			System.err.println(e);
		}
	}
	
	@OnClose
	public void close() {
		System.out.println("close");
		
		websocketSet.remove(this);
	}
	
	@OnError
	public void onError(Session session, Throwable error) {
		error.printStackTrace();
	}
	
	private void sendMsg(String message) throws IOException {
		this.session.getBasicRemote().sendText(message);
	}
}

之后便可以在支持该协议的浏览器网页建立与服务器的连接,并进行双方的通信。连接相关端点的地址同普通接口访问类似,只是协议名不是 httphttps 而是 ws

var websocket = null

if ('WebSocket' in window) {
    websocket = new WebSocket("ws://localhost:8090/my-spring-boot/websocket")
} else {
    alert("not support websocket")
}

websocket.onerror = function () {
    alert("error")
}

websocket.onclose = function () {
    alert("close")
}

websocket.onopen = function () {
    alert("open")
}

websocket.onmessage = function (event) {
    alert(event.data)
}

window.onbeforeunload = function () {
    websocket.close()
}

function closeWebsocket() {
    websocket.close()
}

function  sendMessage() {
    let message = $('#message').val();
    websocket.send(message)
}
STOMP

并不是所有的浏览器都支持 WebSocket 协议,所以为了兼容它们,可以使用子协议 STOMP(Simple or Streaming Text Orientated Messaging Protocol)。

首先需要使用 @EnableWebSocketMessageBroker 注解启用 STOMP 协议,Spring Boot 会加载自动配置 WebSocketMessagingAutoConfiguration ,当然,也可以自己实现 WebSocketMessageBrokerConfigurer 接口来注册需要的端点。

@Configuration
@EnableWebSocketMessageBroker
public class StompConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/stomp-message").withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/subscribe-message");
        registry.setApplicationDestinationPrefixes("/stomp-request");
    }
}

在自定义配置中注册两个服务端点,并设置订阅和请求路径的前缀。其中 withSockJS() 方法表示支持第三方 SockJS 框架,在使用时应引入下面的库:

<script type="text/javascript"
        src="https://cdn.jsdelivr.net/sockjs/1/sockjs.min.js"></script>

<script type="text/javascript"
        src="https://cdn.bootcdn.net/ajax/libs/stomp.js/2.3.3/stomp.js"></script>

而后,便可以创建连接,发送消息或订阅消息:

/** /my-spring-boot 是服务的上下文路径,/stomp-message 是定义的端点路径 */
let socket = new SockJS('/my-spring-boot/stomp-message')
var stompClient = Stomp.over(socket)

stompClient.connect({}, function () {
	 /** /subscribe-message 是订阅消息时的前缀,/plain 是订阅消息的相对路径 */
    stompClient.subscribe('/subscribe-message/plain', function (data) {
        alert(data)
    })
})

/** /stomp-request 是进行消息操作时的前缀,/send-message 是相对路径 */
stompClient.send("/stomp-request/send-message",{},message)

/stomp-request/send-message 路径便会请求到服务中的标注为 @MessageMapping("/send-message") 的方法。该方法可以使用 @SendTo 标注消息转发的路径,还可以在方法中将消息转发给其他消息中间件。

@Controller
public class StompController {

    @Resource
    private RabbitMqService rabbitMqService;

    @MessageMapping("/send-message")
    @SendTo("/subscribe-message/plain")
    public String sendMsg(String message) {
        System.out.println(message);
        rabbitMqService.sendMsg(message);
        return message;
    }
    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值