├── .gitignore ├── README.md ├── bolt-extension ├── CommandHandler.puml ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── bolt │ │ │ ├── codec │ │ │ ├── AbstractCodec.java │ │ │ ├── BoltCodec.java │ │ │ ├── Codec.java │ │ │ └── CodecAdapter.java │ │ │ ├── common │ │ │ ├── ClassHelper.java │ │ │ ├── Constants.java │ │ │ ├── Decdeable.java │ │ │ ├── DecodeableInvocation.java │ │ │ ├── Holder.java │ │ │ ├── Invocation.java │ │ │ ├── Url.java │ │ │ ├── Version.java │ │ │ ├── buffer │ │ │ │ ├── ChannelBuffer.java │ │ │ │ ├── ChannelBufferInputStream.java │ │ │ │ ├── ChannelBufferOutputStream.java │ │ │ │ └── UnsafeByteArrayInputStream.java │ │ │ ├── command │ │ │ │ ├── AbstractCommand.java │ │ │ │ ├── Command.java │ │ │ │ ├── CommandCode.java │ │ │ │ ├── CommandFactory.java │ │ │ │ ├── RemotingCommand.java │ │ │ │ ├── RequestCommand.java │ │ │ │ └── ResponseCommand.java │ │ │ ├── enums │ │ │ │ ├── CommandCodeEnum.java │ │ │ │ ├── ConnectionEventType.java │ │ │ │ ├── ConnectionTimeoutAction.java │ │ │ │ └── ResponseStatus.java │ │ │ ├── exception │ │ │ │ ├── CodecException.java │ │ │ │ ├── ExecutionException.java │ │ │ │ ├── LifeCycleException.java │ │ │ │ ├── RemotingException.java │ │ │ │ ├── SerializationException.java │ │ │ │ └── TimeoutException.java │ │ │ └── extension │ │ │ │ ├── Extension.java │ │ │ │ └── ExtensionLoader.java │ │ │ ├── config │ │ │ ├── BoltClientOption.java │ │ │ ├── BoltGenericOption.java │ │ │ ├── BoltOption.java │ │ │ ├── BoltOptions.java │ │ │ ├── BoltRemotingOption.java │ │ │ ├── BoltServerOption.java │ │ │ └── Configurable.java │ │ │ ├── protocol │ │ │ ├── BoltProtocol.java │ │ │ ├── Protocol.java │ │ │ ├── ReqBody.java │ │ │ ├── handler │ │ │ │ ├── AbstractCommandHandler.java │ │ │ │ ├── CommandHandler.java │ │ │ │ ├── CommandHandlerManager.java │ │ │ │ ├── GeneralCmdHandler.java │ │ │ │ └── HeartbeatHandler.java │ │ │ └── processor │ │ │ │ ├── AbstractUserProcessorAdapter.java │ │ │ │ ├── SimpleReqProcesser.java │ │ │ │ └── UserProcessor.java │ │ │ ├── reomoting │ │ │ ├── AbstractConnectionHandler.java │ │ │ ├── AbstractLifeCycle.java │ │ │ ├── Connection.java │ │ │ ├── ConnectionEventListener.java │ │ │ ├── ConnectionEventProcessor.java │ │ │ ├── ConnectionHandler.java │ │ │ ├── DefaultFuture.java │ │ │ ├── FutureAdapter.java │ │ │ ├── LifeCycle.java │ │ │ ├── RemotingContext.java │ │ │ ├── ResponseCallback.java │ │ │ └── ResponseFuture.java │ │ │ ├── serialization │ │ │ ├── ObjectInput.java │ │ │ ├── ObjectOutput.java │ │ │ ├── Serialization.java │ │ │ ├── SerializationManager.java │ │ │ └── hessian2 │ │ │ │ ├── Hessian2ObjectInput.java │ │ │ │ ├── Hessian2ObjectOutput.java │ │ │ │ ├── Hessian2Serialization.java │ │ │ │ └── Hessian2SerializerFactory.java │ │ │ ├── transport │ │ │ ├── AbstractClient.java │ │ │ ├── AbstractEndpoint.java │ │ │ ├── AbstractServer.java │ │ │ ├── BoltClient.java │ │ │ ├── BoltHandler.java │ │ │ ├── BoltServer.java │ │ │ ├── Client.java │ │ │ ├── Endpoint.java │ │ │ ├── ReconnectClient.java │ │ │ └── Server.java │ │ │ └── util │ │ │ ├── Bytes.java │ │ │ ├── CountDownLatchUtil.java │ │ │ ├── ExecutorUtil.java │ │ │ ├── NamedThreadFactory.java │ │ │ ├── NetUtils.java │ │ │ ├── ObjectUtils.java │ │ │ └── UrlUtils.java │ └── resources │ │ └── META-INF │ │ └── services │ │ ├── com.bolt.protocol.handler.CommandHandler │ │ ├── com.bolt.protocol.processor.UserProcessor │ │ └── com.bolt.serialization.Serialization │ └── test │ └── java │ └── com │ └── bolt │ ├── async │ ├── ComputeCallable.java │ ├── ComputeFutureTask.java │ └── ComputeTest.java │ ├── callback │ └── FutureCallbackTest.java │ ├── common │ ├── ExecutorUtilTest.java │ ├── NettyAttrTest.java │ ├── UrlTest.java │ ├── command │ │ └── CommandFactoryTest.java │ └── serialize │ │ └── SerializationTest.java │ ├── config │ └── BoltOptionTest.java │ ├── coonection │ ├── AsyncTest.java │ ├── ClientMock.java │ ├── ServerMock.java │ ├── SimpleHandler.java │ └── pool │ │ └── SimpleChannelPoolMap.java │ ├── demo │ ├── BoltClientTest.java │ ├── BoltServerTest.java │ └── RequestBody.java │ ├── threadlocal │ ├── FastThreadLocalRunnable.java │ └── FastThreadLocalTest.java │ └── timertask │ └── TimerTaskTest.java ├── hermes-example ├── hemes-sample-api │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── hermes │ │ └── api │ │ ├── SimpleRequestBody.java │ │ └── SimpleResponseBody.java ├── hermes-sample-client │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── hermes │ │ │ └── HermesClientApplication.java │ │ └── resources │ │ └── application.properties ├── hermes-sample-server │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── hermes │ │ │ ├── HermesServerApplication.java │ │ │ └── processor │ │ │ └── SimpleUerProcessor.java │ │ └── resources │ │ ├── META-INF │ │ └── services │ │ │ └── com.bolt.protocol.processor.UserProcessor │ │ └── application.properties └── pom.xml ├── hermes-spring-boot-starter ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── hermes │ └── autoconfigure │ ├── EnableHermes.java │ ├── HermesAutoConfiguration.java │ └── HermesProperties.java └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | 4 | !**/src/main/** 5 | !**/src/test/** 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | .DS_Store 16 | 17 | ### IntelliJ IDEA ### 18 | .idea 19 | *.iws 20 | *.iml 21 | *.ipr 22 | .mvn 23 | mvnw 24 | mvnw.cmd 25 | 26 | ### NetBeans ### 27 | /nbproject/private/ 28 | /nbbuild/ 29 | /dist/ 30 | /nbdist/ 31 | /.nb-gradle/ 32 | build/ 33 | 34 | ### VS Code ### 35 | .vscode/ 36 | -------------------------------------------------------------------------------- /bolt-extension/CommandHandler.puml: -------------------------------------------------------------------------------- 1 | @startuml 2 | 3 | abstract AbstractCommandHandler 4 | abstract AbstractUserProcessorAdapter 5 | 6 | interface CommandHandler 7 | interface UserProcessor 8 | interface Protocol 9 | interface CommandCode 10 | 11 | Protocol <|..BoltProtocol 12 | 13 | CommandHandlerManager o-- BoltProtocol 14 | 15 | CommandHandlerManager*--CommandHandler 16 | 17 | CommandHandler <|.. AbstractCommandHandler 18 | AbstractCommandHandler <|-- GeneralCmdHandler 19 | AbstractCommandHandler <|-- HeartbeatHandler 20 | 21 | 22 | UserProcessor <|.. AbstractUserProcessorAdapter 23 | AbstractUserProcessorAdapter<|--SimpleReqProcesser 24 | UserProcessor*--GeneralCmdHandler 25 | 26 | CommandCode<|..CommandCodeEnum 27 | 28 | CommandCode o-- CommandHandler 29 | CommandCode o-- UserProcessor 30 | 31 | class GeneralCmdHandler { 32 | ConcurrentHashMap> processors 33 | } 34 | 35 | class BoltProtocol{ 36 | CommandHandlerManager cmdHandlerManager 37 | ExecutorService executor 38 | } 39 | 40 | class CommandHandlerManager{ 41 | Map> CMD_HANDLER_MAP 42 | } 43 | 44 | 45 | interface CommandHandler{ 46 | CommandCode getCommandCode() 47 | void handle(RemotingContext ctx, T command) 48 | boolean handelInIOThread() 49 | } 50 | 51 | abstract class AbstractCommandHandler{ 52 | handle(RemotingContext ctx, T command) 53 | abstract handleRequest(RequestCommand request) 54 | abstract handleResponse(ResponseCommand response) 55 | 56 | } 57 | 58 | 59 | 60 | enum CommandCodeEnum { 61 | GENERAL_CMD, 62 | HEARTBEAT_CMD; 63 | } 64 | 65 | @enduml -------------------------------------------------------------------------------- /bolt-extension/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | hermes 7 | com.criss 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | bolt-extension 13 | 14 | 15 | org.springframework 16 | spring-core 17 | 18 | 19 | io.netty 20 | netty-all 21 | 22 | 23 | com.alibaba 24 | hessian-lite 25 | ${hessian.version} 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/codec/AbstractCodec.java: -------------------------------------------------------------------------------- 1 | package com.bolt.codec; 2 | 3 | import com.bolt.common.Constants; 4 | import com.bolt.reomoting.Connection; 5 | import io.netty.handler.codec.DecoderException; 6 | import io.netty.handler.codec.TooLongFrameException; 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | /** 10 | * @Author: wangxw 11 | * @DateTime: 2020/4/6 12 | * @Description: TODO 13 | */ 14 | @Slf4j 15 | public abstract class AbstractCodec implements Codec { 16 | 17 | public static void checkPlayLoad(Connection connection, long length) { 18 | int payload = Constants.DEFAULT_PAYLOAD; 19 | if (connection != null && connection.getUrl() != null) { 20 | payload = connection.getUrl().getParameter(Constants.PAYLOAD_KEY, Constants.DEFAULT_PAYLOAD); 21 | } 22 | if (payload > 0 && length > payload) { 23 | TooLongFrameException e = new TooLongFrameException("Data length too large: " + length + ", max payload: " + payload); 24 | log.error(e.getMessage(), e); 25 | throw e; 26 | } 27 | } 28 | 29 | protected void checkMagic(byte[] header, int readable) throws DecoderException { 30 | if (readable < 1) { 31 | return; 32 | } 33 | if (header[0] != getMagicCode()) { 34 | throw new DecoderException("Magic code check failed"); 35 | } 36 | } 37 | 38 | protected abstract byte getMagicCode(); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/codec/Codec.java: -------------------------------------------------------------------------------- 1 | package com.bolt.codec; 2 | 3 | import com.bolt.common.buffer.ChannelBuffer; 4 | import com.bolt.common.command.RemotingCommand; 5 | import com.bolt.reomoting.Connection; 6 | import io.netty.handler.codec.DecoderException; 7 | import io.netty.handler.codec.EncoderException; 8 | 9 | /** 10 | * @Author: wangxw 11 | * @DateTime: 2020/4/4 12 | * @Description: TODO 13 | */ 14 | public interface Codec { 15 | 16 | void encode(Connection connection, ChannelBuffer buffer, RemotingCommand msg) throws EncoderException; 17 | 18 | Object decode(Connection connection, ChannelBuffer buffer) throws DecoderException; 19 | 20 | enum DecodeResult { 21 | NEED_MORE_INPUT 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/codec/CodecAdapter.java: -------------------------------------------------------------------------------- 1 | package com.bolt.codec; 2 | 3 | import com.bolt.common.Url; 4 | import com.bolt.common.buffer.ChannelBuffer; 5 | import com.bolt.common.command.RemotingCommand; 6 | import com.bolt.reomoting.Connection; 7 | import io.netty.buffer.ByteBuf; 8 | import io.netty.channel.ChannelHandlerContext; 9 | import io.netty.handler.codec.ByteToMessageDecoder; 10 | import io.netty.handler.codec.MessageToByteEncoder; 11 | import io.netty.util.CharsetUtil; 12 | import lombok.Getter; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * @Author: wangxw 18 | * @DateTime: 2020/4/5 19 | * @Description: TODO 20 | */ 21 | public final class CodecAdapter { 22 | private final Codec codec; 23 | @Getter 24 | private final InternalDecoder decoder = new InternalDecoder(); 25 | @Getter 26 | private final InternalEncoder encoder = new InternalEncoder(); 27 | private Url url; 28 | 29 | public CodecAdapter(Codec codec, Url url) { 30 | this.codec = codec; 31 | this.url = url; 32 | } 33 | 34 | private class InternalDecoder extends ByteToMessageDecoder { 35 | @Override 36 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { 37 | ChannelBuffer buffer = new ChannelBuffer(in); 38 | Connection connection = Connection.getOrAddConnection(ctx.channel(), url); 39 | try { 40 | do { 41 | int saveReadIndex = buffer.readerIndex(); 42 | Object msg = codec.decode(connection, buffer); 43 | if (Codec.DecodeResult.NEED_MORE_INPUT.equals(msg)) { 44 | // 重置读指针 45 | buffer.readerIndex(saveReadIndex); 46 | break; 47 | } else { 48 | if (msg != null) { 49 | out.add(msg); 50 | } 51 | } 52 | } while (buffer.readable()); 53 | 54 | } finally { 55 | // 防止内存泄漏 56 | Connection.removeChannelIfDisconnected(ctx.channel()); 57 | } 58 | } 59 | } 60 | 61 | private class InternalEncoder extends MessageToByteEncoder { 62 | 63 | @Override 64 | protected void encode(ChannelHandlerContext ctx, RemotingCommand cmd, ByteBuf out) throws Exception { 65 | ChannelBuffer buffer = new ChannelBuffer(out); 66 | Connection connection = Connection.getOrAddConnection(ctx.channel(), url); 67 | try { 68 | codec.encode(connection, buffer, cmd); 69 | } finally { 70 | Connection.removeChannelIfDisconnected(ctx.channel()); 71 | } 72 | 73 | } 74 | } 75 | 76 | 77 | } 78 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/ClassHelper.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common; 2 | 3 | /** 4 | * @Author: wangxw 5 | * @DateTime: 2020/3/26 6 | * @Description: TODO 7 | */ 8 | public class ClassHelper { 9 | /** 10 | * @param clazz 11 | * @return 12 | * @see 13 | * @see 14 | */ 15 | public static ClassLoader getClassLoader(Class clazz) { 16 | ClassLoader cl = Thread.currentThread().getContextClassLoader(); 17 | if (cl != null) { 18 | return cl; 19 | } 20 | if (clazz != null) { 21 | cl = clazz.getClassLoader(); 22 | if (cl != null) { 23 | return cl; 24 | } 25 | } 26 | return ClassLoader.getSystemClassLoader(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/Constants.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common; 2 | 3 | import com.bolt.common.enums.ConnectionTimeoutAction; 4 | import io.netty.channel.pool.FixedChannelPool; 5 | 6 | /** 7 | * @Author: wangxw 8 | * @DateTime: 2020/4/6 9 | * @Description: TODO 10 | */ 11 | public class Constants { 12 | public static final String PAYLOAD_KEY = "payload"; 13 | public static final int DEFAULT_PAYLOAD = 8 * 1024 * 1024; // 8M 14 | public static final int DEFAULT_IO_THREADS = Math.min(Runtime.getRuntime().availableProcessors() + 1, 32); 15 | public static final String CONNECT_TIMEOUT_KEY = "connect.timeout"; 16 | public static final int DEFAULT_CONNECT_TIMEOUT = 3000; 17 | public static final String SERIALIZATION_KEY = "serialization"; 18 | public static final String DEFAULT_REMOTING_SERIALIZATION = "hessian2"; 19 | public static final String MAX_CONNECTION = "max.connection"; 20 | public static final Integer DEFAULT_MAX_CONNECTION = 1; 21 | public static final String MAX_PENDING_ACQUIRES = "max.pending.acquires"; 22 | public static final Integer DEFAULT_MAX_PENDING_ACQUIRES = Integer.MAX_VALUE; 23 | public static final String ACQUIRE_TIMEOUT = "acquire.timeout"; 24 | public static final Long DEFAULT_ACQUIRE_TIMEOUT = 3000L; 25 | public static String ACQUIRE_TIMEOUT_ACTION = "acquire.timeout.action"; 26 | public static String DEFAULT_ACQUIRE_TIMEOUT_ACTION = ConnectionTimeoutAction.NEW.value(); 27 | public static String RELEASE_HEALTH_CHECK = "release.health.check"; 28 | public static boolean DEFAULT_RELEASE_HEALTH_CHECK = true; 29 | public static String CONNECTION_LAST_RECENT_USED = "last.recent.used"; 30 | public static boolean DEFAULT_CONNECTION_LAST_RECENT_USED = false; 31 | 32 | public static final String TIMEOUT_KEY = "timeout"; 33 | public static final int DEFAULT_TIMEOUT = 3000; 34 | public static final String ASYNC_KEY = "async"; 35 | public static final String RETURN_KEY = "return"; 36 | public static final String HEARTBEAT_KEY = "heartbeat"; 37 | public static final int DEFAULT_HEARTBEAT = 15 * 1000; 38 | 39 | public static final String MAX_HEARTBEAT_COUNT = "heartbeat.times"; 40 | public static final String HEARTBEAT_TIMEOUT_KEY = "heartbeat.timeout"; 41 | public static final int DEFAULT_MAX_HEARTBEAT_COUNT = 3; 42 | } 43 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/Decdeable.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common; 2 | 3 | import com.bolt.common.exception.SerializationException; 4 | import io.netty.handler.codec.DecoderException; 5 | 6 | import java.io.IOException; 7 | 8 | /** 9 | * @Author: wangxw 10 | * @DateTime: 2020/4/20 11 | * @Description: TODO 12 | */ 13 | public interface Decdeable { 14 | 15 | void decodeClassName() throws DecoderException; 16 | 17 | void decodeData() throws DecoderException; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/DecodeableInvocation.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common; 2 | 3 | import com.bolt.common.command.AbstractCommand; 4 | import com.bolt.common.command.ResponseCommand; 5 | import com.bolt.common.enums.ResponseStatus; 6 | import io.netty.handler.codec.DecoderException; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.util.Assert; 10 | import com.bolt.serialization.ObjectInput; 11 | import com.bolt.serialization.Serialization; 12 | import com.bolt.serialization.SerializationManager; 13 | 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; 17 | 18 | /** 19 | * @Author: wangxw 20 | * @DateTime: 2020/4/6 21 | * @Description: TODO 22 | */ 23 | public class DecodeableInvocation extends Invocation implements Decdeable { 24 | private static final Logger logger = LoggerFactory.getLogger(DecodeableInvocation.class); 25 | 26 | private byte serializationType; 27 | private InputStream inputStream; 28 | private AbstractCommand command; 29 | private static final int DESERIALIZE_NO = 1; 30 | private static final int DESERIALIZE_KEY = 2; 31 | private static final int DESERIALIZE_DATA = 3; 32 | 33 | private volatile int state = DESERIALIZE_NO; 34 | private volatile ObjectInput objectInput; 35 | 36 | private static final AtomicIntegerFieldUpdater STATE_UPDATER = 37 | AtomicIntegerFieldUpdater.newUpdater(DecodeableInvocation.class, "state"); 38 | 39 | public DecodeableInvocation(AbstractCommand command, InputStream is, byte id) { 40 | Assert.notNull(is, "inputStream == null"); 41 | Assert.notNull(command, "Command == null"); 42 | this.command = command; 43 | this.inputStream = is; 44 | this.serializationType = id; 45 | } 46 | 47 | @Override 48 | public void decodeClassName() throws DecoderException { 49 | try { 50 | if (state == DESERIALIZE_NO && inputStream.available() > 0) { 51 | // Response 52 | if (command instanceof ResponseCommand) { 53 | ResponseCommand response = (ResponseCommand) command; 54 | if (!ResponseStatus.SUCCESS.equals(response.getStatus())) { 55 | return; 56 | } 57 | } 58 | if (STATE_UPDATER.compareAndSet(this, DESERIALIZE_NO, DESERIALIZE_KEY)) { 59 | Serialization serialization = SerializationManager.getSerializationById(serializationType); 60 | this.objectInput = serialization.deserialize(inputStream); 61 | String version = objectInput.readUTF(); 62 | command.setVersion(version); 63 | String className = objectInput.readUTF(); 64 | this.setClassName(className); 65 | if (logger.isDebugEnabled()) { 66 | logger.debug("Decode ClassName {}", getClassName()); 67 | } 68 | } 69 | } 70 | } catch (IOException e) { 71 | throw new DecoderException("Decode invocation ClassName failed", e); 72 | } 73 | } 74 | 75 | @Override 76 | public void decodeData() throws DecoderException { 77 | try { 78 | if (state == DESERIALIZE_KEY) { 79 | if (STATE_UPDATER.compareAndSet(this, DESERIALIZE_KEY, DESERIALIZE_DATA)) { 80 | Class clazz = Class.forName(this.getClassName(), false, Thread.currentThread().getContextClassLoader()); 81 | this.setData(objectInput.readObject(clazz)); 82 | if (logger.isDebugEnabled()) { 83 | logger.debug("Decode data {}", getData().toString()); 84 | } 85 | } 86 | } 87 | } catch (IOException | ClassNotFoundException e) { 88 | throw new DecoderException("Decode invocation data failed", e); 89 | } 90 | 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/Holder.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common; 2 | 3 | /** 4 | * @Author: wangxw 5 | * @DateTime: 2020/3/25 6 | * @Description: TODO 7 | */ 8 | public class Holder { 9 | private volatile T value; 10 | 11 | public void set(T value) { 12 | this.value = value; 13 | } 14 | 15 | public T get() { 16 | return value; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/Invocation.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: wangxw 7 | * @DateTime: 2020/4/6 8 | * @Description: TODO 9 | */ 10 | @Data 11 | public class Invocation { 12 | private String className; 13 | private T data; 14 | 15 | 16 | } 17 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/Url.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common; 2 | 3 | 4 | import java.net.InetSocketAddress; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | * @Author: wangxw 10 | * @DateTime: 2020/4/7 11 | * @Description: TODO 12 | */ 13 | public class Url { 14 | private Map parameters; 15 | private String host; 16 | private int port; 17 | public static final String CONNECT_TIMEOUT = Constants.CONNECT_TIMEOUT_KEY; 18 | public static final String TIMEOUT = Constants.TIMEOUT_KEY; 19 | public static final String SERIALIZATION= Constants.SERIALIZATION_KEY; 20 | public static final String MAX_CONNECTION = Constants.MAX_CONNECTION; 21 | public static final String MAX_PENDING_ACQUIRES = Constants.MAX_PENDING_ACQUIRES; 22 | public static final String ACQUIRE_TIMEOUT = Constants.ACQUIRE_TIMEOUT; 23 | public static String ACQUIRE_TIMEOUT_ACTION = Constants.ACQUIRE_TIMEOUT_ACTION; 24 | public static String RELEASE_HEALTH_CHECK = Constants.RELEASE_HEALTH_CHECK; 25 | public static String LAST_RECENT_USED = Constants.CONNECTION_LAST_RECENT_USED; 26 | public static final String ASYNC = Constants.ASYNC_KEY; 27 | public static final String ONEWAY = Constants.RETURN_KEY; 28 | public static final String MAX_HEARTBEAT_COUNT = Constants.MAX_HEARTBEAT_COUNT; 29 | 30 | 31 | public static Url.UrlBuilder builder() { 32 | return new Url.UrlBuilder(); 33 | } 34 | 35 | public Url(String host, int port) { 36 | this(host, port, new HashMap()); 37 | } 38 | 39 | public Url(String host, int port, Map parameters) { 40 | this.host = host; 41 | this.port = port; 42 | this.parameters = parameters; 43 | } 44 | 45 | public T getParameter(String key, T defaultValue) { 46 | Object value = parameters.get(key); 47 | if (value != null) { 48 | return (T) value; 49 | } 50 | 51 | return defaultValue; 52 | 53 | } 54 | 55 | public void addParameters(Map parameters) { 56 | if (parameters == null || parameters.size() == 0) { 57 | return; 58 | } 59 | for (Map.Entry entry : parameters.entrySet()) { 60 | this.parameters.putIfAbsent(entry.getKey(), entry.getValue()); 61 | } 62 | } 63 | 64 | public int getPort() { 65 | return this.port; 66 | } 67 | 68 | public String getHost() { 69 | return this.host; 70 | } 71 | 72 | public void setHost(String host) { 73 | this.host = host; 74 | } 75 | 76 | public void setPort(int port) { 77 | this.port = port; 78 | } 79 | 80 | @Override 81 | public boolean equals(Object obj) { 82 | if (this == obj) { 83 | return true; 84 | } 85 | if (obj == null) { 86 | return false; 87 | } 88 | if (getClass() != obj.getClass()) { 89 | return false; 90 | } 91 | Url other = (Url) obj; 92 | if (host == null) { 93 | if (other.host != null) { 94 | return false; 95 | } 96 | } else if (!host.equals(other.host)) { 97 | return false; 98 | } 99 | if (port != other.port) { 100 | return false; 101 | } 102 | if (parameters == null) { 103 | if (other.parameters != null) { 104 | return false; 105 | } 106 | } else if (!parameters.equals(other.parameters)) { 107 | return false; 108 | } 109 | return true; 110 | } 111 | 112 | @Override 113 | public int hashCode() { 114 | final int prime = 31; 115 | int result = 1; 116 | result = prime * result + ((host == null) ? 0 : host.hashCode()); 117 | result = prime * result + ((parameters == null) ? 0 : parameters.hashCode()); 118 | result = prime * result + port; 119 | return result; 120 | } 121 | 122 | @Override 123 | public String toString() { 124 | StringBuilder builder = new StringBuilder(); 125 | builder.append(getHost()).append(":").append(getPort()); 126 | if (parameters != null && parameters.size() > 0) { 127 | boolean first = true; 128 | for (Map.Entry entry : parameters.entrySet()) { 129 | if (first) { 130 | builder.append("?"); 131 | first = false; 132 | } else { 133 | builder.append("&"); 134 | } 135 | builder.append(entry.getKey()).append("=").append(entry.getValue()); 136 | } 137 | } 138 | return builder.toString(); 139 | } 140 | 141 | public static class UrlBuilder { 142 | private Map parameters; 143 | private String host; 144 | private int port; 145 | 146 | private UrlBuilder() { 147 | 148 | } 149 | 150 | public Url.UrlBuilder host(String host) { 151 | this.host = host; 152 | return this; 153 | } 154 | 155 | public Url.UrlBuilder port(int port) { 156 | this.port = port; 157 | return this; 158 | } 159 | 160 | public Url.UrlBuilder setParameters(Map parameters) { 161 | this.parameters = parameters; 162 | return this; 163 | } 164 | 165 | public Url build() { 166 | Url url = new Url(this.host, this.port); 167 | url.addParameters(this.parameters); 168 | return url; 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/Version.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common; 2 | 3 | /** 4 | * @Author: wangxw 5 | * @DateTime: 2020/4/18 6 | * @Description: TODO 7 | */ 8 | public final class Version { 9 | public static final String DEFAULT_BOLT_PROTOCOL_VERSION = "1.0.0"; 10 | private Version(){ 11 | 12 | } 13 | public static String getProtocolVersion() { 14 | return DEFAULT_BOLT_PROTOCOL_VERSION; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/buffer/ChannelBufferInputStream.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common.buffer; 2 | 3 | 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | /** 8 | * @Author: wangxw 9 | * @DateTime: 2020/4/6 10 | * @Description: TODO 11 | */ 12 | public class ChannelBufferInputStream extends InputStream { 13 | private final ChannelBuffer buffer; 14 | private final int startIndex; 15 | private final int endIndex; 16 | 17 | public ChannelBufferInputStream(ChannelBuffer buffer, int length) { 18 | if (buffer == null) { 19 | throw new NullPointerException("buffer"); 20 | } 21 | if (length < 0) { 22 | throw new IllegalArgumentException("length: " + length); 23 | } 24 | if (length > buffer.readableBytes()) { 25 | throw new IndexOutOfBoundsException(); 26 | } 27 | 28 | this.buffer = buffer; 29 | startIndex = buffer.readerIndex(); 30 | endIndex = startIndex + length; 31 | buffer.markReaderIndex(); 32 | } 33 | 34 | /** 35 | * 返回这个流中已经读取的字节数 36 | * @return 37 | */ 38 | public int readBytes() { 39 | return buffer.readerIndex() - startIndex; 40 | } 41 | 42 | /** 43 | * 返回这个流中的可读字节数 44 | * 45 | * @return 46 | * @throws IOException 47 | */ 48 | @Override 49 | public int available() throws IOException { 50 | return endIndex - buffer.readerIndex(); 51 | } 52 | 53 | /** 54 | * 返回下一个可读字节 55 | * 56 | * @return 57 | * @throws IOException 58 | */ 59 | @Override 60 | public int read() throws IOException { 61 | if (!buffer.readable()) { 62 | return -1; 63 | } 64 | return buffer.readByte() & 0xff; 65 | } 66 | 67 | /** 68 | * 从输入流读取最多 len字节的数据到一个字节数组。 69 | * @param b 70 | * @param off 71 | * @param len 72 | * @return 73 | * @throws IOException 74 | */ 75 | @Override 76 | public int read(byte[] b, int off, int len) throws IOException { 77 | int available = available(); 78 | if (available == 0) { 79 | return -1; 80 | } 81 | 82 | len = Math.min(available, len); 83 | buffer.readBytes(b, off, len); 84 | return len; 85 | } 86 | 87 | /** 88 | * 重置 89 | * @throws IOException 90 | */ 91 | @Override 92 | public void reset() throws IOException { 93 | buffer.resetReaderIndex(); 94 | } 95 | 96 | @Override 97 | public boolean markSupported() { 98 | return true; 99 | } 100 | 101 | /** 102 | * 跳过并丢弃来自此输入流的 n字节数据。 103 | * @param n 104 | * @return 105 | * @throws IOException 106 | */ 107 | @Override 108 | public long skip(long n) throws IOException { 109 | if (n > Integer.MAX_VALUE) { 110 | return skipBytes(Integer.MAX_VALUE); 111 | } else { 112 | return skipBytes((int) n); 113 | } 114 | } 115 | 116 | private int skipBytes(int n) throws IOException { 117 | int nBytes = Math.min(available(), n); 118 | buffer.skipBytes(nBytes); 119 | return nBytes; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/buffer/ChannelBufferOutputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.bolt.common.buffer; 19 | 20 | import java.io.IOException; 21 | import java.io.OutputStream; 22 | 23 | public class ChannelBufferOutputStream extends OutputStream { 24 | 25 | private final ChannelBuffer buffer; 26 | private final int startIndex; 27 | 28 | public ChannelBufferOutputStream(ChannelBuffer buffer) { 29 | if (buffer == null) { 30 | throw new NullPointerException("buffer"); 31 | } 32 | this.buffer = buffer; 33 | startIndex = buffer.writerIndex(); 34 | } 35 | 36 | /** 37 | * 返回已经写入的字节数 38 | * @return 39 | */ 40 | public int writtenBytes() { 41 | return buffer.writerIndex() - startIndex; 42 | } 43 | 44 | @Override 45 | public void write(byte[] b, int off, int len) throws IOException { 46 | if (len == 0) { 47 | return; 48 | } 49 | buffer.writeBytes(b, off, len); 50 | } 51 | 52 | @Override 53 | public void write(byte[] b) throws IOException { 54 | buffer.writeBytes(b); 55 | } 56 | 57 | @Override 58 | public void write(int b) throws IOException { 59 | buffer.writeByte((byte) b); 60 | } 61 | 62 | public ChannelBuffer buffer() { 63 | return buffer; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/buffer/UnsafeByteArrayInputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.bolt.common.buffer; 18 | 19 | import java.io.IOException; 20 | import java.io.InputStream; 21 | 22 | /** 23 | * UnsafeByteArrayInputStream. 24 | */ 25 | public class UnsafeByteArrayInputStream extends InputStream { 26 | protected byte mData[]; 27 | 28 | protected int mPosition, mLimit, mMark = 0; 29 | 30 | public UnsafeByteArrayInputStream(byte buf[]) { 31 | this(buf, 0, buf.length); 32 | } 33 | 34 | public UnsafeByteArrayInputStream(byte buf[], int offset) { 35 | this(buf, offset, buf.length - offset); 36 | } 37 | 38 | public UnsafeByteArrayInputStream(byte buf[], int offset, int length) { 39 | mData = buf; 40 | mPosition = mMark = offset; 41 | mLimit = Math.min(offset + length, buf.length); 42 | } 43 | 44 | @Override 45 | public int read() { 46 | return (mPosition < mLimit) ? (mData[mPosition++] & 0xff) : -1; 47 | } 48 | 49 | @Override 50 | public int read(byte b[], int off, int len) { 51 | if (b == null) { 52 | throw new NullPointerException(); 53 | } 54 | if (off < 0 || len < 0 || len > b.length - off) { 55 | throw new IndexOutOfBoundsException(); 56 | } 57 | if (mPosition >= mLimit) { 58 | return -1; 59 | } 60 | if (mPosition + len > mLimit) { 61 | len = mLimit - mPosition; 62 | } 63 | if (len <= 0) { 64 | return 0; 65 | } 66 | System.arraycopy(mData, mPosition, b, off, len); 67 | mPosition += len; 68 | return len; 69 | } 70 | 71 | @Override 72 | public long skip(long len) { 73 | if (mPosition + len > mLimit) { 74 | len = mLimit - mPosition; 75 | } 76 | if (len <= 0) { 77 | return 0; 78 | } 79 | mPosition += len; 80 | return len; 81 | } 82 | 83 | @Override 84 | public int available() { 85 | return mLimit - mPosition; 86 | } 87 | 88 | @Override 89 | public boolean markSupported() { 90 | return true; 91 | } 92 | 93 | @Override 94 | public void mark(int readAheadLimit) { 95 | mMark = mPosition; 96 | } 97 | 98 | @Override 99 | public void reset() { 100 | mPosition = mMark; 101 | } 102 | 103 | @Override 104 | public void close() throws IOException { 105 | } 106 | 107 | public int position() { 108 | return mPosition; 109 | } 110 | 111 | public void position(int newPosition) { 112 | mPosition = newPosition; 113 | } 114 | 115 | public int size() { 116 | return mData == null ? 0 : mData.length; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/command/AbstractCommand.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common.command; 2 | 3 | import com.bolt.common.Invocation; 4 | import lombok.Data; 5 | 6 | /** 7 | * @Author: wangxw 8 | * @DateTime: 2020/4/6 9 | * @Description: TODO 10 | */ 11 | @Data 12 | public abstract class AbstractCommand implements RemotingCommand { 13 | private int id; 14 | private CommandCode cmdCode; 15 | private boolean heartbeat; 16 | private String version; 17 | private Invocation invocation; 18 | 19 | public AbstractCommand() { 20 | 21 | } 22 | 23 | public AbstractCommand(CommandCode cmdCode) { 24 | this(0, cmdCode); 25 | } 26 | 27 | public AbstractCommand(int id, CommandCode cmdCode) { 28 | this.cmdCode = cmdCode; 29 | this.id = id; 30 | } 31 | 32 | @Override 33 | public Invocation getInvocation() { 34 | return this.invocation; 35 | } 36 | 37 | @Override 38 | public CommandCode getCmdCode() { 39 | return this.cmdCode; 40 | } 41 | 42 | @Override 43 | public int getId() { 44 | return this.id; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/command/Command.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common.command; 2 | 3 | /** 4 | * @Author: wangxw 5 | * @DateTime: 2020/4/11 6 | * @Description: TODO 7 | */ 8 | public abstract class Command { 9 | private final transient CommandCode cmdCode; 10 | 11 | 12 | public Command(CommandCode cmdCode) { 13 | this.cmdCode = cmdCode; 14 | } 15 | 16 | protected CommandCode cmdCode() { 17 | return this.cmdCode; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/command/CommandCode.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common.command; 2 | 3 | /** 4 | * @Author: wangxw 5 | * @DateTime: 2020/3/30 6 | * @Description: TODO 7 | */ 8 | public interface CommandCode { 9 | 10 | short getValue(); 11 | } 12 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/command/CommandFactory.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common.command; 2 | 3 | import com.bolt.common.Invocation; 4 | import com.bolt.common.enums.CommandCodeEnum; 5 | import com.bolt.common.enums.ResponseStatus; 6 | import com.bolt.common.exception.RemotingException; 7 | 8 | 9 | /** 10 | * @Author: wangxw 11 | * @DateTime: 2020/4/11 12 | * @Description: TODO 13 | */ 14 | public class CommandFactory { 15 | 16 | public RequestCommand createRequest(Object request) { 17 | CommandCode cmdCode = CommandCodeEnum.GENERAL_CMD; 18 | if (request instanceof Command) { 19 | Command command = (Command) request; 20 | cmdCode = command.cmdCode(); 21 | } 22 | RequestCommand requestCommand = new RequestCommand(cmdCode); 23 | Invocation invocation = new Invocation(); 24 | invocation.setClassName(request.getClass().getName()); 25 | invocation.setData(request); 26 | requestCommand.setInvocation(invocation); 27 | return requestCommand; 28 | } 29 | 30 | public ResponseCommand createResponse(RequestCommand request, Object response) { 31 | if (response instanceof ResponseCommand) { 32 | return (ResponseCommand) response; 33 | } 34 | ResponseCommand responseCommand = new ResponseCommand(request.getId(), request.getCmdCode()); 35 | responseCommand.setStatus(ResponseStatus.SUCCESS); 36 | Invocation invocation = new Invocation(); 37 | invocation.setClassName(response.getClass().getName()); 38 | invocation.setData(response); 39 | responseCommand.setInvocation(invocation); 40 | return responseCommand; 41 | } 42 | 43 | public ResponseCommand createResponse(RequestCommand request, ResponseStatus status, String errorMsg) { 44 | ResponseCommand responseCommand = new ResponseCommand(request.getId(), request.getCmdCode()); 45 | responseCommand.setStatus(status); 46 | responseCommand.setErrorMessage(errorMsg); 47 | return responseCommand; 48 | 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/command/RemotingCommand.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common.command; 2 | 3 | import com.bolt.common.Invocation; 4 | 5 | /** 6 | * @Author: wangxw 7 | * @DateTime: 2020/4/6 8 | * @Description: TODO 9 | */ 10 | public interface RemotingCommand { 11 | 12 | CommandCode getCmdCode(); 13 | 14 | int getId(); 15 | 16 | Invocation getInvocation(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/command/RequestCommand.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common.command; 2 | 3 | import com.bolt.common.Invocation; 4 | import lombok.Data; 5 | 6 | import java.util.concurrent.atomic.AtomicInteger; 7 | import java.util.concurrent.atomic.AtomicLong; 8 | 9 | /** 10 | * @Author: wangxw 11 | * @DateTime: 2020/4/6 12 | * @Description: TODO 13 | */ 14 | @Data 15 | public class RequestCommand extends AbstractCommand { 16 | private boolean twoWay = true; 17 | private boolean broken = false; 18 | private int timeout; 19 | private static final AtomicInteger INVOKE_ID = new AtomicInteger(0); 20 | 21 | public RequestCommand() { 22 | 23 | } 24 | 25 | public RequestCommand(CommandCode cmdCode) { 26 | super(newId(), cmdCode); 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return "RequestCommand{id=" + getId() + 32 | " cmdCode=" + getCmdCode() + 33 | " isHeartBeat=" + isHeartbeat() + "}"; 34 | } 35 | 36 | private static int newId() { 37 | // getAndIncrement() When it grows to MAX_VALUE, it will grow to MIN_VALUE, and the negative can be used as ID 38 | return INVOKE_ID.getAndIncrement(); 39 | } 40 | 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/command/ResponseCommand.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common.command; 2 | 3 | import com.bolt.common.enums.ResponseStatus; 4 | import lombok.Data; 5 | 6 | /** 7 | * @Author: wangxw 8 | * @DateTime: 2020/4/6 9 | * @Description: TODO 10 | */ 11 | @Data 12 | public class ResponseCommand extends AbstractCommand { 13 | private ResponseStatus status; 14 | private String errorMessage; 15 | 16 | public ResponseCommand(CommandCode cmdCode) { 17 | super(cmdCode); 18 | } 19 | 20 | public ResponseCommand(int id, CommandCode cmdCode) { 21 | super(id, cmdCode); 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | 27 | return "ResponseCommand{status=" + status + 28 | " id=" + getId() + 29 | " cmdCode=" + getCmdCode() + 30 | " isHeartBeat" + isHeartbeat() + "}"; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/enums/CommandCodeEnum.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common.enums; 2 | 3 | import com.bolt.common.command.CommandCode; 4 | import lombok.AllArgsConstructor; 5 | 6 | /** 7 | * @Author: wangxw 8 | * @DateTime: 2020/3/30 9 | * @Description: TODO 10 | */ 11 | @AllArgsConstructor 12 | public enum CommandCodeEnum implements CommandCode { 13 | GENERAL_CMD((short) 0), 14 | HEARTBEAT_CMD((short) 1); 15 | 16 | 17 | private short value; 18 | 19 | @Override 20 | public short getValue() { 21 | return this.value; 22 | } 23 | 24 | public static CommandCodeEnum toEnum(short value) { 25 | for (CommandCodeEnum cmd : values()) { 26 | if (value == cmd.getValue()) { 27 | return cmd; 28 | } 29 | } 30 | throw new IllegalArgumentException("Unknown command code value: " + value); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/enums/ConnectionEventType.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common.enums; 2 | 3 | /** 4 | * @Author: wangxw 5 | * @DateTime: 2020/5/1 6 | * @Description: TODO 7 | */ 8 | public enum ConnectionEventType { 9 | CONNECT, CLOSE, EXCEPTION; 10 | } 11 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/enums/ConnectionTimeoutAction.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | 5 | /** 6 | * @Author: wangxw 7 | * @DateTime: 2020/4/17 8 | * @Description: TODO 9 | */ 10 | @AllArgsConstructor 11 | public enum ConnectionTimeoutAction { 12 | NEW("new"), 13 | FIAL("fail"); 14 | private String value; 15 | 16 | public String value() { 17 | return this.value; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/enums/ResponseStatus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.bolt.common.enums; 18 | 19 | import lombok.AllArgsConstructor; 20 | 21 | /** 22 | * Status of the response. 23 | * 24 | * @author jiangping 25 | * @version $Id: ResponseStatus.java, v 0.1 2015-9-28 PM3:08:12 tao Exp $ 26 | */ 27 | @AllArgsConstructor 28 | public enum ResponseStatus { 29 | 30 | SUCCESS((byte) 101), 31 | SERVER_EXCEPTION((byte) 102), 32 | SERVER_THREADPOOL_BUSY((byte) 103), 33 | NO_PROCESSOR((byte) 104), 34 | CLIENT_TIMEOUT((byte) 105), 35 | SERVER_TIMEOUT((byte) 106), 36 | CLIENT_SEND_ERROR((byte) 107), 37 | CODEC_EXCEPTION((byte) 108), 38 | CONNECTION_CLOSED((byte) 109), 39 | UNKNOWN((byte) 111); 40 | 41 | private byte value; 42 | 43 | public byte value() { 44 | return this.value; 45 | } 46 | 47 | public static ResponseStatus toEnum(byte value) { 48 | for (ResponseStatus status : values()) { 49 | if (value == status.value()) { 50 | return status; 51 | } 52 | } 53 | throw new IllegalArgumentException("Unknown status value ," + value); 54 | } 55 | // 56 | // public byte getValue() { 57 | // switch (this) { 58 | // case SUCCESS: 59 | // return 0x0000; 60 | // case ERROR: 61 | // return 0x0001; 62 | // case SERVER_EXCEPTION: 63 | // return 0x0002; 64 | // case UNKNOWN: 65 | // return 0x0003; 66 | // case SERVER_THREADPOOL_BUSY: 67 | // return 0x0004; 68 | // case ERROR_COMM: 69 | // return 0x0005; 70 | // case NO_PROCESSOR: 71 | // return 0x0006; 72 | // case CLIENT_TIMEOUT: 73 | // return 0x0007; 74 | // case CLIENT_SEND_ERROR: 75 | // return 0x0008; 76 | // case CODEC_EXCEPTION: 77 | // return 0x0009; 78 | // case CONNECTION_CLOSED: 79 | // return 0x0010; 80 | // } 81 | // throw new IllegalArgumentException("Unknown status," + this); 82 | // } 83 | // 84 | // /** 85 | // * Convert to ResponseStatus. 86 | // * 87 | // * @param value 88 | // * @return 89 | // */ 90 | // public static ResponseStatus valueOf(byte value) { 91 | // switch (value) { 92 | // case 10: 93 | // return SUCCESS; 94 | // case 11: 95 | // return SERVER_EXCEPTION; 96 | // case 12: 97 | // return SERVER_THREADPOOL_BUSY; 98 | // case 13: 99 | // return NO_PROCESSOR; 100 | // case 14: 101 | // return CLIENT_TIMEOUT; 102 | // case 15: 103 | // return SERVER_TIMEOUT; 104 | // case 16: 105 | // return CODEC_EXCEPTION; 106 | // case 17: 107 | // return CLIENT_SEND_ERROR; 108 | // case 18: 109 | // return CONNECTION_CLOSED; 110 | // case 19: 111 | // return UNKNOWN; 112 | // 113 | // } 114 | // } 115 | } 116 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/exception/CodecException.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common.exception; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * @Author: wangxw 7 | * @DateTime: 2020/4/6 8 | * @Description: TODO 9 | */ 10 | public class CodecException extends IOException { 11 | public CodecException() { 12 | } 13 | 14 | public CodecException(String message) { 15 | super(message); 16 | } 17 | 18 | public CodecException(String message, Throwable cause) { 19 | super(message, cause); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/exception/ExecutionException.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common.exception; 2 | 3 | import com.bolt.common.command.RemotingCommand; 4 | import com.bolt.reomoting.Connection; 5 | 6 | import java.net.InetSocketAddress; 7 | 8 | /** 9 | * @Author: wangxw 10 | * @DateTime: 2020/5/1 11 | * @Description: TODO 12 | */ 13 | public class ExecutionException extends RemotingException { 14 | private static final long serialVersionUID = 5883088121519596889L; 15 | private final RemotingCommand command; 16 | 17 | public ExecutionException(RemotingCommand command, Connection connection, String msg) { 18 | super(connection, msg); 19 | this.command = command; 20 | } 21 | 22 | public ExecutionException(RemotingCommand command, InetSocketAddress localAddress, InetSocketAddress remoteAddress, String message) { 23 | super(localAddress, remoteAddress, message); 24 | this.command = command; 25 | 26 | } 27 | 28 | public ExecutionException(RemotingCommand command, Connection connection, Throwable cause) { 29 | super(connection, cause); 30 | this.command = command; 31 | 32 | } 33 | 34 | public ExecutionException(RemotingCommand command, InetSocketAddress localAddress, InetSocketAddress remoteAddress, Throwable cause) { 35 | super(localAddress, remoteAddress, cause); 36 | this.command = command; 37 | 38 | } 39 | 40 | public ExecutionException(RemotingCommand command, Connection connection, String message, Throwable cause) { 41 | super(connection, message, cause); 42 | this.command = command; 43 | 44 | } 45 | 46 | public ExecutionException(RemotingCommand command, InetSocketAddress localAddress, InetSocketAddress remoteAddress, String message, Throwable cause) { 47 | super(localAddress, remoteAddress, message, cause); 48 | this.command = command; 49 | } 50 | 51 | public RemotingCommand getCommand() { 52 | return command; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/exception/LifeCycleException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.bolt.common.exception; 18 | 19 | /** 20 | * @author chengyi (mark.lx@antfin.com) 2018-11-05 14:42 21 | */ 22 | public class LifeCycleException extends RuntimeException { 23 | 24 | private static final long serialVersionUID = -5581833793111988391L; 25 | 26 | public LifeCycleException(String message) { 27 | super(message); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/exception/RemotingException.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common.exception; 2 | 3 | import com.bolt.reomoting.Connection; 4 | 5 | import java.net.InetSocketAddress; 6 | 7 | /** 8 | * @Author: wangxw 9 | * @DateTime: 2020/4/20 10 | * @Description: TODO 11 | */ 12 | public class RemotingException extends RuntimeException { 13 | 14 | private static final long serialVersionUID = -6507663755035631766L; 15 | private InetSocketAddress localAddress; 16 | 17 | private InetSocketAddress remoteAddress; 18 | public RemotingException(Connection connection, String msg) { 19 | this(connection == null ? null : connection.getLocalAddress(), 20 | connection == null ? null : connection.getRemoteAddress(), msg); 21 | } 22 | 23 | public RemotingException(InetSocketAddress localAddress, InetSocketAddress remoteAddress, String message) { 24 | super(message); 25 | 26 | this.localAddress = localAddress; 27 | this.remoteAddress = remoteAddress; 28 | } 29 | 30 | public RemotingException(Connection connection, Throwable cause) { 31 | this(connection == null ? null : connection.getLocalAddress(), 32 | connection == null ? null : connection.getRemoteAddress(), cause); 33 | } 34 | 35 | public RemotingException(InetSocketAddress localAddress, InetSocketAddress remoteAddress, Throwable cause) { 36 | super(cause); 37 | this.localAddress = localAddress; 38 | this.remoteAddress = remoteAddress; 39 | } 40 | 41 | public RemotingException(Connection connection, String message, Throwable cause) { 42 | this(connection == null ? null : connection.getLocalAddress(), 43 | connection == null ? null : connection.getRemoteAddress(), message, cause); 44 | } 45 | 46 | public RemotingException(InetSocketAddress localAddress, InetSocketAddress remoteAddress, String message, 47 | Throwable cause) { 48 | super(message, cause); 49 | this.localAddress = localAddress; 50 | this.remoteAddress = remoteAddress; 51 | } 52 | 53 | public InetSocketAddress getLocalAddress() { 54 | return localAddress; 55 | } 56 | 57 | public InetSocketAddress getRemoteAddress() { 58 | return remoteAddress; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/exception/SerializationException.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common.exception; 2 | 3 | /** 4 | * @Author: wangxw 5 | * @DateTime: 2020/4/6 6 | * @Description: TODO 7 | */ 8 | public class SerializationException extends CodecException { 9 | public SerializationException() { 10 | } 11 | 12 | public SerializationException(String message) { 13 | super(message); 14 | } 15 | 16 | public SerializationException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/exception/TimeoutException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.bolt.common.exception; 18 | 19 | import com.bolt.reomoting.Connection; 20 | 21 | import java.net.InetSocketAddress; 22 | 23 | /** 24 | * TimeoutException. (API, Prototype, ThreadSafe) 25 | * 26 | * @export 27 | */ 28 | public class TimeoutException extends RemotingException { 29 | 30 | public static final int CLIENT_SIDE = 0; 31 | public static final int SERVER_SIDE = 1; 32 | private static final long serialVersionUID = 3122966731958222692L; 33 | private final int phase; 34 | 35 | public TimeoutException(boolean serverSide, Connection connection, String message) { 36 | super(connection, message); 37 | this.phase = serverSide ? SERVER_SIDE : CLIENT_SIDE; 38 | } 39 | 40 | public TimeoutException(boolean serverSide, InetSocketAddress localAddress, 41 | InetSocketAddress remoteAddress, String message) { 42 | super(localAddress, remoteAddress, message); 43 | this.phase = serverSide ? SERVER_SIDE : CLIENT_SIDE; 44 | } 45 | 46 | public int getPhase() { 47 | return phase; 48 | } 49 | 50 | public boolean isServerSide() { 51 | return phase == 1; 52 | } 53 | 54 | public boolean isClientSide() { 55 | return phase == 0; 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/common/extension/Extension.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common.extension; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * @Author: wangxw 7 | * @DateTime: 2020/3/25 8 | * @Description: TODO 9 | */ 10 | @Documented 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target({ ElementType.TYPE }) 13 | public @interface Extension { 14 | } 15 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/config/BoltClientOption.java: -------------------------------------------------------------------------------- 1 | package com.bolt.config; 2 | 3 | import com.bolt.common.Constants; 4 | 5 | /** 6 | * @Author: wangxw 7 | * @DateTime: 2020/5/4 8 | * @Description: TODO 9 | */ 10 | public class BoltClientOption extends BoltRemotingOption { 11 | 12 | public static final BoltOption HOST = valueOf(BoltClientOption.class, "host", "127.0.0.1"); 13 | public static final BoltOption PORT = valueOf(BoltClientOption.class, "port", 8091); 14 | 15 | // <-----通信模型------> 16 | public static final BoltOption ASYNC = valueOf(BoltClientOption.class, Constants.ASYNC_KEY, false); 17 | 18 | // <-----空闲检测------> 19 | public static final BoltOption HEARTBEATINTERVAL = valueOf(BoltClientOption.class, Constants.HEARTBEAT_KEY, Constants.DEFAULT_HEARTBEAT); 20 | // 全局请求超时时间 21 | public static final BoltOption TIMEOUT = valueOf(BoltClientOption.class, Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); 22 | // 全局连接超时时间 23 | public static final BoltOption CONNECT_TIMEOUT = valueOf(BoltClientOption.class, Constants.CONNECT_TIMEOUT_KEY, Constants.DEFAULT_CONNECT_TIMEOUT); 24 | 25 | // <-----连接池配置------> 26 | public static final BoltOption MAX_CONNECTION = valueOf(BoltClientOption.class, Constants.MAX_CONNECTION, Constants.DEFAULT_MAX_CONNECTION); 27 | public static final BoltOption MAX_PENDING_ACQUIRES = valueOf(BoltClientOption.class, Constants.MAX_PENDING_ACQUIRES, Constants.DEFAULT_MAX_PENDING_ACQUIRES); 28 | public static final BoltOption ACQUIRE_TIMEOUT = valueOf(BoltClientOption.class, Constants.ACQUIRE_TIMEOUT, Constants.DEFAULT_ACQUIRE_TIMEOUT); 29 | public static final BoltOption ACQUIRE_TIMEOUT_ACTION = valueOf(BoltClientOption.class, Constants.ACQUIRE_TIMEOUT_ACTION, Constants.DEFAULT_ACQUIRE_TIMEOUT_ACTION); 30 | public static final BoltOption RELEASE_HEALTH_CHECK = valueOf(BoltClientOption.class, Constants.RELEASE_HEALTH_CHECK, Constants.DEFAULT_RELEASE_HEALTH_CHECK); 31 | public static final BoltOption CONNECTION_LAST_RECENT_USED = valueOf(BoltClientOption.class, Constants.CONNECTION_LAST_RECENT_USED, Constants.DEFAULT_CONNECTION_LAST_RECENT_USED); 32 | 33 | 34 | protected BoltClientOption(String name, T defaultValue) { 35 | super(name, defaultValue); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/config/BoltGenericOption.java: -------------------------------------------------------------------------------- 1 | package com.bolt.config; 2 | 3 | import com.bolt.common.Constants; 4 | 5 | /** 6 | * @Author: wangxw 7 | * @DateTime: 2020/4/10 8 | * @Description: TODO 9 | */ 10 | public class BoltGenericOption extends BoltOption { 11 | public static final BoltOption TCP_NODELAY = valueOf("bolt.tcp.nodelay",true); 12 | public static final BoltOption TCP_SO_REUSEADDR = valueOf("bolt.tcp.so.reuseaddr",true); 13 | public static final BoltOption TCP_SO_KEEPALIVE = valueOf("bolt.tcp.so.keepalive",true); 14 | public static final BoltOption NETTY_IO_RATIO = valueOf("bolt.netty.io.ratio",70); 15 | public static final BoltOption NETTY_BUFFER_POOLED = valueOf("bolt.netty.buffer.pooled",true); 16 | public static final BoltOption NETTY_BUFFER_HIGH_WATER_MARK = valueOf("bolt.netty.buffer.high.watermark",64 * 1024); 17 | public static final BoltOption NETTY_BUFFER_LOW_WATER_MARK = valueOf("bolt.netty.buffer.low.watermark",32 * 1024); 18 | public static final BoltOption IO_THREADS = valueOf("bolt.netty.server.io.thread", Constants.DEFAULT_IO_THREADS); 19 | 20 | protected BoltGenericOption(String name, T defaultValue) { 21 | super(name, defaultValue); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/config/BoltOption.java: -------------------------------------------------------------------------------- 1 | package com.bolt.config; 2 | 3 | 4 | import java.util.Objects; 5 | 6 | /** 7 | * @Author: wangxw 8 | * @DateTime: 2020/4/9 9 | * @Description: TODO 10 | */ 11 | public class BoltOption { 12 | private final String name; 13 | private T defaultValue; 14 | private Class type; 15 | 16 | protected BoltOption(String name, T defaultValue) { 17 | this.name = name; 18 | this.defaultValue = defaultValue; 19 | this.type = getClass(); 20 | } 21 | 22 | public String name() { 23 | return this.name; 24 | } 25 | 26 | public Class type() { 27 | return this.type; 28 | } 29 | 30 | protected void setType(Class type) { 31 | this.type = type; 32 | } 33 | 34 | public T defaultValue() { 35 | return this.defaultValue; 36 | } 37 | 38 | public static BoltOption valueOf(String name) { 39 | return new BoltOption(name, null); 40 | } 41 | 42 | public static BoltOption valueOf(String name, T defaultValue) { 43 | return new BoltOption(name, defaultValue); 44 | } 45 | 46 | public static BoltOption valueOf(Class type, String name) { 47 | BoltOption option = new BoltOption<>(name, null); 48 | option.setType(type); 49 | return option; 50 | } 51 | 52 | public static BoltOption valueOf(Class type, String name, T defaultValue) { 53 | BoltOption option = new BoltOption<>(name, defaultValue); 54 | option.setType(type); 55 | return option; 56 | } 57 | 58 | @Override 59 | public boolean equals(Object o) { 60 | if (this == o) { 61 | return true; 62 | } 63 | 64 | if (o == null || getClass() != o.getClass()) { 65 | return false; 66 | } 67 | BoltOption that = (BoltOption) o; 68 | return name == null ? Objects.equals(name, that.name) : name == null; 69 | } 70 | 71 | @Override 72 | public int hashCode() { 73 | return name == null ? 0 : name.hashCode(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/config/BoltOptions.java: -------------------------------------------------------------------------------- 1 | package com.bolt.config; 2 | 3 | 4 | import java.util.Collections; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | import java.util.concurrent.ConcurrentMap; 9 | import java.util.stream.Collectors; 10 | 11 | /** 12 | * @Author: wangxw 13 | * @DateTime: 2020/4/9 14 | * @Description: TODO 15 | */ 16 | public class BoltOptions { 17 | 18 | private final ConcurrentMap, Object> options = new ConcurrentHashMap<>(); 19 | 20 | public BoltOptions option(BoltOption option, T value) { 21 | if (value == null) { 22 | options.remove(option); 23 | } else { 24 | options.put(option, value); 25 | } 26 | return this; 27 | } 28 | 29 | public T option(BoltOption option) { 30 | Object value = options.get(option); 31 | if (value == null) { 32 | options.put(option, option.defaultValue()); 33 | value = option.defaultValue(); 34 | 35 | } 36 | return value == null ? null : (T) value; 37 | } 38 | 39 | public Map options(Class type) { 40 | return options().entrySet() 41 | .stream() 42 | .filter(option -> option.getKey().type().equals(type)) 43 | .collect(Collectors.toMap(e -> e.getKey().name(), Map.Entry::getValue)); 44 | } 45 | 46 | final Map, Object> options() { 47 | synchronized (options) { 48 | return copiedMap(options); 49 | } 50 | } 51 | 52 | static Map copiedMap(Map map) { 53 | if (map.isEmpty()) { 54 | return Collections.emptyMap(); 55 | } 56 | return Collections.unmodifiableMap(new HashMap(map)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/config/BoltRemotingOption.java: -------------------------------------------------------------------------------- 1 | package com.bolt.config; 2 | 3 | import com.bolt.common.Constants; 4 | 5 | /** 6 | * @Author: wangxw 7 | * @DateTime: 2020/4/10 8 | * @Description: TODO 9 | */ 10 | public class BoltRemotingOption extends BoltOption { 11 | public static final BoltOption SERIALIZATION = valueOf(BoltRemotingOption.class, Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION); 12 | protected BoltRemotingOption(String name, T defaultValue) { 13 | super(name, defaultValue); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/config/BoltServerOption.java: -------------------------------------------------------------------------------- 1 | package com.bolt.config; 2 | 3 | /** 4 | * @Author: wangxw 5 | * @DateTime: 2020/4/21 6 | * @Description: TODO 7 | */ 8 | public class BoltServerOption extends BoltOption { 9 | public static final BoltOption PORT = valueOf("bolt.server.port",8090); 10 | 11 | protected BoltServerOption(String name, T defaultValue) { 12 | super(name, defaultValue); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/config/Configurable.java: -------------------------------------------------------------------------------- 1 | package com.bolt.config; 2 | 3 | /** 4 | * @Author: wangxw 5 | * @DateTime: 2020/4/10 6 | * @Description: TODO 7 | */ 8 | public interface Configurable { 9 | 10 | Configurable option(BoltOption option, T value); 11 | 12 | T option(BoltOption option); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/protocol/BoltProtocol.java: -------------------------------------------------------------------------------- 1 | package com.bolt.protocol; 2 | 3 | import com.bolt.common.command.CommandCode; 4 | import com.bolt.protocol.handler.CommandHandler; 5 | import com.bolt.protocol.handler.CommandHandlerManager; 6 | import com.bolt.util.NamedThreadFactory; 7 | 8 | import java.util.concurrent.*; 9 | 10 | /** 11 | * @Author: wangxw 12 | * @DateTime: 2020/4/4 13 | * @Description: TODO 14 | */ 15 | public class BoltProtocol implements Protocol { 16 | private final CommandHandlerManager cmdHandlerManager; 17 | private ExecutorService executor; 18 | 19 | public BoltProtocol() { 20 | this.cmdHandlerManager = new CommandHandlerManager(); 21 | 22 | this.executor = new ThreadPoolExecutor(8, 23 | 16, 24 | 20, 25 | TimeUnit.SECONDS, 26 | new ArrayBlockingQueue<>(60), 27 | new NamedThreadFactory("Bolt-protocol-executor", true)); 28 | } 29 | 30 | @Override 31 | public CommandHandler getCommandHandler(CommandCode cmdCode) { 32 | return this.cmdHandlerManager.getCmdHandler(cmdCode); 33 | } 34 | 35 | @Override 36 | public ExecutorService getDefaultExecutor() { 37 | return this.executor; 38 | } 39 | 40 | @Override 41 | public void setExecutor(ExecutorService executor) { 42 | this.executor = executor; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/protocol/Protocol.java: -------------------------------------------------------------------------------- 1 | package com.bolt.protocol; 2 | 3 | import com.bolt.common.command.CommandCode; 4 | import com.bolt.protocol.handler.CommandHandler; 5 | 6 | import java.util.concurrent.ExecutorService; 7 | 8 | /** 9 | * @Author: wangxw 10 | * @DateTime: 2020/4/4 11 | * @Description: TODO 12 | */ 13 | public interface Protocol { 14 | 15 | CommandHandler getCommandHandler(CommandCode cmdCode); 16 | 17 | ExecutorService getDefaultExecutor(); 18 | 19 | void setExecutor(ExecutorService executor); 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/protocol/ReqBody.java: -------------------------------------------------------------------------------- 1 | package com.bolt.protocol; 2 | 3 | 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @Author: wangxw 10 | * @DateTime: 2020/4/20 11 | * @Description: TODO 12 | */ 13 | @Data 14 | public class ReqBody implements Serializable { 15 | private String name; 16 | private Integer age; 17 | } 18 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/protocol/handler/AbstractCommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.bolt.protocol.handler; 2 | 3 | import com.bolt.common.DecodeableInvocation; 4 | import com.bolt.common.enums.ResponseStatus; 5 | import com.bolt.reomoting.Connection; 6 | import com.bolt.reomoting.DefaultFuture; 7 | import com.bolt.reomoting.RemotingContext; 8 | import com.bolt.common.command.*; 9 | import com.bolt.common.exception.RemotingException; 10 | import com.bolt.util.ObjectUtils; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import java.util.Optional; 15 | import java.util.concurrent.CompletableFuture; 16 | import java.util.concurrent.ExecutorService; 17 | 18 | /** 19 | * @Author: wangxw 20 | * @DateTime: 2020/4/19 21 | * @Description: TODO 22 | */ 23 | public abstract class AbstractCommandHandler implements CommandHandler { 24 | private static final Logger logger = LoggerFactory.getLogger(AbstractCommandHandler.class); 25 | protected CommandFactory commandFactory; 26 | 27 | public AbstractCommandHandler() { 28 | this.commandFactory = new CommandFactory(); 29 | } 30 | 31 | @Override 32 | public boolean handelInIOThread() { 33 | return true; 34 | } 35 | 36 | @Override 37 | public void handle(RemotingContext ctx, T cmd) throws RemotingException { 38 | ExecutorService executor = handelInIOThread() 39 | ? ctx.getEventLoop() : ctx.protocolExecutor(); 40 | 41 | // IO thread decode className 42 | DecodeableInvocation inv = (DecodeableInvocation) cmd.getInvocation(); 43 | inv.decodeClassName(); 44 | try { 45 | executor.execute(new HandlerRunnable(ctx, cmd)); 46 | } catch (Throwable e) { 47 | throw new RemotingException(ctx.getConnection(), ObjectUtils.toString(e)); 48 | } 49 | 50 | 51 | } 52 | 53 | class HandlerRunnable implements Runnable { 54 | private RemotingContext context; 55 | private T command; 56 | 57 | public HandlerRunnable(RemotingContext context, T command) { 58 | this.context = context; 59 | this.command = command; 60 | } 61 | 62 | @Override 63 | public void run() { 64 | DecodeableInvocation invocation = (DecodeableInvocation) command.getInvocation(); 65 | // IO thread or biz thread decode data 66 | invocation.decodeData(); 67 | try { 68 | Connection connection = context.getConnection(); 69 | if (command instanceof RequestCommand) { 70 | RequestCommand request = (RequestCommand) command; 71 | if (request.isBroken()) { 72 | Throwable t = (Throwable) invocation.getData(); 73 | ResponseCommand response = commandFactory.createResponse(request, ResponseStatus.SERVER_EXCEPTION, ObjectUtils.toString(t)); 74 | connection.sendResponseIfNecessary(request, response); 75 | return; 76 | } 77 | try { 78 | Object result = handleRequest(context, request); 79 | // 服务端异步支持 80 | if (result instanceof CompletableFuture) { 81 | CompletableFuture future = (CompletableFuture) result; 82 | future.whenComplete((r, t) -> { 83 | if (t != null) { 84 | connection.sendResponseIfNecessary(request, 85 | commandFactory.createResponse(request, ResponseStatus.SERVER_EXCEPTION, ObjectUtils.toString(t))); 86 | } 87 | if (r != null) { 88 | connection.sendResponseIfNecessary(request, commandFactory.createResponse(request, result)); 89 | } 90 | }); 91 | return; 92 | } 93 | if (result != null) { 94 | connection.sendResponseIfNecessary(request, commandFactory.createResponse(request, result)); 95 | } 96 | } catch (Throwable t) { 97 | connection.sendResponseIfNecessary(request, 98 | commandFactory.createResponse(request, ResponseStatus.SERVER_EXCEPTION, ObjectUtils.toString(t))); 99 | } 100 | } else if (command instanceof ResponseCommand) { 101 | handleResponse(context, (ResponseCommand) command); 102 | } 103 | } catch (Throwable e) { 104 | logger.warn("HandlerRunnable handle {} operation error, connection is {}", command, context.getConnection(), e); 105 | } 106 | } 107 | } 108 | 109 | public abstract T handleRequest(RemotingContext ctx, RequestCommand request) throws Exception; 110 | 111 | protected void handleResponse(RemotingContext ctx, ResponseCommand response) { 112 | if (response.isHeartbeat()) { 113 | if (logger.isDebugEnabled()) { 114 | logger.debug("Received heartbeat response from remote connection " + ctx.getConnection()); 115 | } 116 | } 117 | Connection connection = ctx.getConnection(); 118 | DefaultFuture.received(connection, response); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/protocol/handler/CommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.bolt.protocol.handler; 2 | 3 | import com.bolt.common.exception.RemotingException; 4 | import com.bolt.reomoting.RemotingContext; 5 | import com.bolt.common.command.CommandCode; 6 | import com.bolt.common.extension.Extension; 7 | 8 | 9 | /** 10 | * @Author: wangxw 11 | * @DateTime: 2020/4/4 12 | * @Description: TODO 13 | */ 14 | @Extension 15 | public interface CommandHandler { 16 | 17 | CommandCode getCommandCode(); 18 | 19 | void handle(RemotingContext ctx, T command) throws RemotingException; 20 | 21 | boolean handelInIOThread(); 22 | } 23 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/protocol/handler/CommandHandlerManager.java: -------------------------------------------------------------------------------- 1 | package com.bolt.protocol.handler; 2 | 3 | import com.bolt.common.command.CommandCode; 4 | import com.bolt.common.extension.ExtensionLoader; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.util.Optional; 9 | import java.util.Set; 10 | import java.util.concurrent.*; 11 | 12 | /** 13 | * @Author: wangxw 14 | * @DateTime: 2020/4/4 15 | * @Description: TODO 16 | */ 17 | public class CommandHandlerManager { 18 | private static final Logger logger = LoggerFactory.getLogger(CommandHandlerManager.class); 19 | private static final ConcurrentHashMap> CMD_HANDLER_MAP = new ConcurrentHashMap(4); 20 | 21 | static { 22 | Set supportedExtensions = ExtensionLoader.getExtensionLoader(CommandHandler.class).getSupportedExtensions(); 23 | for (String name : supportedExtensions) { 24 | CommandHandler commandHandler = ExtensionLoader.getExtensionLoader(CommandHandler.class).getExtension(name); 25 | CommandCode cmdCode = commandHandler.getCommandCode(); 26 | if (CMD_HANDLER_MAP.get(cmdCode) != null) { 27 | logger.error("CommandHandler extension " + commandHandler.getClass().getName() 28 | + " has duplicate version to Protocol extension " 29 | + CMD_HANDLER_MAP.get(cmdCode).getClass().getName() 30 | + ", ignore this CommandHandler extension"); 31 | continue; 32 | } 33 | CMD_HANDLER_MAP.put(cmdCode, commandHandler); 34 | if (logger.isDebugEnabled()) { 35 | logger.debug("Register cmdCode [" + cmdCode + "] with CommandHandler [" + commandHandler.getClass().getName() + "]"); 36 | } 37 | } 38 | } 39 | 40 | public CommandHandler getCmdHandler(CommandCode cmdCode) { 41 | return Optional.ofNullable(CMD_HANDLER_MAP.get(cmdCode)) 42 | .orElseThrow(() -> new IllegalArgumentException("CmdCode " + cmdCode + " no register CommandHandler")); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/protocol/handler/GeneralCmdHandler.java: -------------------------------------------------------------------------------- 1 | package com.bolt.protocol.handler; 2 | 3 | import com.bolt.common.DecodeableInvocation; 4 | import com.bolt.common.Invocation; 5 | import com.bolt.common.command.RemotingCommand; 6 | import com.bolt.common.extension.ExtensionLoader; 7 | import com.bolt.reomoting.Connection; 8 | import com.bolt.reomoting.DefaultFuture; 9 | import com.bolt.reomoting.RemotingContext; 10 | import com.bolt.common.command.CommandCode; 11 | import com.bolt.common.command.RequestCommand; 12 | import com.bolt.common.command.ResponseCommand; 13 | import com.bolt.common.enums.CommandCodeEnum; 14 | import com.bolt.common.exception.RemotingException; 15 | import com.bolt.protocol.processor.UserProcessor; 16 | import org.apache.commons.lang3.StringUtils; 17 | 18 | import java.util.Optional; 19 | import java.util.Set; 20 | import java.util.concurrent.ConcurrentHashMap; 21 | import java.util.concurrent.ExecutorService; 22 | 23 | /** 24 | * @Author: wangxw 25 | * @DateTime: 2020/4/19 26 | * @Description: TODO 27 | */ 28 | public class GeneralCmdHandler extends AbstractCommandHandler { 29 | private ConcurrentHashMap> processors = new ConcurrentHashMap>(4); 30 | 31 | public GeneralCmdHandler() { 32 | Set supportedExtensions = ExtensionLoader.getExtensionLoader(UserProcessor.class).getSupportedExtensions(); 33 | for (String name : supportedExtensions) { 34 | UserProcessor processor = ExtensionLoader.getExtensionLoader(UserProcessor.class).getExtension(name); 35 | if (!StringUtils.isNotBlank(processor.interest())) { 36 | throw new IllegalArgumentException("Processor interest should not be blank!"); 37 | } 38 | UserProcessor preProcessor = processors.putIfAbsent(processor.interest(), 39 | processor); 40 | 41 | if (preProcessor != null) { 42 | String errMsg = "Processor with interest key [" 43 | + processor.interest() 44 | + "] has already been registered, can not register again!"; 45 | throw new IllegalArgumentException(errMsg); 46 | } 47 | } 48 | } 49 | 50 | 51 | // private void registerProcessor(UserProcessor processor) { 52 | // ObjectUtils.isNotNull(processor, "Processer should benot null"); 53 | // if (!StringUtils.isNotBlank(processor.interest())) { 54 | // throw new IllegalArgumentException("Processor interest should not be blank!"); 55 | // } 56 | // UserProcessor preProcessor = processors.putIfAbsent(processor.interest(), 57 | // processor); 58 | // if (preProcessor != null) { 59 | // String errMsg = "Processor with interest key [" 60 | // + processor.interest() 61 | // + "] has already been registered, can not register again!"; 62 | // throw new IllegalArgumentException(errMsg); 63 | // } 64 | // } 65 | 66 | @Override 67 | public CommandCode getCommandCode() { 68 | return CommandCodeEnum.GENERAL_CMD; 69 | } 70 | 71 | @Override 72 | public void handle(RemotingContext ctx, RemotingCommand cmd) throws RemotingException { 73 | UserProcessor processor = null; 74 | ExecutorService executor = null; 75 | 76 | Optional invocation = Optional.ofNullable(cmd.getInvocation()); 77 | 78 | invocation.ifPresent(inv->{ 79 | DecodeableInvocation dinv =(DecodeableInvocation)inv; 80 | dinv.decodeClassName(); 81 | }); 82 | 83 | if (cmd instanceof RequestCommand) { 84 | processor = processors.get(invocation.get().getClassName()); 85 | if (processor == null) { 86 | String errorMsg = "No UserProcesser found by interest: " + invocation.get().getClassName()+" from GeneralCmdHandler"; 87 | throw new RemotingException(ctx.getConnection(), errorMsg); 88 | } 89 | executor = processor.processInIOThread() 90 | ? ctx.getEventLoop() : Optional.ofNullable(processor.getExecutor()) 91 | .orElseGet(() -> ctx.protocolExecutor()); 92 | 93 | } else if (cmd instanceof ResponseCommand) { 94 | executor = handelInIOThread() 95 | ? ctx.getEventLoop() : ctx.protocolExecutor(); 96 | } 97 | try { 98 | executor.execute(new HandlerRunnable(ctx, cmd)); 99 | } catch (Throwable e) { 100 | throw new RemotingException(ctx.getConnection(), e); 101 | } 102 | } 103 | 104 | @Override 105 | public Object handleRequest(RemotingContext ctx, RequestCommand request) throws Exception { 106 | Invocation inv = request.getInvocation(); 107 | UserProcessor processor = processors.get(inv.getClassName()); 108 | return processor.handleRequest(inv.getData()); 109 | } 110 | 111 | @Override 112 | public boolean handelInIOThread() { 113 | return false; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/protocol/handler/HeartbeatHandler.java: -------------------------------------------------------------------------------- 1 | package com.bolt.protocol.handler; 2 | 3 | import com.bolt.common.Constants; 4 | import com.bolt.common.Version; 5 | import com.bolt.common.command.CommandCode; 6 | import com.bolt.common.command.RequestCommand; 7 | import com.bolt.common.command.ResponseCommand; 8 | import com.bolt.common.enums.CommandCodeEnum; 9 | import com.bolt.common.enums.ResponseStatus; 10 | import com.bolt.reomoting.Connection; 11 | import com.bolt.reomoting.RemotingContext; 12 | import com.bolt.transport.ReconnectClient; 13 | import io.netty.util.Attribute; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | 17 | import java.util.concurrent.locks.Lock; 18 | import java.util.concurrent.locks.ReentrantLock; 19 | 20 | /** 21 | * @Author: wangxw 22 | * @DateTime: 2020/5/4 23 | * @Description: TODO 24 | */ 25 | public class HeartbeatHandler extends AbstractCommandHandler { 26 | private static final Logger logger = LoggerFactory.getLogger(HeartbeatHandler.class); 27 | private Lock connectionLock = new ReentrantLock(); 28 | private ReconnectClient reconnectClient; 29 | 30 | @Override 31 | public Object handleRequest(RemotingContext ctx, RequestCommand request) throws Exception { 32 | ResponseCommand response = new ResponseCommand(request.getId(), request.getCmdCode()); 33 | response.setStatus(ResponseStatus.SUCCESS); 34 | response.setHeartbeat(true); 35 | response.setVersion(Version.getProtocolVersion()); 36 | if (logger.isDebugEnabled()) { 37 | logger.debug("Received heartbeat from remote connection " + ctx.getConnection()); 38 | } 39 | return response; 40 | } 41 | 42 | @Override 43 | public CommandCode getCommandCode() { 44 | return CommandCodeEnum.HEARTBEAT_CMD; 45 | } 46 | 47 | public void sendHeartbeat(Connection connection) { 48 | // 心跳次数 49 | Integer heartbeatCount = connection.attr(Connection.HEARTBEAT_COUNT).get(); 50 | Integer maxCount = connection.getUrl().getParameter(Constants.MAX_HEARTBEAT_COUNT, 51 | Constants.DEFAULT_MAX_HEARTBEAT_COUNT); 52 | if (heartbeatCount > maxCount) { 53 | // 关闭连接并重连 54 | connectionLock.lock(); 55 | try { 56 | if (connection.isActive()) { 57 | connection.close(); 58 | } 59 | if(!connection.isActive()){ 60 | reconnectClient.reconnect(connection.getUrl()); 61 | } 62 | } finally { 63 | connectionLock.unlock(); 64 | } 65 | 66 | } else { 67 | RequestCommand request = new RequestCommand(CommandCodeEnum.HEARTBEAT_CMD); 68 | request.setTwoWay(true); 69 | request.setVersion(Version.getProtocolVersion()); 70 | request.setHeartbeat(true); 71 | 72 | connection.send(request, 1000).whenComplete(((res, cause) -> { 73 | if (cause != null) { 74 | Integer oldCount; 75 | Integer newCount; 76 | Attribute HEARTBEAT_COUNT = connection.attr(Connection.HEARTBEAT_COUNT); 77 | do { 78 | oldCount = HEARTBEAT_COUNT.get(); 79 | newCount = oldCount + 1; 80 | } while (!HEARTBEAT_COUNT.compareAndSet(oldCount, newCount)); 81 | return; 82 | } 83 | })); 84 | 85 | if (logger.isDebugEnabled()) { 86 | logger.debug("Send heartbeat to remote connection " + connection + ", heartbeat times " + connection.attr(Connection.HEARTBEAT_COUNT).get()); 87 | } 88 | } 89 | } 90 | 91 | public void setReconnectClient(ReconnectClient reconnectClient) { 92 | this.reconnectClient = reconnectClient; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/protocol/processor/AbstractUserProcessorAdapter.java: -------------------------------------------------------------------------------- 1 | package com.bolt.protocol.processor; 2 | 3 | import com.bolt.common.command.CommandCode; 4 | import com.bolt.common.enums.CommandCodeEnum; 5 | import com.bolt.util.NamedThreadFactory; 6 | 7 | import java.lang.reflect.ParameterizedType; 8 | import java.util.concurrent.*; 9 | 10 | /** 11 | * @Author: wangxw 12 | * @DateTime: 2020/4/20 13 | * @Description: TODO 14 | */ 15 | public abstract class AbstractUserProcessorAdapter implements UserProcessor { 16 | 17 | private ExecutorService executor; 18 | 19 | @Override 20 | public ExecutorService getExecutor() { 21 | return executor; 22 | } 23 | 24 | @Override 25 | public boolean processInIOThread() { 26 | return false; 27 | } 28 | 29 | @Override 30 | public CommandCode cmdCode() { 31 | return CommandCodeEnum.GENERAL_CMD; 32 | } 33 | 34 | public void setExecutor(ExecutorService executor) { 35 | this.executor = executor; 36 | } 37 | 38 | @Override 39 | public String interest() { 40 | Class interestClazz = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 41 | return interestClazz.getName(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/protocol/processor/SimpleReqProcesser.java: -------------------------------------------------------------------------------- 1 | package com.bolt.protocol.processor; 2 | 3 | import com.bolt.common.command.CommandCode; 4 | import com.bolt.common.enums.CommandCodeEnum; 5 | import com.bolt.protocol.ReqBody; 6 | import com.bolt.protocol.processor.AbstractUserProcessorAdapter; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | 11 | /** 12 | * @Author: wangxw 13 | * @DateTime: 2020/4/20 14 | * @Description: TODO 15 | */ 16 | public class SimpleReqProcesser extends AbstractUserProcessorAdapter { 17 | private Logger logger = LoggerFactory.getLogger(getClass()); 18 | 19 | @Override 20 | public String interest() { 21 | return ReqBody.class.getName(); 22 | } 23 | 24 | 25 | @Override 26 | public String handleRequest(ReqBody body) throws Exception { 27 | logger.error("handleRequest: " + body.toString()); 28 | 29 | return "server success"; 30 | } 31 | 32 | @Override 33 | public boolean processInIOThread() { 34 | return false; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/protocol/processor/UserProcessor.java: -------------------------------------------------------------------------------- 1 | package com.bolt.protocol.processor; 2 | 3 | import com.bolt.common.command.CommandCode; 4 | import com.bolt.common.extension.Extension; 5 | 6 | import java.util.concurrent.Executor; 7 | import java.util.concurrent.ExecutorService; 8 | 9 | /** 10 | * @Author: wangxw 11 | * @DateTime: 2020/4/19 12 | * @Description: TODO 13 | */ 14 | @Extension 15 | public interface UserProcessor { 16 | 17 | String interest(); 18 | 19 | CommandCode cmdCode(); 20 | 21 | ExecutorService getExecutor(); 22 | 23 | boolean processInIOThread(); 24 | 25 | Object handleRequest(T request) throws Exception; 26 | } 27 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/reomoting/AbstractConnectionHandler.java: -------------------------------------------------------------------------------- 1 | package com.bolt.reomoting; 2 | 3 | import com.bolt.common.Constants; 4 | import com.bolt.common.command.RemotingCommand; 5 | import com.bolt.common.command.RequestCommand; 6 | import com.bolt.common.command.ResponseCommand; 7 | import com.bolt.common.exception.RemotingException; 8 | import io.netty.channel.ChannelFuture; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import java.util.concurrent.CompletableFuture; 13 | 14 | /** 15 | * @Author: wangxw 16 | * @DateTime: 2020/4/24 17 | * @Description: TODO 18 | */ 19 | public abstract class AbstractConnectionHandler implements ConnectionHandler { 20 | private static final Logger logger = LoggerFactory.getLogger(AbstractConnectionHandler.class); 21 | 22 | public FutureAdapter send(RequestCommand request, int timeout){ 23 | DefaultFuture future = DefaultFuture.newFuture(getConnection(), request, timeout); 24 | FutureAdapter futureAdapter = new FutureAdapter<>(future); 25 | writeAndFlush(request).addListener(f->{ 26 | if (f.isSuccess()) { 27 | future.sent(); 28 | } 29 | if (!f.isSuccess()) { 30 | // 取消 31 | future.cancel(); 32 | throw new RemotingException(getConnection(), createErrorMsg(getConnection(), request, f.cause())); 33 | } 34 | }); 35 | return futureAdapter; 36 | 37 | } 38 | 39 | public void sendResponseIfNecessary(RequestCommand request, ResponseCommand response) { 40 | if (request.isTwoWay()) { 41 | Connection connection = getConnection(); 42 | connection.writeAndFlush(response).addListener(f -> { 43 | if (f.isSuccess()) { 44 | if (logger.isDebugEnabled()) { 45 | logger.debug("write response " + response.toString() + 46 | "to " + getConnection().getRemoteAddress()); 47 | } 48 | } 49 | if (f.cause() != null) { 50 | logger.error("write response " + response.toString() + "to " + connection.getRemoteAddress() + " error", f.cause()); 51 | } 52 | }); 53 | } 54 | } 55 | 56 | 57 | private String createErrorMsg(Connection connection, RemotingCommand cmd, Throwable t) { 58 | StringBuffer errorMsg = new StringBuffer(); 59 | errorMsg.append("Failed to send message " + cmd.toString() + " to " 60 | + connection.getRemoteAddress() + ", request id " + cmd.getId()); 61 | if (t != null) { 62 | errorMsg.append(", error message is:" + t.getMessage()); 63 | } 64 | return errorMsg.toString(); 65 | } 66 | 67 | abstract ChannelFuture writeAndFlush(Object msg); 68 | } 69 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/reomoting/AbstractLifeCycle.java: -------------------------------------------------------------------------------- 1 | package com.bolt.reomoting; 2 | 3 | import com.bolt.common.exception.LifeCycleException; 4 | 5 | import java.util.concurrent.atomic.AtomicBoolean; 6 | 7 | /** 8 | * @Author: wangxw 9 | * @DateTime: 2020/3/18 10 | * @Description: TODO 11 | */ 12 | public abstract class AbstractLifeCycle implements LifeCycle { 13 | 14 | private final AtomicBoolean isStarted = new AtomicBoolean(false); 15 | 16 | @Override 17 | public void startUp() { 18 | if (isStarted.compareAndSet(false, true)) { 19 | return; 20 | } 21 | throw new LifeCycleException("This component has started"); 22 | 23 | } 24 | 25 | @Override 26 | public void shutDown() { 27 | if (isStarted.compareAndSet(true, false)) { 28 | return; 29 | } 30 | throw new LifeCycleException("This component has shutdown"); 31 | } 32 | 33 | 34 | @Override 35 | public boolean isStarted() { 36 | return isStarted.get(); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/reomoting/Connection.java: -------------------------------------------------------------------------------- 1 | package com.bolt.reomoting; 2 | 3 | 4 | import com.bolt.common.Constants; 5 | import com.bolt.common.Url; 6 | import com.bolt.common.command.RemotingCommand; 7 | import com.bolt.common.command.RequestCommand; 8 | import com.bolt.common.command.ResponseCommand; 9 | import com.bolt.common.exception.RemotingException; 10 | import io.netty.channel.Channel; 11 | import io.netty.channel.ChannelFuture; 12 | import io.netty.util.Attribute; 13 | import io.netty.util.AttributeKey; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | 17 | import java.net.InetSocketAddress; 18 | import java.util.Map; 19 | import java.util.concurrent.ConcurrentHashMap; 20 | import java.util.concurrent.ConcurrentMap; 21 | 22 | /** 23 | * @Author: wangxw 24 | * @DateTime: 2020/4/9 25 | * @Description: TODO 26 | */ 27 | public final class Connection extends AbstractConnectionHandler { 28 | private static final Logger logger = LoggerFactory.getLogger(Connection.class); 29 | public static final AttributeKey HEARTBEAT_COUNT = AttributeKey.valueOf("heartbeatCount"); 30 | public static final ConcurrentMap connectionMap = new ConcurrentHashMap(); 31 | private Channel channel; 32 | private Url url; 33 | 34 | public Connection(Channel channel) { 35 | this(channel, null); 36 | } 37 | 38 | public Connection(Channel channel, Url url) { 39 | this.channel = channel; 40 | this.url = url; 41 | attr(HEARTBEAT_COUNT).set(0); 42 | } 43 | 44 | public Channel getChannel() { 45 | return this.channel; 46 | } 47 | 48 | public Url getUrl() { 49 | return this.url; 50 | } 51 | 52 | public boolean isWritable() { 53 | return this.channel.isWritable(); 54 | } 55 | 56 | @Override 57 | public ChannelFuture writeAndFlush(Object msg) throws RemotingException { 58 | if (channel == null) { 59 | throw new RemotingException(this, "The connection has no valid channel, Connection url" + this.url); 60 | } 61 | 62 | if (!isWritable()) { 63 | logger.error("The connection {} write overflow !!!", this); 64 | throw new RemotingException(this, "The connection {} write overflow !!!" + this); 65 | } 66 | return channel.writeAndFlush(msg); 67 | } 68 | 69 | public boolean isActive(){ 70 | return channel.isActive(); 71 | } 72 | 73 | public void close() { 74 | try { 75 | if (logger.isInfoEnabled()) { 76 | logger.info("Close connection" + channel); 77 | } 78 | try { 79 | channel.close(); 80 | } catch (Exception e) { 81 | logger.warn(e.getMessage(), e); 82 | } 83 | 84 | try { 85 | removeChannelIfDisconnected(channel); 86 | } catch (Exception e) { 87 | logger.warn(e.getMessage(), e); 88 | } 89 | } catch (Exception e) { 90 | logger.warn(e.getMessage(), e); 91 | } 92 | } 93 | 94 | public InetSocketAddress getLocalAddress() { 95 | if (channel == null) { 96 | return null; 97 | } 98 | return (InetSocketAddress) this.channel.localAddress(); 99 | } 100 | 101 | public InetSocketAddress getRemoteAddress() { 102 | if (channel == null) { 103 | return null; 104 | } 105 | 106 | return (InetSocketAddress) this.channel.remoteAddress(); 107 | } 108 | 109 | @Override 110 | public Connection getConnection() { 111 | return this; 112 | } 113 | 114 | public Attribute attr(AttributeKey key) { 115 | return channel.attr(key); 116 | } 117 | 118 | public void resetHeartbeat() { 119 | attr(Connection.HEARTBEAT_COUNT).set(0); 120 | } 121 | 122 | public static Connection getOrAddConnection(Channel ch, Url url) { 123 | if (ch == null) { 124 | return null; 125 | } 126 | Connection ret = connectionMap.get(ch); 127 | if (ret == null) { 128 | Connection connection = new Connection(ch, url); 129 | if (ch.isActive()) { 130 | ret = connectionMap.putIfAbsent(ch, connection); 131 | } 132 | if (ret == null) { 133 | ret = connection; 134 | } 135 | } 136 | return ret; 137 | } 138 | 139 | public static Connection getConnection(Channel ch) { 140 | if (ch == null) { 141 | return null; 142 | } 143 | return connectionMap.get(ch); 144 | } 145 | 146 | public static void removeChannelIfDisconnected(io.netty.channel.Channel ch) { 147 | if (ch != null && !ch.isActive()) { 148 | connectionMap.remove(ch); 149 | } 150 | } 151 | 152 | public static void clear() { 153 | try { 154 | for (Map.Entry entry : connectionMap.entrySet()) { 155 | io.netty.channel.Channel ch = entry.getKey(); 156 | removeChannelIfDisconnected(ch); 157 | } 158 | } catch (Throwable t) { 159 | logger.warn(t.getMessage(), t); 160 | } 161 | } 162 | 163 | @Override 164 | public int hashCode() { 165 | final int prime = 31; 166 | int result = 1; 167 | result = prime * result + ((channel == null) ? 0 : channel.hashCode()); 168 | return result; 169 | } 170 | 171 | @Override 172 | public boolean equals(Object obj) { 173 | if (this == obj) { 174 | return true; 175 | } 176 | if (obj == null) { 177 | return false; 178 | } 179 | if (getClass() != obj.getClass()) { 180 | return false; 181 | } 182 | Connection other = (Connection) obj; 183 | if (channel == null) { 184 | if (other.channel != null) { 185 | return false; 186 | } 187 | } else if (!channel.equals(other.channel)) { 188 | return false; 189 | } 190 | return true; 191 | } 192 | 193 | @Override 194 | public String toString() { 195 | return "[connection=" + channel + "]"; 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/reomoting/ConnectionEventListener.java: -------------------------------------------------------------------------------- 1 | package com.bolt.reomoting; 2 | 3 | import com.bolt.common.enums.ConnectionEventType; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | 9 | /** 10 | * @Author: wangxw 11 | * @DateTime: 2020/5/1 12 | * @Description: TODO 13 | */ 14 | public class ConnectionEventListener { 15 | private ConcurrentHashMap> processors = new ConcurrentHashMap>(); 16 | 17 | public void onEvent(ConnectionEventType type,Connection connection) { 18 | List processorList = this.processors.get(type); 19 | if (processorList != null) { 20 | for (ConnectionEventProcessor processor : processorList) { 21 | processor.onEvent(connection); 22 | } 23 | } 24 | } 25 | 26 | public void addConnectionEventProcessor(ConnectionEventType type, 27 | ConnectionEventProcessor processor) { 28 | List processorList = this.processors.get(type); 29 | if (processorList == null) { 30 | this.processors.putIfAbsent(type, new ArrayList(1)); 31 | processorList = this.processors.get(type); 32 | } 33 | processorList.add(processor); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/reomoting/ConnectionEventProcessor.java: -------------------------------------------------------------------------------- 1 | package com.bolt.reomoting; 2 | 3 | import com.bolt.reomoting.Connection; 4 | 5 | import java.net.InetSocketAddress; 6 | 7 | /** 8 | * @Author: wangxw 9 | * @DateTime: 2020/5/1 10 | * @Description: TODO 11 | */ 12 | @FunctionalInterface 13 | public interface ConnectionEventProcessor { 14 | 15 | void onEvent(Connection connection); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/reomoting/ConnectionHandler.java: -------------------------------------------------------------------------------- 1 | package com.bolt.reomoting; 2 | 3 | import com.bolt.common.command.RequestCommand; 4 | import com.bolt.common.command.ResponseCommand; 5 | import com.bolt.common.exception.RemotingException; 6 | 7 | /** 8 | * @Author: wangxw 9 | * @DateTime: 2020/4/24 10 | * @Description: TODO 11 | */ 12 | public interface ConnectionHandler { 13 | 14 | Connection getConnection(); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/reomoting/FutureAdapter.java: -------------------------------------------------------------------------------- 1 | package com.bolt.reomoting; 2 | 3 | import com.bolt.common.Invocation; 4 | 5 | import java.util.Optional; 6 | import java.util.concurrent.CompletableFuture; 7 | import java.util.concurrent.ExecutionException; 8 | import java.util.concurrent.TimeUnit; 9 | import java.util.concurrent.TimeoutException; 10 | 11 | /** 12 | * @Author: wangxw 13 | * @DateTime: 2020/4/28 14 | * @Description: TODO 15 | */ 16 | public class FutureAdapter extends CompletableFuture { 17 | 18 | private final ResponseFuture future; 19 | public FutureAdapter(ResponseFuture future) { 20 | this.future = future; 21 | future.setCallback(new ResponseCallback() { 22 | @Override 23 | public void done(Invocation invocation) { 24 | Optional.ofNullable(invocation) 25 | .ifPresent(inv -> { 26 | FutureAdapter.this.complete((V)inv.getData()); 27 | }); 28 | } 29 | 30 | @Override 31 | public void caught(Throwable throwable) { 32 | FutureAdapter.this.completeExceptionally(throwable); 33 | } 34 | }); 35 | } 36 | 37 | public ResponseFuture getFuture() { 38 | return future; 39 | } 40 | @Override 41 | public boolean cancel(boolean mayInterruptIfRunning) { 42 | return false; 43 | } 44 | 45 | @Override 46 | public boolean isCancelled() { 47 | return false; 48 | } 49 | 50 | @Override 51 | public boolean isDone() { 52 | return super.isDone(); 53 | } 54 | 55 | @Override 56 | @SuppressWarnings("unchecked") 57 | public V get() throws InterruptedException, ExecutionException { 58 | try { 59 | return super.get(); 60 | } catch (ExecutionException | InterruptedException e) { 61 | throw e; 62 | } catch (Throwable e) { 63 | throw new RuntimeException(e); 64 | } 65 | } 66 | 67 | @Override 68 | @SuppressWarnings("unchecked") 69 | public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { 70 | try { 71 | return super.get(timeout, unit); 72 | } catch (TimeoutException | ExecutionException | InterruptedException e) { 73 | throw e; 74 | } catch (Throwable e) { 75 | throw new RuntimeException(e); 76 | } 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/reomoting/LifeCycle.java: -------------------------------------------------------------------------------- 1 | package com.bolt.reomoting; 2 | 3 | import com.bolt.common.exception.LifeCycleException; 4 | 5 | /** 6 | * @Author: wangxw 7 | * @DateTime: 2020/3/18 8 | * @Description: TODO 9 | */ 10 | public interface LifeCycle { 11 | 12 | void startUp() throws LifeCycleException; 13 | 14 | void shutDown() throws LifeCycleException; 15 | 16 | boolean isStarted(); 17 | } 18 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/reomoting/RemotingContext.java: -------------------------------------------------------------------------------- 1 | package com.bolt.reomoting; 2 | 3 | import io.netty.channel.ChannelFuture; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.EventLoop; 6 | import io.netty.util.concurrent.FastThreadLocal; 7 | 8 | import java.util.concurrent.CompletableFuture; 9 | import java.util.concurrent.ExecutorService; 10 | import java.util.concurrent.Future; 11 | 12 | /** 13 | * @Author: wangxw 14 | * @DateTime: 2020/4/20 15 | * @Description: TODO 16 | */ 17 | public class RemotingContext { 18 | private static final FastThreadLocal LOCAL = new FastThreadLocal() { 19 | @Override 20 | protected RemotingContext initialValue() { 21 | return new RemotingContext(); 22 | } 23 | }; 24 | private Future future; 25 | 26 | private ChannelHandlerContext context; 27 | /** 28 | * 协议级别的线程池 29 | */ 30 | private ExecutorService protocolExecutor; 31 | /** 32 | * IO线程 33 | */ 34 | private EventLoop eventLoop; 35 | 36 | private Connection connection; 37 | 38 | public static RemotingContext getContext(){ 39 | return LOCAL.get(); 40 | } 41 | 42 | public static void removeContext() { 43 | LOCAL.remove(); 44 | } 45 | 46 | protected RemotingContext() { 47 | } 48 | 49 | public RemotingContext(ChannelHandlerContext context, EventLoop eventLoop, ExecutorService protocolExecutor,Connection connection) { 50 | this.context = context; 51 | this.eventLoop = eventLoop; 52 | this.protocolExecutor = protocolExecutor; 53 | this.connection=connection; 54 | } 55 | 56 | 57 | public ChannelFuture writeAndFlush(Object msg) { 58 | return this.context.writeAndFlush(msg); 59 | } 60 | 61 | public ExecutorService protocolExecutor() { 62 | return protocolExecutor; 63 | } 64 | 65 | public EventLoop getEventLoop() { 66 | return eventLoop; 67 | } 68 | 69 | public Connection getConnection() { 70 | return connection; 71 | } 72 | 73 | public CompletableFuturegetCompletableFuture() { 74 | return (CompletableFuture) future; 75 | } 76 | 77 | public void setFuture(Future future) { 78 | this.future = future; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/reomoting/ResponseCallback.java: -------------------------------------------------------------------------------- 1 | package com.bolt.reomoting; 2 | 3 | import com.bolt.common.Invocation; 4 | 5 | /** 6 | * @Author: wangxw 7 | * @DateTime: 2020/4/28 8 | * @Description: TODO 9 | */ 10 | public interface ResponseCallback { 11 | 12 | /** 13 | * done. 14 | * 15 | * @param invocation 16 | */ 17 | void done(Invocation invocation); 18 | 19 | /** 20 | * caught exception. 21 | * 22 | * @param throwable 23 | */ 24 | void caught(Throwable throwable); 25 | } 26 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/reomoting/ResponseFuture.java: -------------------------------------------------------------------------------- 1 | package com.bolt.reomoting; 2 | 3 | import com.bolt.common.exception.RemotingException; 4 | 5 | /** 6 | * @Author: wangxw 7 | * @DateTime: 2020/4/24 8 | * @Description: TODO 9 | */ 10 | public interface ResponseFuture { 11 | 12 | /** 13 | * get result. 14 | * 15 | * @return result. 16 | */ 17 | T get() throws RemotingException; 18 | 19 | /** 20 | * get result with the specified timeout. 21 | * 22 | * @param timeoutInMillis timeout. 23 | * @return result. 24 | */ 25 | T get(int timeoutInMillis) throws RemotingException; 26 | 27 | /** 28 | * set callback. 29 | * 30 | * @param callback 31 | */ 32 | void setCallback(ResponseCallback callback); 33 | 34 | /** 35 | * check is done. 36 | * 37 | * @return done or not. 38 | */ 39 | boolean isDone(); 40 | } 41 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/serialization/ObjectInput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.bolt.serialization; 18 | 19 | import java.io.IOException; 20 | import java.lang.reflect.Type; 21 | 22 | /** 23 | * Object input. 24 | */ 25 | public interface ObjectInput { 26 | /** 27 | * Read boolean. 28 | * 29 | * @return boolean. 30 | * @throws IOException 31 | */ 32 | boolean readBool() throws IOException; 33 | 34 | /** 35 | * Read byte. 36 | * 37 | * @return byte value. 38 | * @throws IOException 39 | */ 40 | byte readByte() throws IOException; 41 | 42 | /** 43 | * Read short integer. 44 | * 45 | * @return short. 46 | * @throws IOException 47 | */ 48 | 49 | short readShort() throws IOException; 50 | 51 | /** 52 | * Read integer. 53 | * 54 | * @return integer. 55 | * @throws IOException 56 | */ 57 | 58 | int readInt() throws IOException; 59 | 60 | /** 61 | * Read long. 62 | * 63 | * @return long. 64 | * @throws IOException 65 | */ 66 | 67 | long readLong() throws IOException; 68 | 69 | /** 70 | * Read float. 71 | * 72 | * @return float. 73 | * @throws IOException 74 | */ 75 | float readFloat() throws IOException; 76 | 77 | /** 78 | * Read double. 79 | * 80 | * @return double. 81 | * @throws IOException 82 | */ 83 | 84 | double readDouble() throws IOException; 85 | 86 | /** 87 | * Read UTF-8 string. 88 | * 89 | * @return string. 90 | * @throws IOException 91 | */ 92 | 93 | String readUTF() throws IOException; 94 | 95 | /** 96 | * Read byte array. 97 | * 98 | * @return byte array. 99 | * @throws IOException 100 | */ 101 | byte[] readBytes() throws IOException; 102 | 103 | /** 104 | * read object. 105 | * 106 | * @return object. 107 | */ 108 | Object readObject() throws IOException, ClassNotFoundException; 109 | 110 | /** 111 | * read object. 112 | * 113 | * @param cls object type. 114 | * @return object. 115 | */ 116 | T readObject(Class cls) throws IOException, ClassNotFoundException; 117 | 118 | /** 119 | * read object. 120 | * 121 | * @param cls object type. 122 | * @return object. 123 | */ 124 | T readObject(Class cls, Type type) throws IOException, ClassNotFoundException; 125 | 126 | } -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/serialization/ObjectOutput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.bolt.serialization; 18 | 19 | import java.io.IOException; 20 | 21 | /** 22 | * Object output. 23 | */ 24 | public interface ObjectOutput { 25 | /** 26 | * Write boolean. 27 | * 28 | * @param v value. 29 | * @throws IOException 30 | */ 31 | void writeBool(boolean v) throws IOException; 32 | 33 | /** 34 | * Write byte. 35 | * 36 | * @param v value. 37 | * @throws IOException 38 | */ 39 | void writeByte(byte v) throws IOException; 40 | 41 | /** 42 | * Write short. 43 | * 44 | * @param v value. 45 | * @throws IOException 46 | */ 47 | void writeShort(short v) throws IOException; 48 | 49 | /** 50 | * Write integer. 51 | * 52 | * @param v value. 53 | * @throws IOException 54 | */ 55 | void writeInt(int v) throws IOException; 56 | 57 | /** 58 | * Write long. 59 | * 60 | * @param v value. 61 | * @throws IOException 62 | */ 63 | void writeLong(long v) throws IOException; 64 | 65 | /** 66 | * Write float. 67 | * 68 | * @param v value. 69 | * @throws IOException 70 | */ 71 | void writeFloat(float v) throws IOException; 72 | 73 | /** 74 | * Write double. 75 | * 76 | * @param v value. 77 | * @throws IOException 78 | */ 79 | void writeDouble(double v) throws IOException; 80 | 81 | /** 82 | * Write string. 83 | * 84 | * @param v value. 85 | * @throws IOException 86 | */ 87 | void writeUTF(String v) throws IOException; 88 | 89 | /** 90 | * Write byte array. 91 | * 92 | * @param v value. 93 | * @throws IOException 94 | */ 95 | void writeBytes(byte[] v) throws IOException; 96 | 97 | /** 98 | * Write byte array. 99 | * 100 | * @param v value. 101 | * @param off offset. 102 | * @param len length. 103 | * @throws IOException 104 | */ 105 | void writeBytes(byte[] v, int off, int len) throws IOException; 106 | 107 | /** 108 | * Flush buffer. 109 | * 110 | * @throws IOException 111 | */ 112 | void flushBuffer() throws IOException; 113 | 114 | /** 115 | * write object. 116 | * 117 | * @param obj object. 118 | */ 119 | void writeObject(Object obj) throws IOException; 120 | 121 | } -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/serialization/Serialization.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.bolt.serialization; 18 | 19 | 20 | import com.bolt.common.extension.Extension; 21 | 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.io.OutputStream; 25 | 26 | /** 27 | * Serialization. (SPI, Singleton, ThreadSafe) 28 | */ 29 | @Extension 30 | public interface Serialization { 31 | 32 | /** 33 | * get content type id 34 | * 35 | * @return content type id 36 | */ 37 | byte getContentTypeId(); 38 | 39 | /** 40 | * get content type 41 | * 42 | * @return content type 43 | */ 44 | String getContentType(); 45 | 46 | /** 47 | * create serializer 48 | * 49 | * @param output 50 | * @return serializer 51 | * @throws IOException 52 | */ 53 | ObjectOutput serialize(OutputStream output) throws IOException; 54 | 55 | /** 56 | * create deserializer 57 | * 58 | * @param input 59 | * @return deserializer 60 | * @throws IOException 61 | */ 62 | ObjectInput deserialize(InputStream input) throws IOException; 63 | 64 | } -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/serialization/SerializationManager.java: -------------------------------------------------------------------------------- 1 | package com.bolt.serialization; 2 | 3 | import com.bolt.common.Constants; 4 | import com.bolt.common.Url; 5 | import com.bolt.common.exception.SerializationException; 6 | import com.bolt.common.extension.ExtensionLoader; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.io.IOException; 11 | import java.util.Optional; 12 | import java.util.Set; 13 | 14 | 15 | /** 16 | * @Author: wangxw 17 | * @DateTime: 2020/3/27 18 | * @Description: TODO 19 | */ 20 | public class SerializationManager { 21 | 22 | private static final Logger logger = LoggerFactory.getLogger(SerializationManager.class); 23 | 24 | private static Serialization[] ID_SERIALIZER_LIST = new Serialization[5]; 25 | 26 | static { 27 | Set extensions = ExtensionLoader.getExtensionLoader(Serialization.class).getSupportedExtensions(); 28 | for (String name : extensions) { 29 | Serialization serialization = ExtensionLoader.getExtensionLoader(Serialization.class).getExtension(name); 30 | byte contentTypeId = serialization.getContentTypeId(); 31 | if (ID_SERIALIZER_LIST[contentTypeId] != null) { 32 | logger.error("Serialization extension " + serialization.getClass().getName() 33 | + " has duplicate id to Serialization extension " 34 | + ID_SERIALIZER_LIST[contentTypeId].getClass().getName() 35 | + ", ignore this Serializer extension"); 36 | continue; 37 | } 38 | 39 | addSerialiation(contentTypeId, serialization); 40 | } 41 | 42 | } 43 | 44 | private SerializationManager() { 45 | 46 | } 47 | 48 | public static Serialization getSerialization(Url url) { 49 | return ExtensionLoader.getExtensionLoader(Serialization.class) 50 | .getExtension(url.getParameter(Constants.SERIALIZATION_KEY, 51 | Constants.DEFAULT_REMOTING_SERIALIZATION)); 52 | } 53 | 54 | public static Serialization getSerializationById(Byte id) throws IOException { 55 | final String error = "Unexpected serializer id:" + id + " received from network, please check if the peer send the right id."; 56 | return Optional.ofNullable(ID_SERIALIZER_LIST[id]) 57 | .orElseThrow(() -> new SerializationException(error)); 58 | } 59 | 60 | private static void addSerialiation(int idx, Serialization serialization) { 61 | if (ID_SERIALIZER_LIST.length <= idx) { 62 | Serialization[] newSerializers = new Serialization[idx + 5]; 63 | System.arraycopy(ID_SERIALIZER_LIST, 0, newSerializers, 0, ID_SERIALIZER_LIST.length); 64 | ID_SERIALIZER_LIST = newSerializers; 65 | } 66 | ID_SERIALIZER_LIST[idx] = serialization; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/serialization/hessian2/Hessian2ObjectInput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.bolt.serialization.hessian2; 18 | 19 | import com.alibaba.com.caucho.hessian.io.Hessian2Input; 20 | import com.bolt.serialization.ObjectInput; 21 | 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.lang.reflect.Type; 25 | 26 | /** 27 | * Hessian2 Object input. 28 | */ 29 | public class Hessian2ObjectInput implements ObjectInput { 30 | private final Hessian2Input mH2i; 31 | 32 | public Hessian2ObjectInput(InputStream is) { 33 | mH2i = new Hessian2Input(is); 34 | mH2i.setSerializerFactory(Hessian2SerializerFactory.SERIALIZER_FACTORY); 35 | } 36 | 37 | @Override 38 | public boolean readBool() throws IOException { 39 | return mH2i.readBoolean(); 40 | } 41 | 42 | @Override 43 | public byte readByte() throws IOException { 44 | return (byte) mH2i.readInt(); 45 | } 46 | 47 | @Override 48 | public short readShort() throws IOException { 49 | return (short) mH2i.readInt(); 50 | } 51 | 52 | @Override 53 | public int readInt() throws IOException { 54 | return mH2i.readInt(); 55 | } 56 | 57 | @Override 58 | public long readLong() throws IOException { 59 | return mH2i.readLong(); 60 | } 61 | 62 | @Override 63 | public float readFloat() throws IOException { 64 | return (float) mH2i.readDouble(); 65 | } 66 | 67 | @Override 68 | public double readDouble() throws IOException { 69 | return mH2i.readDouble(); 70 | } 71 | 72 | @Override 73 | public byte[] readBytes() throws IOException { 74 | return mH2i.readBytes(); 75 | } 76 | 77 | @Override 78 | public String readUTF() throws IOException { 79 | return mH2i.readString(); 80 | } 81 | 82 | @Override 83 | public Object readObject() throws IOException { 84 | return mH2i.readObject(); 85 | } 86 | 87 | @Override 88 | @SuppressWarnings("unchecked") 89 | public T readObject(Class cls) throws IOException, 90 | ClassNotFoundException { 91 | return (T) mH2i.readObject(cls); 92 | } 93 | 94 | @Override 95 | public T readObject(Class cls, Type type) throws IOException, ClassNotFoundException { 96 | return readObject(cls); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/serialization/hessian2/Hessian2ObjectOutput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.bolt.serialization.hessian2; 18 | 19 | import com.alibaba.com.caucho.hessian.io.Hessian2Output; 20 | import com.bolt.serialization.ObjectOutput; 21 | 22 | import java.io.IOException; 23 | import java.io.OutputStream; 24 | 25 | /** 26 | * Hessian2 Object output. 27 | */ 28 | public class Hessian2ObjectOutput implements ObjectOutput { 29 | private final Hessian2Output mH2o; 30 | 31 | public Hessian2ObjectOutput(OutputStream os) { 32 | mH2o = new Hessian2Output(os); 33 | mH2o.setSerializerFactory(Hessian2SerializerFactory.SERIALIZER_FACTORY); 34 | } 35 | 36 | @Override 37 | public void writeBool(boolean v) throws IOException { 38 | mH2o.writeBoolean(v); 39 | } 40 | 41 | @Override 42 | public void writeByte(byte v) throws IOException { 43 | mH2o.writeInt(v); 44 | } 45 | 46 | @Override 47 | public void writeShort(short v) throws IOException { 48 | mH2o.writeInt(v); 49 | } 50 | 51 | @Override 52 | public void writeInt(int v) throws IOException { 53 | mH2o.writeInt(v); 54 | } 55 | 56 | @Override 57 | public void writeLong(long v) throws IOException { 58 | mH2o.writeLong(v); 59 | } 60 | 61 | @Override 62 | public void writeFloat(float v) throws IOException { 63 | mH2o.writeDouble(v); 64 | } 65 | 66 | @Override 67 | public void writeDouble(double v) throws IOException { 68 | mH2o.writeDouble(v); 69 | } 70 | 71 | @Override 72 | public void writeBytes(byte[] b) throws IOException { 73 | mH2o.writeBytes(b); 74 | } 75 | 76 | @Override 77 | public void writeBytes(byte[] b, int off, int len) throws IOException { 78 | mH2o.writeBytes(b, off, len); 79 | } 80 | 81 | @Override 82 | public void writeUTF(String v) throws IOException { 83 | mH2o.writeString(v); 84 | } 85 | 86 | @Override 87 | public void writeObject(Object obj) throws IOException { 88 | mH2o.writeObject(obj); 89 | } 90 | 91 | @Override 92 | public void flushBuffer() throws IOException { 93 | mH2o.flushBuffer(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/serialization/hessian2/Hessian2Serialization.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.bolt.serialization.hessian2; 18 | 19 | 20 | import com.bolt.serialization.ObjectInput; 21 | import com.bolt.serialization.ObjectOutput; 22 | import com.bolt.serialization.Serialization; 23 | 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | import java.io.OutputStream; 27 | 28 | public class Hessian2Serialization implements Serialization { 29 | 30 | public static final byte ID = 2; 31 | 32 | @Override 33 | public byte getContentTypeId() { 34 | return ID; 35 | } 36 | 37 | @Override 38 | public String getContentType() { 39 | return "x-application/hessian2"; 40 | } 41 | 42 | @Override 43 | public ObjectOutput serialize(OutputStream out) throws IOException { 44 | return new Hessian2ObjectOutput(out); 45 | } 46 | 47 | @Override 48 | public ObjectInput deserialize(InputStream is) throws IOException { 49 | return new Hessian2ObjectInput(is); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/serialization/hessian2/Hessian2SerializerFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.bolt.serialization.hessian2; 18 | 19 | import com.alibaba.com.caucho.hessian.io.SerializerFactory; 20 | 21 | public class Hessian2SerializerFactory extends SerializerFactory { 22 | 23 | public static final SerializerFactory SERIALIZER_FACTORY = new Hessian2SerializerFactory(); 24 | 25 | private Hessian2SerializerFactory() { 26 | } 27 | 28 | @Override 29 | public ClassLoader getClassLoader() { 30 | return Thread.currentThread().getContextClassLoader(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/transport/AbstractEndpoint.java: -------------------------------------------------------------------------------- 1 | package com.bolt.transport; 2 | 3 | import com.bolt.codec.Codec; 4 | import com.bolt.common.enums.ConnectionEventType; 5 | import com.bolt.config.*; 6 | import com.bolt.reomoting.AbstractLifeCycle; 7 | import com.bolt.common.Url; 8 | import com.bolt.protocol.Protocol; 9 | import com.bolt.reomoting.ConnectionEventListener; 10 | import com.bolt.reomoting.ConnectionEventProcessor; 11 | import io.netty.channel.WriteBufferWaterMark; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | import java.util.Map; 16 | 17 | /** 18 | * @Author: wangxw 19 | * @DateTime: 2020/4/9 20 | * @Description: TODO 21 | */ 22 | public abstract class AbstractEndpoint extends AbstractLifeCycle implements Endpoint, Configurable { 23 | private static final Logger logger = LoggerFactory.getLogger(AbstractEndpoint.class); 24 | protected final BoltOptions options = new BoltOptions(); 25 | private Codec codec; 26 | private Protocol protocol; 27 | private volatile Url url; 28 | private boolean serverSide; 29 | private ConnectionEventListener connectionEventListener = new ConnectionEventListener(); 30 | 31 | protected abstract void doOpen() throws Throwable; 32 | 33 | protected abstract void doClose() throws Throwable; 34 | 35 | public AbstractEndpoint(Codec codec, Protocol protocol) { 36 | this(false, codec, protocol); 37 | } 38 | 39 | public AbstractEndpoint(boolean serverSide, Codec codec, Protocol protocol) { 40 | this.serverSide = serverSide; 41 | this.codec = codec; 42 | this.protocol = protocol; 43 | } 44 | 45 | @Override 46 | public Configurable option(BoltOption option, T value) { 47 | options.option(option, value); 48 | return this; 49 | } 50 | 51 | @Override 52 | public T option(BoltOption option) { 53 | return options.option(option); 54 | } 55 | 56 | protected Map options(Class type) { 57 | return options.options(type); 58 | } 59 | 60 | protected Codec getCodec() { 61 | return codec; 62 | } 63 | 64 | public Protocol getProtocol() { 65 | return protocol; 66 | } 67 | 68 | protected void init(Url url) { 69 | url.addParameters(options(BoltRemotingOption.class)); 70 | if (isServerSide()) { 71 | url.addParameters(options(BoltServerOption.class)); 72 | } else { 73 | if (url.getHost() == null) { 74 | url.setHost(option(BoltClientOption.HOST)); 75 | url.setPort(option(BoltClientOption.PORT)); 76 | } 77 | url.addParameters(options(BoltClientOption.class)); 78 | } 79 | this.url = url; 80 | } 81 | 82 | @Override 83 | public Url getUrl() { 84 | return url; 85 | } 86 | 87 | public WriteBufferWaterMark initWriteBufferWaterMark() { 88 | Integer lowWaterMark = this.option(BoltGenericOption.NETTY_BUFFER_LOW_WATER_MARK); 89 | Integer highWaterMark = this.option(BoltGenericOption.NETTY_BUFFER_HIGH_WATER_MARK); 90 | String prefix = isServerSide() ? "[bolt server side]" : "[bolt client side]"; 91 | if (lowWaterMark > highWaterMark) { 92 | throw new IllegalArgumentException( 93 | String.format(prefix + " netty high water mark {%s}" + 94 | " should not be smaller than low water mark {%s} bytes)", 95 | highWaterMark, lowWaterMark)); 96 | } else { 97 | logger.info(prefix + " netty low water mark is {} bytes, high water mark is {} bytes", 98 | lowWaterMark, highWaterMark); 99 | } 100 | return new WriteBufferWaterMark(lowWaterMark, highWaterMark); 101 | } 102 | 103 | @Override 104 | public boolean isServerSide() { 105 | return serverSide; 106 | } 107 | 108 | public void addConnectionEventProcessor(ConnectionEventType type, ConnectionEventProcessor processor) { 109 | connectionEventListener.addConnectionEventProcessor(type, processor); 110 | } 111 | 112 | protected ConnectionEventListener getConnectionEventListener() { 113 | return connectionEventListener; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/transport/AbstractServer.java: -------------------------------------------------------------------------------- 1 | package com.bolt.transport; 2 | 3 | import com.bolt.codec.Codec; 4 | import com.bolt.common.exception.RemotingException; 5 | import com.bolt.protocol.Protocol; 6 | import com.bolt.util.ExecutorUtil; 7 | import com.bolt.util.NetUtils; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.net.InetSocketAddress; 12 | 13 | /** 14 | * @Author: wangxw 15 | * @DateTime: 2020/4/21 16 | * @Description: TODO 17 | */ 18 | public abstract class AbstractServer extends AbstractEndpoint implements Server { 19 | private static final Logger logger = LoggerFactory.getLogger(AbstractServer.class); 20 | 21 | protected int port; 22 | 23 | public AbstractServer(Codec codec, Protocol protocol) { 24 | super(true, codec, protocol); 25 | } 26 | 27 | 28 | @Override 29 | public InetSocketAddress getLocalAddress() { 30 | return new InetSocketAddress(NetUtils.getLocalHost(), port); 31 | } 32 | 33 | @Override 34 | public void startUp() { 35 | super.startUp(); 36 | long start = System.currentTimeMillis(); 37 | try { 38 | doOpen(); 39 | if (logger.isInfoEnabled()) { 40 | logger.info("Start " + getClass().getSimpleName() + " bind port [{}], start time {}ms", 41 | port, System.currentTimeMillis() - start); 42 | } 43 | } catch (Throwable t) { 44 | shutDown(); 45 | throw new RemotingException(getLocalAddress(), null, "Failed to bind " + getClass().getSimpleName() 46 | + " on " + getLocalAddress() + ", cause: " + t.getMessage(), t); 47 | } 48 | 49 | } 50 | 51 | @Override 52 | public void shutDown() { 53 | super.shutDown(); 54 | 55 | try { 56 | close(); 57 | } catch (Throwable t) { 58 | logger.warn(t.getMessage(), t); 59 | } 60 | } 61 | 62 | @Override 63 | public void close() { 64 | if (logger.isInfoEnabled()) { 65 | logger.info("Close " + getClass().getSimpleName() + " bind " + getLocalAddress()); 66 | } 67 | ExecutorUtil.gracefulShutdown(getProtocol().getDefaultExecutor(), 100); 68 | 69 | try { 70 | doClose(); 71 | } catch (Throwable t) { 72 | logger.warn(t.getMessage(), t); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/transport/BoltServer.java: -------------------------------------------------------------------------------- 1 | package com.bolt.transport; 2 | 3 | import com.bolt.codec.BoltCodec; 4 | import com.bolt.codec.CodecAdapter; 5 | import com.bolt.common.Url; 6 | import com.bolt.config.BoltGenericOption; 7 | import com.bolt.config.BoltRemotingOption; 8 | import com.bolt.config.BoltServerOption; 9 | import com.bolt.reomoting.Connection; 10 | import com.bolt.protocol.BoltProtocol; 11 | import com.bolt.util.NetUtils; 12 | import com.bolt.util.UrlUtils; 13 | import io.netty.bootstrap.ServerBootstrap; 14 | import io.netty.buffer.PooledByteBufAllocator; 15 | import io.netty.channel.*; 16 | import io.netty.channel.nio.NioEventLoopGroup; 17 | import io.netty.channel.socket.nio.NioServerSocketChannel; 18 | import io.netty.channel.socket.nio.NioSocketChannel; 19 | import io.netty.handler.timeout.IdleStateHandler; 20 | import io.netty.util.concurrent.DefaultThreadFactory; 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | import java.net.URL; 25 | import java.util.Map; 26 | 27 | import static java.util.concurrent.TimeUnit.MILLISECONDS; 28 | 29 | 30 | /** 31 | * @Author: wangxw 32 | * @DateTime: 2020/4/17 33 | * @Description: TODO 34 | */ 35 | public class BoltServer extends AbstractServer { 36 | private static final Logger logger = LoggerFactory.getLogger(BoltServer.class); 37 | private ServerBootstrap bootstrap; 38 | private EventLoopGroup bossGroup; 39 | private EventLoopGroup workerGroup; 40 | private volatile Channel channel; 41 | 42 | public BoltServer() { 43 | super(new BoltCodec(), new BoltProtocol()); 44 | } 45 | 46 | 47 | @Override 48 | public void doOpen() throws Throwable { 49 | bootstrap = new ServerBootstrap(); 50 | bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory("BoltServerBoss", false)); 51 | workerGroup = new NioEventLoopGroup(this.option(BoltGenericOption.IO_THREADS), new DefaultThreadFactory("BoltServerWorker", true)); 52 | port = this.option(BoltServerOption.PORT); 53 | init(new Url(NetUtils.getLocalHost(), port)); 54 | final BoltHandler serverHandler = new BoltHandler(getUrl(), getProtocol(), isServerSide()); 55 | int idleTimeout = UrlUtils.getIdleTimeout(getUrl()); 56 | serverHandler.setConnectionEventListener(getConnectionEventListener()); 57 | 58 | 59 | bootstrap.group(bossGroup, workerGroup) 60 | .channel(NioServerSocketChannel.class) 61 | .childOption(ChannelOption.TCP_NODELAY, this.option(BoltGenericOption.TCP_NODELAY)) 62 | .childOption(ChannelOption.SO_REUSEADDR, this.option(BoltGenericOption.TCP_SO_REUSEADDR)) 63 | .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) 64 | .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, initWriteBufferWaterMark()) 65 | .childHandler(new ChannelInitializer() { 66 | @Override 67 | protected void initChannel(NioSocketChannel ch) throws Exception { 68 | CodecAdapter adapter = new CodecAdapter(getCodec(), getUrl()); 69 | ch.pipeline() 70 | .addLast("decoder", adapter.getDecoder()) 71 | .addLast("encoder", adapter.getEncoder()) 72 | .addLast("server-idle-handler", new IdleStateHandler(0, 0, idleTimeout, MILLISECONDS)) 73 | .addLast(serverHandler); 74 | } 75 | }); 76 | ChannelFuture future = bootstrap.bind(this.port).syncUninterruptibly(); 77 | channel = future.channel(); 78 | } 79 | 80 | @Override 81 | protected void doClose() throws Throwable { 82 | try { 83 | if (channel != null) { 84 | // unbind. 85 | channel.close(); 86 | } 87 | } catch (Throwable e) { 88 | logger.warn(e.getMessage(), e); 89 | } 90 | 91 | try { 92 | if (bootstrap != null) { 93 | bossGroup.shutdownGracefully(); 94 | workerGroup.shutdownGracefully(); 95 | } 96 | } catch (Throwable e) { 97 | logger.warn(e.getMessage(), e); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/transport/Client.java: -------------------------------------------------------------------------------- 1 | package com.bolt.transport; 2 | 3 | import com.bolt.common.Url; 4 | import com.bolt.common.exception.RemotingException; 5 | import com.bolt.reomoting.Connection; 6 | 7 | import java.util.concurrent.CompletableFuture; 8 | 9 | /** 10 | * @Author: wangxw 11 | * @DateTime: 2020/4/22 12 | * @Description: TODO 13 | */ 14 | public interface Client extends Endpoint { 15 | 16 | Connection ctreateConnectionIfAbsent(Url url) throws RemotingException; 17 | 18 | T request(Url url, Object request) throws RemotingException; 19 | 20 | T request(Object request) throws RemotingException; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/transport/Endpoint.java: -------------------------------------------------------------------------------- 1 | package com.bolt.transport; 2 | 3 | import com.bolt.common.Url; 4 | import io.netty.channel.WriteBufferWaterMark; 5 | 6 | import java.net.InetSocketAddress; 7 | 8 | /** 9 | * @Author: wangxw 10 | * @DateTime: 2020/4/21 11 | * @Description: TODO 12 | */ 13 | public interface Endpoint { 14 | 15 | void close(); 16 | 17 | Url getUrl(); 18 | 19 | InetSocketAddress getLocalAddress(); 20 | 21 | boolean isServerSide(); 22 | } 23 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/transport/ReconnectClient.java: -------------------------------------------------------------------------------- 1 | package com.bolt.transport; 2 | 3 | 4 | import com.bolt.common.Url; 5 | import com.bolt.reomoting.AbstractLifeCycle; 6 | import com.bolt.util.NamedThreadFactory; 7 | import com.bolt.util.ObjectUtils; 8 | import io.netty.util.HashedWheelTimer; 9 | import io.netty.util.Timeout; 10 | import io.netty.util.TimerTask; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import java.util.concurrent.*; 15 | import java.util.concurrent.atomic.AtomicInteger; 16 | 17 | /** 18 | * @Author: wangxw 19 | * @DateTime: 2020/5/5 20 | * @Description: TODO 21 | */ 22 | public class ReconnectClient extends AbstractLifeCycle { 23 | private static final Logger logger = LoggerFactory.getLogger(ReconnectClient.class); 24 | private static final HashedWheelTimer IDLE_CHECK_TIMER = new HashedWheelTimer( 25 | new NamedThreadFactory("bolt-client-reconnect-timer", true), 1, TimeUnit.SECONDS); 26 | private LinkedBlockingQueue tasks = new LinkedBlockingQueue(); 27 | private Client client; 28 | private Thread reconnectThread; 29 | 30 | public ReconnectClient(Client client) { 31 | this.client = client; 32 | } 33 | 34 | @Override 35 | public void startUp() { 36 | super.startUp(); 37 | this.reconnectThread = new Thread(() -> { 38 | while (isStarted()) { 39 | ReconnectTimerTask task = null; 40 | try { 41 | task = tasks.take(); 42 | } catch (InterruptedException e) { 43 | } 44 | IDLE_CHECK_TIMER.newTimeout(task, task.getReconnectCount() * 3, TimeUnit.SECONDS); 45 | } 46 | }, "bolt-client-reconnect-thread"); 47 | reconnectThread.setDaemon(true); 48 | reconnectThread.start(); 49 | } 50 | 51 | @Override 52 | public void shutDown() { 53 | super.shutDown(); 54 | tasks.clear(); 55 | IDLE_CHECK_TIMER.stop(); 56 | } 57 | 58 | public void reconnect(Url url) { 59 | try { 60 | tasks.put(new ReconnectTimerTask(url)); 61 | } catch (InterruptedException e) { 62 | logger.warn(e.getMessage(), e); 63 | } 64 | } 65 | 66 | 67 | private class ReconnectTimerTask implements TimerTask { 68 | private final Url url; 69 | private AtomicInteger reconnectCount = new AtomicInteger(0); 70 | 71 | private ReconnectTimerTask(Url url) { 72 | this.url = url; 73 | } 74 | 75 | public ReconnectTimerTask addReconnectCount() { 76 | reconnectCount.getAndIncrement(); 77 | return this; 78 | } 79 | 80 | protected int getReconnectCount() { 81 | return reconnectCount.get(); 82 | } 83 | 84 | @Override 85 | public String toString() { 86 | return "ReconnectTask{" + 87 | "url=" + url + 88 | ", reconnectCount=" + reconnectCount + 89 | '}'; 90 | } 91 | 92 | @Override 93 | public void run(Timeout timeout) throws Exception { 94 | try { 95 | if (logger.isInfoEnabled()) { 96 | logger.info("Reconnect to server count " + getReconnectCount() + ", client(url: " + url + ")"); 97 | } 98 | client.ctreateConnectionIfAbsent(url); 99 | } catch (Exception e) { 100 | logger.warn(ObjectUtils.toString(e)); 101 | tasks.put(addReconnectCount()); 102 | } 103 | } 104 | } 105 | 106 | 107 | } 108 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/transport/Server.java: -------------------------------------------------------------------------------- 1 | package com.bolt.transport; 2 | 3 | /** 4 | * @Author: wangxw 5 | * @DateTime: 2020/4/21 6 | * @Description: TODO 7 | */ 8 | public interface Server extends Endpoint { 9 | } 10 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/util/CountDownLatchUtil.java: -------------------------------------------------------------------------------- 1 | package com.bolt.util; 2 | 3 | import java.util.concurrent.CountDownLatch; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.Executors; 6 | 7 | public class CountDownLatchUtil { 8 | private CountDownLatch start; 9 | private CountDownLatch end; 10 | private int poolSize; 11 | 12 | public CountDownLatchUtil() { 13 | this(10); 14 | } 15 | 16 | public CountDownLatchUtil(int poolSize) { 17 | this.poolSize = poolSize; 18 | start = new CountDownLatch(1); 19 | end = new CountDownLatch(poolSize); 20 | } 21 | 22 | public void latch(MyFunctionalInterface functionalInterface) throws InterruptedException { 23 | ExecutorService service = Executors.newFixedThreadPool(poolSize); 24 | for (int i = 0; i < poolSize; i++) { 25 | Runnable runnable = new Runnable() { 26 | 27 | @Override 28 | public void run() { 29 | try { 30 | start.await(); 31 | functionalInterface.run(); 32 | } catch (InterruptedException e) { 33 | e.printStackTrace(); 34 | } finally { 35 | end.countDown(); 36 | } 37 | } 38 | }; 39 | service.execute(runnable); 40 | } 41 | 42 | start.countDown(); 43 | end.await(); 44 | } 45 | 46 | @FunctionalInterface 47 | public interface MyFunctionalInterface { 48 | void run(); 49 | } 50 | } -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/util/ExecutorUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.bolt.util; 18 | 19 | 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | 23 | import java.util.concurrent.*; 24 | 25 | public class ExecutorUtil { 26 | private static final Logger logger = LoggerFactory.getLogger(ExecutorUtil.class); 27 | private static final ThreadPoolExecutor shutdownExecutor = new ThreadPoolExecutor(0, 1, 28 | 0L, TimeUnit.MILLISECONDS, 29 | new LinkedBlockingQueue(100), 30 | new NamedThreadFactory("Close-ExecutorService-Timer", true)); 31 | 32 | public static boolean isTerminated(Executor executor) { 33 | if (executor instanceof ExecutorService) { 34 | if (((ExecutorService) executor).isTerminated()) { 35 | return true; 36 | } 37 | } 38 | return false; 39 | } 40 | 41 | /** 42 | * Use the shutdown pattern from: 43 | * https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html 44 | * @param executor the Executor to shutdown 45 | * @param timeout the timeout in milliseconds before termination 46 | */ 47 | public static void gracefulShutdown(Executor executor, int timeout) { 48 | if (!(executor instanceof ExecutorService) || isTerminated(executor)) { 49 | return; 50 | } 51 | final ExecutorService es = (ExecutorService) executor; 52 | try { 53 | // Disable new tasks from being submitted 54 | es.shutdown(); 55 | } catch (SecurityException ex2) { 56 | return; 57 | } catch (NullPointerException ex2) { 58 | return; 59 | } 60 | try { 61 | // Wait a while for existing tasks to terminate 62 | if (!es.awaitTermination(timeout, TimeUnit.MILLISECONDS)) { 63 | es.shutdownNow(); 64 | } 65 | } catch (InterruptedException ex) { 66 | es.shutdownNow(); 67 | Thread.currentThread().interrupt(); 68 | } 69 | if (!isTerminated(es)) { 70 | newThreadToCloseExecutor(es); 71 | } 72 | } 73 | 74 | public static void shutdownNow(Executor executor, final int timeout) { 75 | // 1.判断线程池所有线程是否已经被终止 76 | if (!(executor instanceof ExecutorService) || isTerminated(executor)) { 77 | return; 78 | } 79 | final ExecutorService es = (ExecutorService) executor; 80 | try { 81 | // 立即终止 82 | es.shutdownNow(); 83 | } catch (SecurityException ex2) { 84 | return; 85 | } catch (NullPointerException ex2) { 86 | return; 87 | } 88 | try { 89 | es.awaitTermination(timeout, TimeUnit.MILLISECONDS); 90 | } catch (InterruptedException ex) { 91 | Thread.currentThread().interrupt(); 92 | } 93 | if (!isTerminated(es)) { 94 | newThreadToCloseExecutor(es); 95 | } 96 | } 97 | 98 | private static void newThreadToCloseExecutor(final ExecutorService es) { 99 | if (!isTerminated(es)) { 100 | shutdownExecutor.execute(new Runnable() { 101 | @Override 102 | public void run() { 103 | try { 104 | for (int i = 0; i < 1000; i++) { 105 | es.shutdownNow(); 106 | if (es.awaitTermination(10, TimeUnit.MILLISECONDS)) { 107 | break; 108 | } 109 | } 110 | } catch (InterruptedException ex) { 111 | Thread.currentThread().interrupt(); 112 | } catch (Throwable e) { 113 | logger.warn(e.getMessage(), e); 114 | } 115 | } 116 | }); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/util/NamedThreadFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.bolt.util; 18 | 19 | import java.util.concurrent.ThreadFactory; 20 | import java.util.concurrent.atomic.AtomicInteger; 21 | 22 | /** 23 | * InternalThreadFactory. 24 | */ 25 | public class NamedThreadFactory implements ThreadFactory { 26 | 27 | protected static final AtomicInteger POOL_SEQ = new AtomicInteger(1); 28 | 29 | protected final AtomicInteger mThreadNum = new AtomicInteger(1); 30 | 31 | protected final String mPrefix; 32 | 33 | protected final boolean mDaemon; 34 | 35 | protected final ThreadGroup mGroup; 36 | 37 | public NamedThreadFactory() { 38 | this("pool-" + POOL_SEQ.getAndIncrement(), false); 39 | } 40 | 41 | public NamedThreadFactory(String prefix) { 42 | this(prefix, false); 43 | } 44 | 45 | public NamedThreadFactory(String prefix, boolean daemon) { 46 | mPrefix = prefix + "-thread-"; 47 | mDaemon = daemon; 48 | SecurityManager s = System.getSecurityManager(); 49 | mGroup = (s == null) ? Thread.currentThread().getThreadGroup() : s.getThreadGroup(); 50 | } 51 | 52 | @Override 53 | public Thread newThread(Runnable runnable) { 54 | String name = mPrefix + mThreadNum.getAndIncrement(); 55 | Thread ret = new Thread(mGroup, runnable, name, 0); 56 | ret.setDaemon(mDaemon); 57 | return ret; 58 | } 59 | 60 | public ThreadGroup getThreadGroup() { 61 | return mGroup; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/util/ObjectUtils.java: -------------------------------------------------------------------------------- 1 | package com.bolt.util; 2 | 3 | import org.springframework.lang.Nullable; 4 | 5 | import java.io.PrintWriter; 6 | import java.io.StringWriter; 7 | 8 | /** 9 | * @Author: wangxw 10 | * @DateTime: 2020/4/20 11 | * @Description: TODO 12 | */ 13 | public class ObjectUtils { 14 | 15 | public static void isNotNull(@Nullable Object object, String message) { 16 | if (object == null) { 17 | throw new IllegalArgumentException(message); 18 | } 19 | } 20 | 21 | public static String toString(Throwable e) { 22 | StringWriter w = new StringWriter(); 23 | PrintWriter p = new PrintWriter(w); 24 | p.print(e.getClass().getName()); 25 | if (e.getMessage() != null) { 26 | p.print(": " + e.getMessage()); 27 | } 28 | p.println(); 29 | try { 30 | e.printStackTrace(p); 31 | return w.toString(); 32 | } finally { 33 | p.close(); 34 | } 35 | } 36 | 37 | public static String toString(String msg, Throwable e) { 38 | StringWriter w = new StringWriter(); 39 | w.write(msg + "\n"); 40 | PrintWriter p = new PrintWriter(w); 41 | try { 42 | e.printStackTrace(p); 43 | return w.toString(); 44 | } finally { 45 | p.close(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /bolt-extension/src/main/java/com/bolt/util/UrlUtils.java: -------------------------------------------------------------------------------- 1 | package com.bolt.util; 2 | 3 | import com.bolt.common.Constants; 4 | import com.bolt.common.Url; 5 | import org.apache.commons.lang3.StringUtils; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * @Author: wangxw 12 | * @DateTime: 2020/4/7 13 | * @Description: TODO 14 | */ 15 | public class UrlUtils { 16 | 17 | private final static String URL_COLON_SYMBOL = ":"; 18 | private final static String URL_PARAM_STARTING_SYMBOL = "?"; 19 | 20 | public static Url parseUrl(String address, Map parameterMap) { 21 | if (StringUtils.isBlank(address)) { 22 | throw new IllegalArgumentException("Illegal format address [" + address + "], it should not be blank! "); 23 | } 24 | String host = null; 25 | int port = 0; 26 | String[] urls = StringUtils.split(address, URL_COLON_SYMBOL); 27 | if (urls.length != 2) { 28 | throw new IllegalArgumentException("Illegal format address [" + address + "], Illegal colon position "); 29 | 30 | } 31 | host = urls[0]; 32 | if (urls[1].endsWith(URL_PARAM_STARTING_SYMBOL)) { 33 | throw new IllegalArgumentException("Illegal format address [" + address + "], should be not end with [?] "); 34 | } 35 | urls = StringUtils.split(urls[1], URL_PARAM_STARTING_SYMBOL); 36 | if (urls.length > 2) { 37 | throw new IllegalArgumentException("Illegal format address [" + address + "], must have one [?]! "); 38 | } 39 | 40 | port = Integer.valueOf(urls[0]); 41 | Map parameters = new HashMap<>(); 42 | ; 43 | if (urls.length == 2) { 44 | String params = urls[1]; 45 | String[] parts = StringUtils.split(params, "&"); 46 | for (String part : parts) { 47 | int i = part.indexOf("="); 48 | if (i >= 0) { 49 | parameters.put(part.substring(0, i), part.substring(i + 1)); 50 | 51 | } 52 | } 53 | } 54 | parameters.putAll(parameterMap); 55 | return new Url(host, port, parameters); 56 | } 57 | 58 | public static Url valueOf(Url url, Map parameters) { 59 | url.addParameters(parameters); 60 | return url; 61 | } 62 | 63 | public static boolean isAsync(Url url){ 64 | return url.getParameter(Constants.ASYNC_KEY, false); 65 | } 66 | 67 | public static boolean isOneway(Url url){ 68 | return url.getParameter(Constants.RETURN_KEY, false); 69 | } 70 | 71 | public static int getHeartbeat(Url url) { 72 | return url.getParameter(Constants.HEARTBEAT_KEY, Constants.DEFAULT_HEARTBEAT); 73 | } 74 | 75 | public static int getIdleTimeout(Url url) { 76 | int heartBeat = getHeartbeat(url); 77 | // idleTimeout should be at least more than six heartBeat because possible retries of client. 78 | int idleTimeout = url.getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, heartBeat * 6); 79 | if (idleTimeout < heartBeat * 6) { 80 | throw new IllegalStateException("idleTimeout < heartbeatInterval * 6"); 81 | } 82 | return idleTimeout; 83 | } 84 | 85 | public static int getTimeout(Url url,Integer timeout) { 86 | return url.getParameter(Constants.TIMEOUT_KEY, timeout); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /bolt-extension/src/main/resources/META-INF/services/com.bolt.protocol.handler.CommandHandler: -------------------------------------------------------------------------------- 1 | generalReq=com.bolt.protocol.handler.GeneralCmdHandler 2 | heartbeat=com.bolt.protocol.handler.HeartbeatHandler -------------------------------------------------------------------------------- /bolt-extension/src/main/resources/META-INF/services/com.bolt.protocol.processor.UserProcessor: -------------------------------------------------------------------------------- 1 | simpleReq=com.bolt.protocol.processor.SimpleReqProcesser -------------------------------------------------------------------------------- /bolt-extension/src/main/resources/META-INF/services/com.bolt.serialization.Serialization: -------------------------------------------------------------------------------- 1 | hessian2=com.bolt.serialization.hessian2.Hessian2Serialization -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/async/ComputeCallable.java: -------------------------------------------------------------------------------- 1 | package com.bolt.async; 2 | 3 | import java.util.concurrent.Callable; 4 | 5 | /** 6 | * @Author: wangxw 7 | * @DateTime: 2020/4/8 8 | * @Description: TODO 9 | */ 10 | public class ComputeCallable implements Callable { 11 | private Integer value; 12 | private String taskName; 13 | 14 | public ComputeCallable(Integer value, String taskName) { 15 | this.value = value; 16 | this.taskName = taskName; 17 | System.out.println("生成子线程计算任务: " + taskName); 18 | } 19 | 20 | @Override 21 | public Integer call() throws Exception { 22 | Thread.sleep(2000); 23 | String str = "ThreadName: " + Thread.currentThread().getName() + " value: " + value + " TaskName: " + taskName; 24 | System.out.println(str + "Done"); 25 | return value; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/async/ComputeFutureTask.java: -------------------------------------------------------------------------------- 1 | package com.bolt.async; 2 | 3 | import java.util.concurrent.Callable; 4 | import java.util.concurrent.FutureTask; 5 | import java.util.concurrent.atomic.AtomicInteger; 6 | 7 | /** 8 | * @Author: wangxw 9 | * @DateTime: 2020/4/8 10 | * @Description: TODO 11 | */ 12 | public class ComputeFutureTask extends FutureTask { 13 | private AtomicInteger hasRun = new AtomicInteger(); 14 | 15 | public ComputeFutureTask(Callable callable) { 16 | super(callable); 17 | } 18 | 19 | @Override 20 | public void run() { 21 | int i = hasRun.getAndIncrement(); 22 | System.out.println("执行次数:" + i); 23 | super.run(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/async/ComputeTest.java: -------------------------------------------------------------------------------- 1 | package com.bolt.async; 2 | 3 | import com.bolt.util.CountDownLatchUtil; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.junit.runners.JUnit4; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.concurrent.*; 11 | 12 | /** 13 | * @Author: wangxw 14 | * @DateTime: 2020/4/8 15 | * @Description: TODO 16 | */ 17 | @RunWith(JUnit4.class) 18 | public class ComputeTest { 19 | private ConcurrentHashMap> connectionPool = new ConcurrentHashMap>(); 20 | 21 | @Test 22 | public void test1() { 23 | List> taskList = new ArrayList>(); 24 | ExecutorService executor = Executors.newFixedThreadPool(5); 25 | for (int i = 0; i < 5; i++) { 26 | ComputeFutureTask ft = new ComputeFutureTask(new ComputeCallable(i, "task-" + i)); 27 | taskList.add(ft); 28 | executor.execute(ft); 29 | } 30 | 31 | Integer res = 0; 32 | for (ComputeFutureTask task : taskList) { 33 | try { 34 | res += task.get(); 35 | } catch (Exception e) { 36 | } 37 | } 38 | System.out.println(res); 39 | executor.shutdown(); 40 | } 41 | 42 | /** 43 | * 同一个任务的call多线程只会被执行一次 44 | * 45 | * @throws Exception 46 | */ 47 | @Test 48 | public void test2() throws Exception { 49 | ComputeFutureTask ft = new ComputeFutureTask(new ComputeCallable(100, "task-" + 100)); 50 | CountDownLatchUtil latchUtil = new CountDownLatchUtil(); 51 | latchUtil.latch(() -> { 52 | ft.run(); 53 | }); 54 | } 55 | 56 | @Test 57 | public void getOrCreateConnectionTest() throws Exception { 58 | CountDownLatchUtil latchUtil = new CountDownLatchUtil(); 59 | latchUtil.latch(() -> { 60 | try { 61 | Connection c = getOrCreateConnection("127.0.0.1:8081"); 62 | System.out.println(c); 63 | } catch (Exception e) { 64 | e.printStackTrace(); 65 | } 66 | 67 | }); 68 | } 69 | 70 | public Connection getOrCreateConnection(String key) throws Exception { 71 | // ConcurrentHashMap get方法无锁并发 72 | FutureTask connectionFutureTask = connectionPool.get(key); 73 | if (connectionFutureTask == null) { 74 | Callable callable = new Callable() { 75 | @Override 76 | public Connection call() throws Exception { 77 | return createConnection(); 78 | } 79 | }; 80 | 81 | System.out.println("Callable: " + callable); 82 | 83 | ComputeFutureTask newTask = new ComputeFutureTask(callable); 84 | System.out.println("NewTask: " + newTask); 85 | 86 | // cas无锁操作 87 | connectionFutureTask = connectionPool.putIfAbsent(key, newTask); 88 | if (connectionFutureTask == null) { 89 | connectionFutureTask = newTask; 90 | connectionFutureTask.run(); 91 | System.out.println("Join Pool Task : " + connectionFutureTask); 92 | } 93 | } 94 | return connectionFutureTask.get(); 95 | } 96 | 97 | private class Connection { 98 | 99 | } 100 | 101 | private Connection createConnection() { 102 | return new Connection(); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/callback/FutureCallbackTest.java: -------------------------------------------------------------------------------- 1 | package com.bolt.callback; 2 | 3 | import com.bolt.common.Invocation; 4 | import com.bolt.common.command.RequestCommand; 5 | import com.bolt.common.command.ResponseCommand; 6 | import com.bolt.common.enums.CommandCodeEnum; 7 | import com.bolt.common.enums.ResponseStatus; 8 | import com.bolt.reomoting.Connection; 9 | import com.bolt.reomoting.DefaultFuture; 10 | import com.bolt.reomoting.FutureAdapter; 11 | import com.bolt.reomoting.ResponseCallback; 12 | import io.netty.channel.Channel; 13 | import io.netty.channel.socket.nio.NioSocketChannel; 14 | import org.junit.Test; 15 | import org.junit.runner.RunWith; 16 | import org.junit.runners.JUnit4; 17 | 18 | import java.util.concurrent.CompletableFuture; 19 | import java.util.concurrent.CountDownLatch; 20 | 21 | /** 22 | * @Author: wangxw 23 | * @DateTime: 2020/4/28 24 | * @Description: TODO 25 | */ 26 | @RunWith(JUnit4.class) 27 | public class FutureCallbackTest { 28 | 29 | @Test 30 | public void callbcak() throws InterruptedException { 31 | CountDownLatch latch = new CountDownLatch(1); 32 | Channel channel = new NioSocketChannel(); 33 | Connection connection = new Connection(channel); 34 | RequestCommand req = new RequestCommand(CommandCodeEnum.GENERAL_CMD); 35 | int id = req.getId(); 36 | DefaultFuture future = DefaultFuture.newFuture(connection, req 37 | , 1000); 38 | 39 | future.setCallback(new ResponseCallback() { 40 | @Override 41 | public void done(Invocation response) { 42 | latch.countDown(); 43 | 44 | System.out.println("callback"); 45 | } 46 | 47 | 48 | @Override 49 | public void caught(Throwable exception) { 50 | } 51 | }); 52 | ResponseCommand res = new ResponseCommand(id, CommandCodeEnum.GENERAL_CMD); 53 | res.setInvocation(new Invocation()); 54 | res.setStatus(ResponseStatus.SUCCESS); 55 | DefaultFuture.received(connection, res); 56 | latch.await(); 57 | } 58 | 59 | @Test 60 | public void callbackWithCom() throws InterruptedException { 61 | CountDownLatch latch = new CountDownLatch(1); 62 | 63 | Channel channel = new NioSocketChannel(); 64 | Connection connection = new Connection(channel); 65 | RequestCommand req = new RequestCommand(CommandCodeEnum.GENERAL_CMD); 66 | int id = req.getId(); 67 | DefaultFuture future = DefaultFuture.newFuture(connection, req 68 | , 1000); 69 | FutureAdapter futureAdapter = new FutureAdapter(future); 70 | 71 | ResponseCommand res = new ResponseCommand(id, CommandCodeEnum.GENERAL_CMD); 72 | Invocation invocation = new Invocation(); 73 | invocation.setData("---name---"); 74 | res.setInvocation(invocation); 75 | res.setStatus(ResponseStatus.SUCCESS); 76 | DefaultFuture.received(connection, res); 77 | 78 | 79 | futureAdapter.whenComplete((k, v) -> { 80 | latch.countDown(); 81 | System.out.println(k); 82 | }); 83 | 84 | latch.await(); 85 | 86 | } 87 | 88 | @Test 89 | public void completable_future_test() { 90 | CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> { 91 | return "test"; 92 | }); 93 | 94 | completableFuture.whenComplete((k,v)->{ 95 | 96 | }); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/common/ExecutorUtilTest.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common; 2 | 3 | import lombok.SneakyThrows; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.junit.runners.JUnit4; 8 | 9 | import java.util.List; 10 | import java.util.concurrent.ExecutorService; 11 | import java.util.concurrent.Executors; 12 | import java.util.concurrent.TimeUnit; 13 | 14 | /** 15 | * @Author: wangxw 16 | * @DateTime: 2020/4/21 17 | * @Description: TODO 18 | */ 19 | @RunWith(JUnit4.class) 20 | public class ExecutorUtilTest { 21 | ExecutorService executor = Executors.newFixedThreadPool(5); 22 | 23 | @Before 24 | public void setUp() { 25 | 26 | } 27 | 28 | @Test 29 | public void shutDownNow_test() { 30 | 31 | executor.execute(new Runnable() { 32 | @Override 33 | public void run() { 34 | try { 35 | TimeUnit.SECONDS.sleep(10); 36 | System.out.println("task1 has completion"); 37 | 38 | } catch (InterruptedException e) { 39 | System.out.println("task1 has Interrupted"); 40 | } 41 | 42 | } 43 | }); 44 | 45 | for (int i = 0; i < 5; i++) { 46 | Runnable runnable = new Runnable() { 47 | @Override 48 | public void run() { 49 | try { 50 | TimeUnit.SECONDS.sleep(1); 51 | System.out.println("task2 has completion"); 52 | 53 | } catch (InterruptedException e) { 54 | System.out.println("task2 has Interrupted"); 55 | } 56 | 57 | } 58 | }; 59 | System.out.println("runnable "+runnable); 60 | executor.execute(runnable); 61 | } 62 | 63 | List runnables = executor.shutdownNow(); 64 | runnables.forEach(System.out::println); 65 | executor.execute(new Runnable() { 66 | @Override 67 | public void run() { 68 | System.out.println("...."); 69 | } 70 | }); 71 | // try { 72 | // if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { 73 | // System.out.println("awaitTermination : "); 74 | // executor.shutdownNow(); 75 | // } 76 | // } catch (InterruptedException e) { 77 | // System.out.println("awaitTermination interrupted: " + e); 78 | // executor.shutdownNow(); 79 | // } 80 | 81 | 82 | System.out.println(executor.isTerminated()); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/common/NettyAttrTest.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common; 2 | 3 | import com.bolt.reomoting.Connection; 4 | import com.bolt.util.CountDownLatchUtil; 5 | import io.netty.channel.Channel; 6 | import io.netty.channel.socket.nio.NioSocketChannel; 7 | import io.netty.util.AttributeKey; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.junit.runners.JUnit4; 11 | 12 | /** 13 | * @Author: wangxw 14 | * @DateTime: 2020/4/21 15 | * @Description: TODO 16 | */ 17 | @RunWith(JUnit4.class) 18 | public class NettyAttrTest { 19 | @Test 20 | public void test() throws InterruptedException { 21 | AttributeKey CON = AttributeKey.valueOf("CONNECTION"); 22 | io.netty.channel.Channel ch = new NioSocketChannel(); 23 | 24 | CountDownLatchUtil latchUtil = new CountDownLatchUtil(); 25 | 26 | for(int i=0;i<5;i++){ 27 | Connection con = new Connection(ch); 28 | System.out.println("插入:"+con); 29 | ch.attr(CON).setIfAbsent(con); 30 | } 31 | 32 | 33 | Connection connection = ch.attr(CON).get(); 34 | System.out.println(connection); 35 | } 36 | 37 | @Test 38 | public void test1(){ 39 | Channel ch = new NioSocketChannel(); 40 | ch.close(); 41 | ch.close(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/common/UrlTest.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common; 2 | 3 | 4 | import com.bolt.util.NetUtils; 5 | import com.bolt.util.UrlUtils; 6 | import org.junit.Assert; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | import org.junit.runners.JUnit4; 10 | 11 | import java.net.InetSocketAddress; 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | /** 16 | * @Author: wangxw 17 | * @DateTime: 2020/4/7 18 | * @Description: TODO 19 | */ 20 | @RunWith(JUnit4.class) 21 | public class UrlTest { 22 | 23 | @Test 24 | public void test_equals() { 25 | InetSocketAddress socketAddress1 = new InetSocketAddress("127.0.0.1", 80); 26 | InetSocketAddress socketAddress2 = new InetSocketAddress("127.0.0.1", 80); 27 | Assert.assertEquals(socketAddress1, socketAddress2); 28 | } 29 | 30 | @Test 31 | public void test_url_equals() { 32 | Map option = new HashMap(); 33 | option.put(Url.SERIALIZATION, Constants.DEFAULT_REMOTING_SERIALIZATION); 34 | Url urlA = Url.builder().port(80).host("123.0.0.1") 35 | .setParameters(option).build(); 36 | 37 | Url urlB = Url.builder() 38 | .port(80).host("123.0.0.1") 39 | .setParameters(option).build(); 40 | option = new HashMap(); 41 | option.put(Url.MAX_CONNECTION, 10); 42 | 43 | Url urlC = Url.builder() 44 | .port(80).host("123.0.0.1") 45 | .setParameters(option).build(); 46 | Assert.assertEquals(urlA, urlB); 47 | Assert.assertNotEquals(urlA, urlC); 48 | } 49 | 50 | @Test 51 | public void test_url_add() { 52 | Map option = new HashMap(); 53 | option.put(Url.SERIALIZATION, "hessian2"); 54 | option.put(Url.MAX_CONNECTION, 10); 55 | 56 | Url url = Url.builder() 57 | .port(80).host("123.0.0.1") 58 | .setParameters(option).build(); 59 | option = new HashMap(); 60 | option.put(Url.MAX_CONNECTION, 20); 61 | url.addParameters(option); 62 | System.out.println(url.toString()); 63 | } 64 | 65 | 66 | @Test 67 | public void test_url_parse() { 68 | 69 | } 70 | } -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/common/command/CommandFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common.command; 2 | 3 | import com.bolt.common.Invocation; 4 | import com.bolt.common.enums.CommandCodeEnum; 5 | import jdk.nashorn.internal.objects.annotations.Setter; 6 | import lombok.Data; 7 | import lombok.Getter; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.junit.runners.JUnit4; 11 | 12 | import static org.junit.Assert.*; 13 | 14 | /** 15 | * @Author: wangxw 16 | * @DateTime: 2020/4/11 17 | * @Description: TODO 18 | */ 19 | @RunWith(JUnit4.class) 20 | public class CommandFactoryTest { 21 | 22 | @Test 23 | public void createRequestCommand() { 24 | RequestBody requestBody = new RequestBody(CommandCodeEnum.GENERAL_CMD); 25 | requestBody.setName("zhang san"); 26 | CommandFactory factory = new CommandFactory(); 27 | RequestCommand requestCommand = factory.createRequest(requestBody); 28 | Invocation data = requestCommand.getInvocation(); 29 | System.out.println(requestCommand.getCmdCode()); 30 | System.out.println(data.toString()); 31 | } 32 | 33 | public class RequestBody extends Command { 34 | @Getter 35 | private String name; 36 | 37 | public RequestBody(CommandCode cmdCode) { 38 | super(cmdCode); 39 | } 40 | 41 | public void setName(String name) { 42 | this.name = name; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/common/serialize/SerializationTest.java: -------------------------------------------------------------------------------- 1 | package com.bolt.common.serialize; 2 | 3 | import com.bolt.common.extension.ExtensionLoader; 4 | import com.bolt.serialization.ObjectInput; 5 | import com.bolt.serialization.ObjectOutput; 6 | import com.bolt.serialization.Serialization; 7 | import com.bolt.serialization.hessian2.Hessian2ObjectOutput; 8 | import com.bolt.serialization.hessian2.Hessian2Serialization; 9 | import lombok.Data; 10 | import org.junit.Assert; 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | import org.junit.runners.JUnit4; 14 | 15 | import java.io.ByteArrayInputStream; 16 | import java.io.ByteArrayOutputStream; 17 | import java.io.Serializable; 18 | 19 | /** 20 | * @Author: wangxw 21 | * @DateTime: 2020/4/24 22 | * @Description: TODO 23 | */ 24 | @RunWith(JUnit4.class) 25 | public class SerializationTest { 26 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 27 | 28 | @Test 29 | public void test_se() throws Exception { 30 | String str = "zhan"; 31 | Data data = new Data(); 32 | data.setName(str); 33 | Hessian2Serialization hessian2Serialization = new Hessian2Serialization(); 34 | ObjectOutput objectOutput = hessian2Serialization.serialize(byteArrayOutputStream); 35 | objectOutput.writeUTF(str); 36 | objectOutput.writeObject(data); 37 | objectOutput.flushBuffer(); 38 | ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( 39 | byteArrayOutputStream.toByteArray()); 40 | ObjectInput objectInput = hessian2Serialization.deserialize(byteArrayInputStream); 41 | Assert.assertEquals(str, objectInput.readUTF()); 42 | Assert.assertEquals(data.toString(), objectInput.readObject(Data.class).toString()); 43 | } 44 | 45 | @Test 46 | public void t() { 47 | boolean a = true; 48 | boolean b = true; 49 | 50 | if (!a && !b) { 51 | System.out.println("......"); 52 | } 53 | } 54 | 55 | @lombok.Data 56 | public static class Data implements Serializable { 57 | String name; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/config/BoltOptionTest.java: -------------------------------------------------------------------------------- 1 | package com.bolt.config; 2 | 3 | import com.bolt.common.Constants; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.junit.runners.JUnit4; 7 | 8 | import java.util.Map; 9 | 10 | /** 11 | * @Author: wangxw 12 | * @DateTime: 2020/4/9 13 | * @Description: TODO 14 | */ 15 | @RunWith(JUnit4.class) 16 | public class BoltOptionTest { 17 | @Test 18 | public void test() { 19 | 20 | BoltOptions options = new BoltOptions(); 21 | options.option(BoltRemotingOption.SERIALIZATION, Constants.DEFAULT_REMOTING_SERIALIZATION); 22 | 23 | Map map = options.options(BoltRemotingOption.class); 24 | 25 | // map.forEach((k, v) -> { 26 | // System.out.println(k.name() + ":" + k.defaultValue()); 27 | // System.out.println(v); 28 | // }); 29 | // 30 | // map = options.options(); 31 | // 32 | // map.forEach((k, v) -> { 33 | // System.out.println(k.name() + ":" + k.defaultValue()); 34 | // System.out.println(v); 35 | // }); 36 | 37 | 38 | } 39 | 40 | public static void main(String[] args) { 41 | System.out.println(9&7); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/coonection/AsyncTest.java: -------------------------------------------------------------------------------- 1 | package com.bolt.coonection; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.socket.nio.NioSocketChannel; 5 | import io.netty.util.concurrent.*; 6 | import org.junit.Assert; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | import org.junit.runners.JUnit4; 10 | 11 | import java.util.Deque; 12 | import java.util.concurrent.ConcurrentLinkedDeque; 13 | import java.util.concurrent.CountDownLatch; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | /** 17 | * @Author: wangxw 18 | * @DateTime: 2020/4/15 19 | * @Description: TODO 20 | */ 21 | @RunWith(JUnit4.class) 22 | public class AsyncTest { 23 | 24 | @Test 25 | public void promiseTest() throws InterruptedException { 26 | CountDownLatch latch = new CountDownLatch(1); 27 | EventExecutor executorA = new DefaultEventExecutor(new DefaultThreadFactory("EventA")); 28 | EventExecutor executorB = new DefaultEventExecutor(); 29 | Channel channel = new NioSocketChannel(); 30 | // 为EventLoop注册一个Promise 31 | Promise newPromise = executorA.newPromise(); 32 | System.out.println(Thread.currentThread().getName()); 33 | newPromise.addListener(f -> { 34 | if (f.isSuccess()) { 35 | Assert.assertEquals(channel, f.getNow()); 36 | System.out.println(Thread.currentThread().getName()); 37 | latch.countDown(); 38 | } 39 | }); 40 | Assert.assertEquals(false, executorB.inEventLoop()); 41 | executorB.execute(new Runnable() { 42 | @Override 43 | public void run() { 44 | newPromise.setSuccess(channel); 45 | } 46 | }); 47 | latch.await(); 48 | } 49 | @Test 50 | public void succeededFutureTest() { 51 | EventExecutor executor = new DefaultEventExecutor(); 52 | Future future = executor.newSucceededFuture(Boolean.TRUE); 53 | if (future.isDone()) { 54 | Assert.assertEquals(true, future.getNow()); 55 | } 56 | } 57 | 58 | @Test 59 | public void scheduleTest() throws InterruptedException { 60 | CountDownLatch latch = new CountDownLatch(1); 61 | EventExecutor executor = new DefaultEventExecutor(); 62 | ScheduledFuture schedule = executor.schedule(new Runnable() { 63 | @Override 64 | public void run() { 65 | latch.countDown(); 66 | } 67 | }, 5, TimeUnit.SECONDS); 68 | 69 | schedule.cancel(false); 70 | 71 | Assert.assertEquals(true,schedule.isDone()); 72 | Assert.assertEquals(true,schedule.isCancelled()); 73 | 74 | latch.await(); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/coonection/ClientMock.java: -------------------------------------------------------------------------------- 1 | package com.bolt.coonection; 2 | 3 | import com.bolt.coonection.pool.SimpleChannelPoolMap; 4 | import io.netty.bootstrap.Bootstrap; 5 | import io.netty.buffer.PooledByteBufAllocator; 6 | import io.netty.buffer.Unpooled; 7 | import io.netty.channel.Channel; 8 | import io.netty.channel.ChannelOption; 9 | import io.netty.channel.nio.NioEventLoopGroup; 10 | import io.netty.channel.pool.SimpleChannelPool; 11 | import io.netty.channel.socket.nio.NioSocketChannel; 12 | import io.netty.util.CharsetUtil; 13 | import io.netty.util.concurrent.DefaultThreadFactory; 14 | import io.netty.util.concurrent.Future; 15 | import io.netty.util.concurrent.FutureListener; 16 | 17 | import java.net.InetSocketAddress; 18 | 19 | /** 20 | * @Author: wangxw 21 | * @DateTime: 2020/4/15 22 | * @Description: TODO 23 | */ 24 | public class ClientMock { 25 | private static SimpleChannelPoolMap poolMap; 26 | 27 | public static void main(String[] args) { 28 | NioEventLoopGroup group = new NioEventLoopGroup(1, new DefaultThreadFactory("Client-Event", false)); 29 | Bootstrap bootstrap = new Bootstrap(); 30 | bootstrap.group(group) 31 | .channel(NioSocketChannel.class) 32 | .option(ChannelOption.TCP_NODELAY, Boolean.TRUE) 33 | .option(ChannelOption.SO_REUSEADDR, Boolean.TRUE) 34 | .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); 35 | poolMap = new SimpleChannelPoolMap(bootstrap); 36 | 37 | SimpleChannelPool channelPool = poolMap.get(new InetSocketAddress(8090)); 38 | // 从连接池获取一个连接 39 | channelPool.acquire().addListener(new FutureListener() { 40 | @Override 41 | public void operationComplete(Future future) throws Exception { 42 | if (future.isSuccess()) { 43 | Channel channel = future.getNow(); 44 | channel.writeAndFlush(Unpooled.copiedBuffer("hello", CharsetUtil.UTF_8)); 45 | // 将连接放入连接池 46 | channelPool.release(channel); 47 | } 48 | if (future.cause() != null) { 49 | System.out.println(future.cause()); 50 | } 51 | } 52 | }); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/coonection/ServerMock.java: -------------------------------------------------------------------------------- 1 | package com.bolt.coonection; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.buffer.PooledByteBufAllocator; 5 | import io.netty.channel.*; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioServerSocketChannel; 8 | import io.netty.channel.socket.nio.NioSocketChannel; 9 | import io.netty.util.concurrent.DefaultThreadFactory; 10 | 11 | import java.net.InetSocketAddress; 12 | 13 | /** 14 | * @Author: wangxw 15 | * @DateTime: 2020/4/15 16 | * @Description: TODO 17 | */ 18 | public class ServerMock { 19 | 20 | public static void main(String[] args) throws InterruptedException { 21 | ServerBootstrap bootstrap = new ServerBootstrap(); 22 | NioEventLoopGroup bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory("NettyServerBoss", false)); 23 | NioEventLoopGroup workerGroup = new NioEventLoopGroup(4, new DefaultThreadFactory("NettyServerWorker", false)); 24 | bootstrap.group(bossGroup, workerGroup) 25 | .channel(NioServerSocketChannel.class) 26 | .childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE) 27 | .childOption(ChannelOption.SO_REUSEADDR, Boolean.TRUE) 28 | .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) 29 | .childHandler(new ChannelInitializer() { 30 | @Override 31 | protected void initChannel(NioSocketChannel ch) throws Exception { 32 | ch.pipeline().addLast(new SimpleHandler()); 33 | } 34 | }); 35 | 36 | ChannelFuture channelFuture = bootstrap.bind(8090).sync(); 37 | channelFuture.channel(); 38 | 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/coonection/SimpleHandler.java: -------------------------------------------------------------------------------- 1 | package com.bolt.coonection; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandler; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.channel.ChannelInboundHandlerAdapter; 7 | import io.netty.util.CharsetUtil; 8 | 9 | /** 10 | * @Author: wangxw 11 | * @DateTime: 2020/4/15 12 | * @Description: TODO 13 | */ 14 | @ChannelHandler.Sharable 15 | public class SimpleHandler extends ChannelInboundHandlerAdapter { 16 | 17 | @Override 18 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 19 | System.out.println("channelActive: " + ctx.channel()); 20 | } 21 | 22 | @Override 23 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 24 | System.out.println("channelInactive: " + ctx.channel()); 25 | } 26 | 27 | @Override 28 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 29 | ByteBuf byteBuf = (ByteBuf)msg; 30 | System.out.println("channelRead: " + ctx.channel()+" msg: "+byteBuf.toString(CharsetUtil.UTF_8)); 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/coonection/pool/SimpleChannelPoolMap.java: -------------------------------------------------------------------------------- 1 | package com.bolt.coonection.pool; 2 | 3 | import com.bolt.coonection.SimpleHandler; 4 | import io.netty.bootstrap.Bootstrap; 5 | import io.netty.channel.Channel; 6 | import io.netty.channel.pool.AbstractChannelPoolMap; 7 | import io.netty.channel.pool.ChannelPool; 8 | import io.netty.channel.pool.ChannelPoolHandler; 9 | import io.netty.channel.pool.SimpleChannelPool; 10 | 11 | import java.net.InetSocketAddress; 12 | 13 | /** 14 | * @Author: wangxw 15 | * @DateTime: 2020/4/15 16 | * @Description: TODO 17 | */ 18 | public class SimpleChannelPoolMap extends AbstractChannelPoolMap { 19 | private Bootstrap bootstrap; 20 | SimpleHandler simpleHandler = new SimpleHandler(); 21 | 22 | public SimpleChannelPoolMap(Bootstrap bootstrap) { 23 | this.bootstrap = bootstrap; 24 | } 25 | 26 | @Override 27 | protected SimpleChannelPool newPool(InetSocketAddress key) { 28 | return new SimpleChannelPool(bootstrap.remoteAddress(key), new ChannelPoolHandler() { 29 | @Override 30 | public void channelReleased(Channel ch) throws Exception { 31 | System.out.println("channelReleased: " + ch); 32 | } 33 | 34 | @Override 35 | public void channelAcquired(Channel ch) throws Exception { 36 | System.out.println("channelAcquired: " + ch); 37 | 38 | } 39 | @Override 40 | public void channelCreated(Channel ch) throws Exception { 41 | // 为channel添加handler 42 | ch.pipeline().addLast(simpleHandler); 43 | } 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/demo/BoltClientTest.java: -------------------------------------------------------------------------------- 1 | package com.bolt.demo; 2 | 3 | import com.bolt.config.BoltClientOption; 4 | import com.bolt.reomoting.RemotingContext; 5 | import com.bolt.common.Url; 6 | import com.bolt.config.BoltRemotingOption; 7 | import com.bolt.protocol.ReqBody; 8 | import com.bolt.transport.BoltClient; 9 | import com.bolt.util.CountDownLatchUtil; 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | import org.junit.runners.JUnit4; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | import java.util.concurrent.CompletableFuture; 20 | import java.util.concurrent.CountDownLatch; 21 | 22 | /** 23 | * @Author: wangxw 24 | * @DateTime: 2020/4/10 25 | * @Description: TODO 26 | */ 27 | @RunWith(JUnit4.class) 28 | public class BoltClientTest { 29 | private static final Logger logger = LoggerFactory.getLogger(BoltClientTest.class); 30 | BoltClient client; 31 | 32 | @Before 33 | public void setUp() { 34 | client = new BoltClient(); 35 | client.option(BoltClientOption.CONNECT_TIMEOUT, 3000); 36 | client.startUp(); 37 | } 38 | 39 | @Test 40 | public void sync_test() { 41 | Map map = new HashMap(); 42 | // 设置连接超时时间 43 | map.put(Url.CONNECT_TIMEOUT, 9000); 44 | Url url = Url.builder() 45 | .host("127.0.0.1") 46 | .port(9091) 47 | .setParameters(map) 48 | .build(); 49 | ReqBody requestBody = new ReqBody(); 50 | requestBody.setName("zhang"); 51 | requestBody.setAge(20); 52 | String body = client.request(url, requestBody); 53 | logger.info("Client Recv : " + body); 54 | } 55 | 56 | 57 | @Test 58 | public void async_test() throws Exception { 59 | Map map = new HashMap(); 60 | // 设置连接超时时间 61 | map.put(Url.CONNECT_TIMEOUT, 9000); 62 | // 异步调用 63 | map.put(Url.ASYNC, true); 64 | Url url = Url.builder() 65 | .host("127.0.0.1") 66 | .port(9091) 67 | .setParameters(map) 68 | .build(); 69 | ReqBody requestBody = new ReqBody(); 70 | requestBody.setName("zhang"); 71 | requestBody.setAge(20); 72 | CompletableFuture future = client.request(url, requestBody); 73 | logger.info("Client Recv : " + future.get()); 74 | } 75 | 76 | @Test 77 | public void call_back() throws Exception { 78 | Map map = new HashMap(); 79 | // 设置连接超时时间 80 | map.put(Url.CONNECT_TIMEOUT, 9000); 81 | // 异步调用 82 | map.put(Url.ASYNC, true); 83 | Url url = Url.builder() 84 | .host("127.0.0.1") 85 | .port(9091) 86 | .setParameters(map) 87 | .build(); 88 | ReqBody requestBody = new ReqBody(); 89 | requestBody.setName("zhang"); 90 | requestBody.setAge(20); 91 | CompletableFuture future = client.request(url, requestBody); 92 | CountDownLatch latch = new CountDownLatch(1); 93 | future.whenComplete((res, cause) -> { 94 | if (cause != null) { 95 | // 异常处理 96 | } 97 | latch.countDown(); 98 | logger.info("Client Recv : " + res); 99 | }); 100 | latch.await(); 101 | } 102 | 103 | @Test 104 | public void oneway_test() throws Exception { 105 | Map map = new HashMap(); 106 | // 设置连接超时时间 107 | map.put(Url.CONNECT_TIMEOUT, 9000); 108 | // 单向调用 109 | map.put(Url.ONEWAY, true); 110 | Url url = Url.builder() 111 | .host("127.0.0.1") 112 | .port(9091) 113 | .setParameters(map) 114 | .build(); 115 | ReqBody requestBody = new ReqBody(); 116 | requestBody.setName("zhang"); 117 | requestBody.setAge(20); 118 | client.request(url, requestBody); 119 | } 120 | 121 | 122 | } 123 | -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/demo/BoltServerTest.java: -------------------------------------------------------------------------------- 1 | package com.bolt.demo; 2 | 3 | import com.bolt.common.enums.ConnectionEventType; 4 | import com.bolt.config.BoltServerOption; 5 | import com.bolt.transport.BoltServer; 6 | 7 | /** 8 | * @Author: wangxw 9 | * @DateTime: 2020/4/18 10 | * @Description: TODO 11 | */ 12 | public class BoltServerTest { 13 | public static void main(String[] args) { 14 | BoltServer server = new BoltServer(); 15 | server.option(BoltServerOption.PORT,9091); 16 | server.addConnectionEventProcessor(ConnectionEventType.CONNECT,((connection) -> { 17 | // 并发控制,连接统计等 18 | })); 19 | server.startUp(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/demo/RequestBody.java: -------------------------------------------------------------------------------- 1 | package com.bolt.demo; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * @Author: wangxw 9 | * @DateTime: 2020/4/18 10 | * @Description: TODO 11 | */ 12 | @Data 13 | public class RequestBody implements Serializable { 14 | 15 | private static final long serialVersionUID = 6622870532377526353L; 16 | 17 | private String name; 18 | } 19 | -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/threadlocal/FastThreadLocalRunnable.java: -------------------------------------------------------------------------------- 1 | package com.bolt.threadlocal; 2 | 3 | import com.bolt.util.ObjectUtils; 4 | import io.netty.util.concurrent.FastThreadLocal; 5 | 6 | /** 7 | * @Author: wangxw 8 | * @DateTime: 2020/4/27 9 | * @Description: TODO 10 | */ 11 | public class FastThreadLocalRunnable implements Runnable { 12 | private Runnable runnable; 13 | 14 | private FastThreadLocalRunnable(Runnable runnable) { 15 | ObjectUtils.isNotNull(runnable, "runnalbe should be not null"); 16 | this.runnable = runnable; 17 | } 18 | 19 | public static Runnable wrap(Runnable runnable) { 20 | return runnable instanceof FastThreadLocalRunnable ? runnable : new FastThreadLocalRunnable(runnable); 21 | } 22 | 23 | @Override 24 | public void run() { 25 | try { 26 | // 运行任务 27 | this.runnable.run(); 28 | } finally { 29 | /** 30 | * 线程池中的线程由于会被复用,所以线程池中的每一条线程在执行task结束后,要清理掉其InternalThreadLocalMap和其内的FastThreadLocal信息, 31 | * 否则,当这条线程在下一次被复用的时候,其ThreadLocalMap信息还存储着上一次被使用时的信息; 32 | * 另外,假设这条线程不再被使用,但是这个线程有可能不会被销毁(与线程池的类型和配置相关),那么其上的ThreadLocal将发生资源泄露。 33 | */ 34 | FastThreadLocal.removeAll(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/threadlocal/FastThreadLocalTest.java: -------------------------------------------------------------------------------- 1 | package com.bolt.threadlocal; 2 | 3 | import com.bolt.util.CountDownLatchUtil; 4 | import io.netty.util.concurrent.FastThreadLocal; 5 | import io.netty.util.concurrent.FastThreadLocalThread; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.junit.runners.JUnit4; 9 | 10 | import java.util.concurrent.*; 11 | 12 | /** 13 | * @Author: wangxw 14 | * @DateTime: 2020/4/27 15 | * @Description: TODO 16 | */ 17 | @RunWith(JUnit4.class) 18 | public class FastThreadLocalTest { 19 | private static final Executor executor = Executors.newFixedThreadPool(3); 20 | private static final ThreadLocal threadLocal = new ThreadLocal() { 21 | @Override 22 | protected Person initialValue() { 23 | return new Person(); 24 | } 25 | }; 26 | private static final FastThreadLocal fastThreadLocal1 = new FastThreadLocal() { 27 | @Override 28 | protected Integer initialValue() throws Exception { 29 | return 100; 30 | } 31 | 32 | @Override 33 | protected void onRemoval(Integer value) throws Exception { 34 | System.out.println(value + ":我被删除了"); 35 | } 36 | }; 37 | 38 | private static final FastThreadLocal fastThreadLocal2 = new FastThreadLocal() { 39 | @Override 40 | protected Person initialValue() throws Exception { 41 | return new Person(); 42 | } 43 | }; 44 | 45 | @Test 46 | public void testSetAndGetByCommonThread() { 47 | Integer x = fastThreadLocal1.get(); 48 | System.out.println(x); 49 | fastThreadLocal1.set(200); 50 | } 51 | 52 | @Test 53 | public void testSetAndGetByFastThreadLocalThread() { 54 | new FastThreadLocalThread(() -> { 55 | Integer x = fastThreadLocal1.get(); 56 | fastThreadLocal1.set(200); 57 | }).start(); 58 | } 59 | 60 | 61 | @Test 62 | public void testThreadLocal() throws InterruptedException { 63 | CountDownLatch latch = new CountDownLatch(10); 64 | CountDownLatch latchmain = new CountDownLatch(1); 65 | final Runnable runnable = new Runnable() { 66 | @Override 67 | public void run() { 68 | try { 69 | latchmain.await(); 70 | System.out.println(Thread.currentThread().getName() + " : " + fastThreadLocal2.get()); 71 | latch.countDown(); 72 | } catch (Exception e) { 73 | } 74 | } 75 | }; 76 | 77 | for (int i = 0; i < 10; i++) { 78 | executor.execute(FastThreadLocalRunnable.wrap(runnable)); 79 | } 80 | latchmain.countDown(); 81 | latch.await(); 82 | } 83 | 84 | static class Person { 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /bolt-extension/src/test/java/com/bolt/timertask/TimerTaskTest.java: -------------------------------------------------------------------------------- 1 | package com.bolt.timertask; 2 | 3 | import com.bolt.common.Url; 4 | import com.bolt.util.NamedThreadFactory; 5 | import io.netty.util.HashedWheelTimer; 6 | import io.netty.util.Timeout; 7 | import io.netty.util.TimerTask; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.junit.runners.JUnit4; 11 | 12 | import java.util.concurrent.CountDownLatch; 13 | import java.util.concurrent.LinkedBlockingQueue; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | /** 17 | * @Author: wangxw 18 | * @DateTime: 2020/5/2 19 | * @Description: TODO 20 | */ 21 | @RunWith(JUnit4.class) 22 | public class TimerTaskTest { 23 | private static final HashedWheelTimer IDLE_CHECK_TIMER = new HashedWheelTimer( 24 | new NamedThreadFactory("dubbo-client-idleCheck", true), 1, TimeUnit.SECONDS, 128); 25 | LinkedBlockingQueue queue = new LinkedBlockingQueue(); 26 | 27 | @Test 28 | public void test() throws Exception { 29 | IDLE_CHECK_TIMER.newTimeout(new TimerTask() { 30 | @Override 31 | public void run(Timeout timeout) throws Exception { 32 | while (true) { 33 | String str = queue.take(); 34 | System.out.println(str); 35 | } 36 | } 37 | }, 0, TimeUnit.SECONDS); 38 | 39 | queue.put("张三"); 40 | new CountDownLatch(1).await(); 41 | } 42 | 43 | public void ss() throws IllegalArgumentException { 44 | throw new IllegalArgumentException("sss"); 45 | } 46 | @Test 47 | public void reconnectTimerTaskTest() throws InterruptedException { 48 | // ReconnectTimerTask task = new ReconnectTimerTask(); 49 | // IDLE_CHECK_TIMER.newTimeout(task, 0, TimeUnit.SECONDS); 50 | // System.out.println(task); 51 | // System.out.println(IDLE_CHECK_TIMER); 52 | // TimeUnit.SECONDS.sleep(2); 53 | // 54 | // task.reconnect(new Url("123",90)); 55 | // new CountDownLatch(1).await(); 56 | } 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /hermes-example/hemes-sample-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | hermes-example 7 | com.criss 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | hemes-sample-api 13 | 14 | 15 | -------------------------------------------------------------------------------- /hermes-example/hemes-sample-api/src/main/java/com/hermes/api/SimpleRequestBody.java: -------------------------------------------------------------------------------- 1 | package com.hermes.api; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @Author: wangxw 10 | * @DateTime: 2020/5/8 11 | * @Description: TODO 12 | */ 13 | @AllArgsConstructor 14 | @Data 15 | public class SimpleRequestBody implements Serializable { 16 | private String name; 17 | private int age; 18 | private long phone; 19 | } 20 | -------------------------------------------------------------------------------- /hermes-example/hemes-sample-api/src/main/java/com/hermes/api/SimpleResponseBody.java: -------------------------------------------------------------------------------- 1 | package com.hermes.api; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @Author: wangxw 10 | * @DateTime: 2020/5/8 11 | * @Description: TODO 12 | */ 13 | @AllArgsConstructor 14 | @Data 15 | public class SimpleResponseBody implements Serializable { 16 | private String data; 17 | } 18 | -------------------------------------------------------------------------------- /hermes-example/hermes-sample-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | hermes-example 7 | com.criss 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | hermes-client-sample 13 | 14 | 15 | 16 | com.criss 17 | hermes-spring-boot-starter 18 | 1.0.0 19 | 20 | 21 | com.criss 22 | hemes-sample-api 23 | 1.0.0 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /hermes-example/hermes-sample-client/src/main/java/com/hermes/HermesClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.hermes; 2 | 3 | import com.bolt.transport.Client; 4 | import com.hermes.api.SimpleRequestBody; 5 | import com.hermes.api.SimpleResponseBody; 6 | import com.hermes.autoconfigure.EnableHermes; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.boot.SpringApplication; 11 | import org.springframework.boot.autoconfigure.SpringBootApplication; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | @SpringBootApplication 16 | @EnableHermes 17 | @RestController 18 | public class HermesClientApplication { 19 | 20 | private Logger logger = LoggerFactory.getLogger(getClass()); 21 | 22 | @Autowired 23 | private Client client; 24 | 25 | public static void main(String[] args) { 26 | SpringApplication.run(HermesClientApplication.class, args); 27 | } 28 | 29 | @GetMapping("/hermes/rest") 30 | public void rest() { 31 | SimpleRequestBody requestBody = new SimpleRequestBody("criss", 25, 17731352346L); 32 | SimpleResponseBody responseBody = client.request(requestBody); 33 | logger.info("Client Recv: " + responseBody.toString()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /hermes-example/hermes-sample-client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | hermes.client.enabled=true 2 | hermes.client.connect-timeout=9000 3 | hermes.client.timeout=6000 4 | #logging.level.root=debug -------------------------------------------------------------------------------- /hermes-example/hermes-sample-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | hermes-example 7 | com.criss 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | hermes-server-sample 13 | 14 | 15 | 16 | com.criss 17 | hemes-sample-api 18 | 1.0.0 19 | 20 | 21 | com.criss 22 | hermes-spring-boot-starter 23 | 1.0.0 24 | 25 | 26 | -------------------------------------------------------------------------------- /hermes-example/hermes-sample-server/src/main/java/com/hermes/HermesServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.hermes; 2 | 3 | import com.hermes.autoconfigure.EnableHermes; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @SpringBootApplication 8 | @EnableHermes 9 | public class HermesServerApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(HermesServerApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /hermes-example/hermes-sample-server/src/main/java/com/hermes/processor/SimpleUerProcessor.java: -------------------------------------------------------------------------------- 1 | package com.hermes.processor; 2 | 3 | import com.bolt.protocol.processor.AbstractUserProcessorAdapter; 4 | import com.hermes.api.SimpleRequestBody; 5 | import com.hermes.api.SimpleResponseBody; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | /** 10 | * @Author: wangxw 11 | * @DateTime: 2020/5/8 12 | * @Description: TODO 13 | */ 14 | public class SimpleUerProcessor extends AbstractUserProcessorAdapter { 15 | private static final Logger logger = LoggerFactory.getLogger(SimpleUerProcessor.class); 16 | 17 | @Override 18 | public Object handleRequest(SimpleRequestBody request) throws Exception { 19 | logger.info("Server Recv: " + request.toString()); 20 | return new SimpleResponseBody(request.toString()); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /hermes-example/hermes-sample-server/src/main/resources/META-INF/services/com.bolt.protocol.processor.UserProcessor: -------------------------------------------------------------------------------- 1 | simple=com.hermes.processor.SimpleUerProcessor -------------------------------------------------------------------------------- /hermes-example/hermes-sample-server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | hermes.server.enabled=true 2 | #logging.level.root=debug -------------------------------------------------------------------------------- /hermes-example/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | hermes 7 | com.criss 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | hermes-sample-client 13 | hermes-sample-server 14 | hemes-sample-api 15 | 16 | hermes-example 17 | 18 | 19 | -------------------------------------------------------------------------------- /hermes-spring-boot-starter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | hermes 7 | com.criss 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | hermes-spring-boot-starter 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-autoconfigure 17 | 18 | 19 | org.springframework.boot 20 | spring-boot-configuration-processor 21 | true 22 | 23 | 24 | com.criss 25 | bolt-extension 26 | 1.0.0 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /hermes-spring-boot-starter/src/main/java/com/hermes/autoconfigure/EnableHermes.java: -------------------------------------------------------------------------------- 1 | package com.hermes.autoconfigure; 2 | 3 | import org.springframework.context.annotation.Import; 4 | 5 | import java.lang.annotation.*; 6 | 7 | /** 8 | * @Author: wangxw 9 | * @DateTime: 2020/5/8 10 | * @Description: TODO 11 | */ 12 | @Target(ElementType.TYPE) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Import(HermesAutoConfiguration.class) 15 | @Documented 16 | @Inherited 17 | public @interface EnableHermes { 18 | } 19 | -------------------------------------------------------------------------------- /hermes-spring-boot-starter/src/main/java/com/hermes/autoconfigure/HermesAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.hermes.autoconfigure; 2 | 3 | import com.bolt.config.BoltClientOption; 4 | import com.bolt.config.BoltGenericOption; 5 | import com.bolt.config.BoltRemotingOption; 6 | import com.bolt.config.BoltServerOption; 7 | import com.bolt.transport.BoltClient; 8 | import com.bolt.transport.BoltServer; 9 | import com.bolt.transport.Client; 10 | import com.bolt.transport.Server; 11 | import io.netty.buffer.PooledByteBufAllocator; 12 | import io.netty.channel.ChannelOption; 13 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 14 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 15 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 16 | import org.springframework.context.annotation.Bean; 17 | import org.springframework.context.annotation.Configuration; 18 | 19 | @Configuration 20 | @EnableConfigurationProperties({HermesProperties.class}) 21 | public class HermesAutoConfiguration { 22 | 23 | private HermesProperties properties; 24 | 25 | public HermesAutoConfiguration(HermesProperties properties) { 26 | this.properties = properties; 27 | } 28 | 29 | @Bean 30 | @ConditionalOnMissingBean 31 | @ConditionalOnProperty(prefix = "hermes.client", name = "enabled", havingValue = "true") 32 | public Client client() { 33 | HermesProperties.Client pc = properties.getClient(); 34 | BoltClient client = new BoltClient(); 35 | client.option(BoltClientOption.HOST, pc.getHost()) 36 | .option(BoltClientOption.PORT, pc.getPort()) 37 | .option(BoltGenericOption.TCP_NODELAY, properties.isTcpNodelay()) 38 | .option(BoltGenericOption.TCP_SO_REUSEADDR, properties.isTcpSoReuseaddr()) 39 | .option(BoltGenericOption.NETTY_BUFFER_HIGH_WATER_MARK, properties.getNettyBufferHighWatermark()) 40 | .option(BoltGenericOption.NETTY_BUFFER_LOW_WATER_MARK, properties.getNettyBufferLowerWatermark()) 41 | .option(BoltGenericOption.NETTY_IO_RATIO, properties.getNettyIORatio()) 42 | .option(BoltGenericOption.TCP_SO_KEEPALIVE, properties.isTcpSoKeepalive()) 43 | .option(BoltClientOption.HEARTBEATINTERVAL, pc.getHeartbeatInterval()) 44 | .option(BoltClientOption.CONNECT_TIMEOUT, pc.getConnectTimeout()) 45 | .option(BoltClientOption.TIMEOUT, pc.getTimeout()) 46 | .option(BoltClientOption.MAX_CONNECTION, pc.getMaxConnection()) 47 | .option(BoltClientOption.ACQUIRE_TIMEOUT, pc.getAcquireTimeout()) 48 | .option(BoltClientOption.ACQUIRE_TIMEOUT_ACTION, pc.getAcquireTimeoutAction()) 49 | .option(BoltClientOption.RELEASE_HEALTH_CHECK, pc.isHealthCheck()) 50 | .option(BoltClientOption.CONNECTION_LAST_RECENT_USED, pc.isLastRecentUsed()) 51 | .option(BoltRemotingOption.SERIALIZATION, properties.getSerialization()); 52 | client.startUp(); 53 | return client; 54 | } 55 | 56 | @Bean 57 | @ConditionalOnMissingBean 58 | @ConditionalOnProperty(prefix = "hermes.server", name = "enabled", havingValue = "true") 59 | public Server server() { 60 | HermesProperties.Server ps = properties.getServer(); 61 | BoltServer server = new BoltServer(); 62 | server.option(BoltServerOption.PORT, ps.getPort()) 63 | .option(BoltGenericOption.TCP_NODELAY, properties.isTcpNodelay()) 64 | .option(BoltGenericOption.TCP_SO_REUSEADDR, properties.isTcpSoReuseaddr()) 65 | .option(BoltGenericOption.NETTY_BUFFER_HIGH_WATER_MARK, properties.getNettyBufferHighWatermark()) 66 | .option(BoltGenericOption.NETTY_BUFFER_LOW_WATER_MARK, properties.getNettyBufferLowerWatermark()) 67 | .option(BoltGenericOption.NETTY_IO_RATIO, properties.getNettyIORatio()) 68 | .option(BoltGenericOption.TCP_SO_KEEPALIVE, properties.isTcpSoKeepalive()) 69 | .option(BoltGenericOption.IO_THREADS, properties.getNettyServerIoThread()) 70 | .option(BoltRemotingOption.SERIALIZATION, properties.getSerialization()); 71 | server.startUp(); 72 | return server; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /hermes-spring-boot-starter/src/main/java/com/hermes/autoconfigure/HermesProperties.java: -------------------------------------------------------------------------------- 1 | package com.hermes.autoconfigure; 2 | 3 | import com.bolt.common.Constants; 4 | import lombok.Data; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | 7 | @ConfigurationProperties(prefix = "hermes") 8 | @Data 9 | public class HermesProperties { 10 | private Client client = new Client(); 11 | private Server server = new Server(); 12 | 13 | private String serialization = "hessian2"; 14 | private boolean tcpNodelay = true; 15 | private boolean tcpSoReuseaddr = true; 16 | private boolean tcpSoKeepalive = false; 17 | private int nettyIORatio = 70; 18 | private boolean nettyBufferPooled = true; 19 | private int nettyBufferHighWatermark = 64 * 1024; 20 | private int nettyBufferLowerWatermark = 32 * 1024; 21 | private int nettyServerIoThread = Constants.DEFAULT_IO_THREADS; 22 | 23 | @Data 24 | public static class Client { 25 | private boolean enabled = false; 26 | private String host = "127.0.0.1"; 27 | private int port = 8091; 28 | private int connectTimeout = 3000; 29 | private int timeout =3000; 30 | private int heartbeatInterval = 15 * 1000; 31 | private int maxConnection = 1; 32 | private int maxPendingAcquires = Integer.MAX_VALUE; 33 | private long acquireTimeout = 3000; 34 | private String acquireTimeoutAction = "new"; 35 | private boolean lastRecentUsed = false; 36 | private boolean healthCheck = true; 37 | 38 | } 39 | 40 | @Data 41 | public static class Server { 42 | private boolean enabled = false; 43 | private int port = 8091; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.criss 8 | hermes 9 | pom 10 | 1.0.0 11 | 12 | bolt-extension 13 | hermes-spring-boot-starter 14 | hermes-example 15 | 16 | 17 | 18 | 19 | org.springframework.boot 20 | spring-boot-dependencies 21 | 2.2.6.RELEASE 22 | pom 23 | import 24 | 25 | 26 | 27 | 28 | 1.8 29 | 3.5.1 30 | UTF-8 31 | 3.2.3 32 | 33 | 34 | 35 | org.projectlombok 36 | lombok 37 | true 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-logging 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-test 46 | test 47 | 48 | 49 | junit 50 | junit 51 | test 52 | 53 | 54 | org.apache.commons 55 | commons-lang3 56 | 57 | 58 | 59 | 60 | 61 | org.apache.maven.plugins 62 | maven-compiler-plugin 63 | ${maven.compiler.plugin} 64 | 65 | ${java.version} 66 | ${java.version} 67 | ${project.encoding} 68 | 69 | 70 | 71 | 72 | --------------------------------------------------------------------------------