命令模式将请求封装成一系列对象,对象里包含指令和数据。
在分布式架构中,master需要给worker分发任务,worker完成后需要把任务处理结果返回给master。
master/worker之间的信息交互会有很多不同的指令和数据,这种不同消息的实现就可以采用命令模式。
我们首先定义一个命令对象
一、命令模式同步实现
public class Command implements Serializable,Cloneable { private static AtomicLong idGenerator=new AtomicLong(1L); private Long id; private String request; private String response; public Command( String content) { this.id = idGenerator.getAndIncrement(); this.request = content; } public String getResponse() { return response; } public void setResponse(String response) { this.response = response; } protected Command clone() { try { return (Command) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } @Override public String toString() { return "Command{" + "id=" + id + ", request='" + request + '\'' + ", response='" + response + '\'' + '}'; } }
然后定义一个master,master负责向worker发送命令
public class Master { void dispatch(Worker worker,Command command){ System.out.println("dispatch a command:"+command +"to "+worker.getClass().getSimpleName()); Command response = worker.process(command); System.out.println("receive a command"+response); } public static void main(String[] args) { Command command1 = new Command("hello,python!"); Command command2 = new Command("hello,java!"); Master master = new Master(); Worker worker1 = new Worker1(); Worker worker2 = new Worker2(); master.dispatch(worker1,command1); master.dispatch(worker2,command2); } }
定义一个worker接口,用于处理命令,并返回任务的结果
public interface Worker { Command process(Command command); } public class Worker1 implements Worker { @Override public Command process(Command command) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Command clone = command.clone(); clone.setResponse("worker1 ok"); return clone; } } public class Worker2 implements Worker { @Override public Command process(Command command) { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } Command clone = command.clone(); clone.setResponse("worker2 ok"); return clone; } }
执行master,输出:
dispatch a command:Command{id=1, request='hello,python!', response='null'}to Worker1 receive a commandCommand{id=1, request='hello,python!', response='worker1 ok'} dispatch a command:Command{id=2, request='hello,java!', response='null'}to Worker2 receive a commandCommand{id=2, request='hello,java!', response='worker2 ok'}
二、命令模式异步实现
其实分布式系统中,更常见的实现是异步io,我们给Worker接口添加一个异步处理方法
public interface Worker { /** * 同步处理 * @param command * @return */ Command process(Command command); /** * 异步处理 * @param command */ void asyncProcess(Command command); }
定义一个实现了Worker接口的实现类
public class AsyncWorker implements Worker { @Override public Command process(Command command) { return null; } @Override public void asyncProcess(Command command){ try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } Command clone = command.clone(); Long id = clone.getId(); clone.setResponse("AsyncWorker ok"); ResponseFuture future = ResponseFuture.getFuture(id); future.putResponse(clone); } }
因为是异步处理,我们定义一个Future类
/** * 任务结果future类 */ public class ResponseFuture { private static final Map<Long,ResponseFuture> futures=new ConcurrentHashMap<>(256); private long requestId; private CountDownLatch latch=new CountDownLatch(1); private Command response; private final InvokeCallback invokeCallback; public ResponseFuture(long requestId, InvokeCallback invokeCallback) { this.requestId = requestId; this.invokeCallback = invokeCallback; futures.put(requestId, this); } public void executeInvokeCallback() { if (invokeCallback != null) { invokeCallback.operationComplete(this); } } public void putResponse(final Command responseCommand) { this.response = responseCommand; this.latch.countDown(); futures.remove(requestId); } public Command getResponseCommand() { return response; } public static ResponseFuture getFuture(long requestId) { return futures.get(requestId); } }
定义一个回调接口,用于获得结果后的回调
/** * 回调接口 */ public interface InvokeCallback { void operationComplete(final ResponseFuture responseFuture); }
因为需要异步获取结果,我们对command类进行了扩展
public class Command implements Serializable,Cloneable { private static AtomicLong idGenerator=new AtomicLong(1L); private Long id; private String request; private String response; public Command( String content) { this.id = idGenerator.getAndIncrement(); this.request = content; } public Long getId() { return id; } public String getResponse() { return response; } public void setResponse(String response) { this.response = response; } protected Command clone() { try { return (Command) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } @Override public String toString() { return "Command{" + "id=" + id + ", request='" + request + '\'' + ", response='" + response + '\'' + '}'; } }
master发生异步请求
public class Master { // void dispatch(Worker worker, Command command) { // System.out.println("dispatch a command:" + command + "to " + worker.getClass().getSimpleName()); // Command response = worker.process(command); // System.out.println("receive a command" + response); // } void dispatchAsync(Worker worker, Command command, final InvokeCallback invokeCallback) { System.out.println("dispatch a command:" + command + "to " + worker.getClass().getSimpleName()); Long requestId = command.getId(); ResponseFuture responseFuture = new ResponseFuture(requestId, invokeCallback); worker.asyncProcess(command); responseFuture.executeInvokeCallback(); } public static void main(String[] args) { Master master = new Master(); // Command command1 = new Command("hello,sync!"); // Worker worker1 = new SyncWorker(); // System.out.println("dispatch Sync"); // master.dispatch(worker1, command1); Command command2 = new Command("hello,async!"); Worker worker2 = new AsyncWorker(); System.out.println("dispatch ASync"); master.dispatchAsync(worker2, command2, new InvokeCallback() { @Override public void operationComplete(ResponseFuture responseFuture) { Command responseCommand = responseFuture.getResponseCommand(); System.out.println(responseCommand); } }); } }
输出:
dispatch ASync dispatch a command:Command{id=1, request='hello,async!', response='null'}to AsyncWorker Command{id=1, request='hello,async!', response='AsyncWorker ok'}
上面的实现是分布式架构的一种简化,以方便在单机进行演示。
实际的分布式架构中,master拿不到worker对象,worker也不可能拿到Future对象,异步消息的传递一般是基于异步io框架(比如netty)的channel来实现的。
netty不是我们本文讨论的重点,这里就不做更多的描述了。