Reactor简介
Reactor是一个基础库,用在构建实时数据流应用、要求有容错和低延迟至毫秒、纳秒、皮秒的服务。
— PrefaceTL;DR
什么是Reactor?
让我们大致了解一下Reactor。在你使用喜欢的搜索敲入一些关键词如Reactive、spring Reactive、Asynchronous java或者仅仅是”What the heck is Reactor?”.简而言之,Reactor是一个轻量级的JVM基础库,它可以帮助我们构建的服务和应用高效而异步的传递消息。
高效的含义是什么呢?
传递一个消息从A到B时GC产生的内存很小或者完全没有。
当消费者处理消息的速度低于生产者产生消息的速度时产生了溢出时,必须尽快处理。
尽可能的提供无锁的异步流。
据以往的经验来看,我们知道异步编程是困难的,特别是当一个平台提供了很多选项如JVM。
Reactor瞄准绝大部分场景中真正的无阻塞,并且提供了一组比原生Jdk的java.util.concurrent库更高效的API。Reactor也提供了一个可选性(不建议使用):
阻塞等待:如Future.get()。
Unsafe数据获取:如ReentrantLock.lock()。
异常抛出:如try ..catch …finally
同步阻塞:如 syschronized
Wrapper配置(GC压力):例如 new Wrapper(event)
让我们先使用一个纯正的Executor方法:
复制代码
private ExecutorService threadPool = Executors.newFixedThreadPool(8);
final List batches = new ArrayList();
Callable t = new Callable() { //1
public T run() {
synchronized(batches) { //2
T result = callDatabase(msg); //3
batches.add(result);
return result;
}
}
};
Future f = threadPool.submit(t); //4
T result = f.get() //5
复制代码
1.分配回调方法—可能会导致gc压力。
2.Synchronization将强制对每个线程停止检查。
3. 存在消费者的消费能力低于生产者生产能力的隐患。
4. 使用线程池将task传递到目标线程–肯定通过FutureTask给gc造成压力。
5. 阻塞直至callDatabase()响应。
从上述的简单示例中,容易看出扩展性会受到严重的影响。
不断分配的对象将导致gc停止工作,特别是耗时比较多的大任务时。当一个gc停止工作时将会从降低全局的性能。
队列默认情况下长度是不受限制的。任务会堆积到数据库中。
后台日志不是一个内存泄露的地方,但是副作用就比较烦人了:在gc暂停工作时需要扫描更多对象;损失数据重要bit的风险;等等。
经典链接Queue分配节点时产生的内存压力。
使用阻塞方式应答请求时发生恶性循环。
阻塞方式应答导致生产者效率慢下来。实际上,因为需要提交更多任务时等待响应,流程变成了基本的同步方式。
同数据存储的通信异常将以不友好的形式传递到生产者,通过线程边界来分离工作,这使容错的协商变的比较容易。
完全的、真正的非阻塞比较难以实现—特别是有比较时髦名称的分布式系统中如微服务架构。然而,Reactor却没有妥协,它试图利用可用的最佳模式来使开发者不必觉得像是在写一个数学论文而仅仅是一个微服务(nanservice)。
spring reactor 多线程配置
首先搭建spring mybatis项目,前面博客已经有搭建步骤
框架spring reactor,可以帮助我们新开一个异步的线程来处理一些比如记录日志的功能,这样就能节约后台相应的时间。
1:引入jar包,这里使用的是maven,只需要引用一个jar包就行了
<dependency>
<groupId>org.projectreactorgroupId>
<artifactId>reactor-springartifactId>
<version>1.0.1.RELEASEversion>
dependency>
2:写一个reactor的配置的bean
package com.baobaotao.reactor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.Environment;
import reactor.core.Reactor;
import reactor.core.spec.Reactors;
import reactor.spring.context.config.EnableReactor;
@Configuration
@EnableReactor
public class ReactorConfig {
@Bean(name="rootReactor")
public Reactor rootReactor(Environment env){
return Reactors.reactor().env(env).get();
}
@Bean(name = "reportReactor")
public Reactor reportReactor(Environment env) {
return Reactors.reactor().env(env).get();
}
}
3:事件的处理类,一般是以Hander结尾,方便区分:
package com.baobaotao.reactor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import reactor.core.Reactor;
import reactor.event.Event;
import reactor.spring.annotation.Selector;
@Component
public class IndexHandler {
@Autowired
@Qualifier("rootReactor")
private Reactor reactor ;
@Autowired
@Qualifier("reportReactor")
private Reactor reactorxx ;
@Selector(value="hello",reactor="@rootReactor")
public void handleTestTopic(Event evt)throws Exception{
System.out.println("************");
}
@Selector(value="hellos",reactor="@reportReactor")
public void handleTestTopics(Event evt)throws Exception{
System.out.println("xxxxxx**********");
String data = evt.getData();
System.out.println(data);
}
}
4:最后就是在controller或者service里面通知新开线程了:
package com.baobaotao.reactor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import reactor.core.Reactor;
import reactor.event.Event;
@Controller
@RequestMapping("/baobaotao/recator/")
public class IndexController {
@Autowired
@Qualifier("rootReactor")
private Reactor r;
@Autowired
@Qualifier("reportReactor")
private Reactor rx;
@RequestMapping("/chen")
@Transactional
@ResponseBody
public void chen() {
r.notify("hello", Event.wrap("你好"));
}
@RequestMapping("/chenzy")
@Transactional
@ResponseBody
public void chenzy() {
rx.notify("hellos", Event.wrap("好"));
}
}
启动程序请求http://127.0.0.1/baobaotao/recator/chenzy
就可以看到log输出
System.out.println("xxxxxx**********");
String data = evt.getData();
System.out.println(data);