看我这标题,越来越觉得自己不去UC上班太浪费了,哈哈哈。。。本来这篇文章之前就要发布的,但是因为一些事情耽搁了
开始步入正题:手写RPC的简单实现
什么是RPC
常用的RPC框架有哪些
怎么实现
一丶什么是RPC
远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的思想。RPC 是一种技术思想而非一种规范或协议。
RPC 的核心功能主要有这几个部分组成,分别是:客户端、客户端 Stub、网络传输模块、服务端 Stub、服务端等。
客户端:调用服务方。
客户端存根:存放服务端地址信息,将请求参数数据信息打包成网络消息,通过网络传输发送给服务端。
服务端存根:接收发送过来的请求消息并进行解包,然后再调用本地服务进行处理。
网络传输:通过TCP 或 HTTP进行网络传输。
RPC调用过程:
客户端->通过本地调用的方式调用服务->客户端->接收调用请求后负责序列化->找到远程服务地址->将消息发送给服务端->服务端存根->收到消息后进行反序列化操作->根据结果调用本地的服务进行相关处理->本地服务业务处理->处理结果返回->序列化结果->将结果发送至消费方->客户端存根->接收到消息并反序列化->服务消费方得到最终结果。
二、常用的RPC框架有哪些
应用级的服务框架:阿里的 Dubbo、gRPC、SpringCloud和Thrift 等。
远程通信协议:RMI、Socket、SOAP(HTTP XML)、REST(HTTP JSON)等。
通信框架:MINA 和 Netty等。
下面重点介绍几种应用级服务框架:
Dubbo:之前阿里开源的一个极为出名的 RPC 框架,在很多互联网公司和企业应用中广泛使用。后面由Weex捐赠给 Apache,由Apache进行孵化,现如今Apache Dubbo从孵化器毕业。(dubbox是由当当在阿里的基础上升级的)
gRPC:是 Google 的产物,基于 HTTP 协议实现的,底层使用到了 Netty 框架的支持。
SpringCloud:spring的产物,熟悉spring的应该知道,老熟人了。与其说是框架,不如说是是一系列框架的有序集合。
Thrift:是由 Facebook 开源的一个 RPC 框架,现在已经挂在 apache下了。
三、怎么实现:
如果想要自己实现一个 RPC,最简单的方式要实现三个技术点,分别是:
服务寻址
数据流的序列化和反序列化
网络传输
本项目的环境
JAVA11,Spring5.1,netty4
话不多说,开始动手。上代码
发布生产者类
public class ProviderBean implements ApplicationContextAware {
private String interfacea;
private String mapping;
private String alias;
protected void Export() {
System.out.format("生产者信息", interfacea, mapping, alias);
}
private Logger logger = LoggerFactory.getLogger(ProviderBean.class);
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
RpcProviderConfig rpcProviderConfig = new RpcProviderConfig();
rpcProviderConfig.setNozzle(interfacea);
rpcProviderConfig.setRef(mapping);
rpcProviderConfig.setAlias(alias);
rpcProviderConfig.setHost(LocalServerInfo.LOCAL_HOST);
rpcProviderConfig.setPort(LocalServerInfo.LOCAL_PORT);
long count = RedisRegistryCenter.registryProvider(interfacea, alias, JSON.toJSONString(rpcProviderConfig));
logger.info("", interfacea, alias, count);
}
}
消费者类
@SuppressWarnings("rawtypes")
public class ConsumerBean<T> implements FactoryBean {
private ChannelFuture channelFuture;
private RpcProviderConfig rpcProviderConfig;
private String interfaceb;
private String alias;
protected synchronized T refer() {
System.out.format(" \r\n", interfaceb, alias);
return null;
}
public Object getObject() throws Exception {
if (null == rpcProviderConfig) {
String infoStr = RedisRegistryCenter.obtainProvider(interfaceb, alias);
rpcProviderConfig = JSON.parseObject(infoStr, RpcProviderConfig.class);
}
Assert.isTrue(null != rpcProviderConfig);
if (null == channelFuture) {
ClientSocket clientSocket = new ClientSocket(rpcProviderConfig.getHost(), rpcProviderConfig.getPort());
new Thread(clientSocket).start();
for (int i = 0; i < 100; i++) {
if (null != channelFuture) break;
Thread.sleep(500);
channelFuture = clientSocket.getFuture();
}
}
Assert.isTrue(null != channelFuture);
Request request = new Request();
request.setChannel(channelFuture.channel());
request.setNozzle(interfaceb);
request.setRef(rpcProviderConfig.getRef());
request.setAlias(alias);
return (T) JDKProxy.getProxy(ClassLoaderUtils.forName(interfaceb), request);
}
public Class<?> getObjectType() {
try {
return ClassLoaderUtils.forName(interfaceb);
} catch (ClassNotFoundException e) {
return null;
}
}
public boolean isSingleton() {
return true;
}
}
通讯这块:
public class ServerBean implements ApplicationContextAware {
private String host;
private int port;
private Logger logger = LoggerFactory.getLogger(ServerBean.class);
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
logger.info("启动注册中心 ...");
RedisRegistryCenter.init(host, port);
logger.info("启动注册中心完成 {} {}", host, port);
logger.info("初始化生产端服务 ...");
ServerSocket serverSocket = new ServerSocket(applicationContext);
Thread thread = new Thread(serverSocket);
thread.start();
while (!serverSocket.isActiveSocketServer()) {
try {
Thread.sleep(500);
} catch (InterruptedException ignore) {
}
}
logger.info("初始化生产端服务完成 ", LocalServerInfo.LOCAL_HOST, LocalServerInfo.LOCAL_PORT);
}
}
解析器
public class DefinitionParser implements BeanDefinitionParser {
private final Class<?> beanClass;
DefinitionParser(Class<?> beanClass) {
this.beanClass = beanClass;
}
public BeanDefinition parse(Element element, ParserContext parserContext) {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(beanClass);
beanDefinition.setLazyInit(false);
String beanName = element.getAttribute("id");
parserContext.getRegistry().registerBeanDefinition(beanName, beanDefinition);
for (Method method : beanClass.getMethods()) {
if (!isProperty(method, beanClass)) continue;
String name = method.getName();
String methodName = name.substring(3, 4).toLowerCase() + name.substring(4);
String value = element.getAttribute(methodName);
beanDefinition.getPropertyValues().addPropertyValue(methodName, value);
}
return beanDefinition;
}
private boolean isProperty(Method method, Class beanClass) {
String methodName = method.getName();
boolean flag = methodName.length() > 3 && methodName.startsWith("set") && Modifier.isPublic(method.getModifiers()) && method.getParameterTypes().length == 1;
Method getter = null;
if (!flag) return false;
Class<?> type = method.getParameterTypes()[0];
try {
getter = beanClass.getMethod("get" + methodName.substring(3));
} catch (Exception e) {
e.printStackTrace();
}
if (null == getter) {
try {
getter = beanClass.getMethod("is" + methodName.substring(3));
} catch (Exception e) {
e.printStackTrace();
}
}
flag = getter != null && Modifier.isPublic(getter.getModifiers()) && type.equals(getter.getReturnType());
return flag;
}
}
//命名空间
public class NamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("consumer", new DefinitionParser(ConsumerBean.class));
registerBeanDefinitionParser("provider", new DefinitionParser(ProviderBean.class));
registerBeanDefinitionParser("server", new DefinitionParser(ServerBean.class));
}
}
自定义XML的约束
dtd或者xsd显得稍微规范一点,自己想怎么约束就怎么约束
接下来到通讯这块,选择netty作为我们的socket框架,采用future方式进行通信。
客户端套接字
public class ClientSocket implements Runnable {
private ChannelFuture future;
private String inetHost;
private int inetPort;
public ClientSocket(String inetHost, int inetPort) {
this.inetHost = inetHost;
this.inetPort = inetPort;
}
public void run() {
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(workerGroup);
b.channel(NioSocketChannel.class);
b.option(ChannelOption.AUTO_READ, true);
b.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(
new RpcDecoder(Response.class),
new RpcEncoder(Request.class),
new MyClientHandler());
}
});
ChannelFuture f = b.connect(inetHost, inetPort).sync();
this.future = f;
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
}
}
public ChannelFuture getFuture() {
return future;
}
public void setFuture(ChannelFuture future) {
this.future = future;
}
}
客户端处理器
public class MyClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object obj) throws Exception {
Response msg = (Response) obj;
String requestId = msg.getRequestId();
SyncWriteFuture future = (SyncWriteFuture) SyncWriteMap.syncKey.get(requestId);
if (future != null) {
future.setResponse(msg);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
Redis作为注册中心
public class RedisRegistryCenter {
private static Jedis jedis;
public static void init(String host, int port) {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(5);
config.setTestOnBorrow(false);
JedisPool jedisPool = new JedisPool(config, host, port);
jedis = jedisPool.getResource();
}
public static Long registryProvider(String nozzle, String alias, String info) {
return jedis.sadd(nozzle + "_" + alias, info);
}
public static String obtainProvider(String nozzle, String alias) {
return jedis.srandmember(nozzle + "_" + alias);
}
public static Jedis jedis() {
return jedis;
}
}
服务端套接字
public class ServerSocket implements Runnable {
private ChannelFuture f;
private transient ApplicationContext applicationContext;
public ServerSocket(ApplicationContext applicationContext){
this.applicationContext = applicationContext;
}
public boolean isActiveSocketServer() {
try {
if (f != null) {
return f.channel().isActive();
} else {
return false;
}
} catch (Exception e) {
return false;
}
}
public void run() {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
ch.pipeline().addLast(
new RpcDecoder(Request.class),
new RpcEncoder(Response.class),
new MyServerHandler(applicationContext));
}
});
int port = 22201;
while (NetUtil.isPortUsing(port)) {
port++;
}
LocalServerInfo.LOCAL_HOST = NetUtil.getHost();
LocalServerInfo.LOCAL_PORT = port;
this.f = b.bind(port).sync();
this.f.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
服务端处理器
public class MyServerHandler extends ChannelInboundHandlerAdapter {
private ApplicationContext applicationContext;
MyServerHandler(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void channelRead(ChannelHandlerContext ctx, Object obj) {
try {
Request msg = (Request) obj;
Class<?> classType = ClassLoaderUtils.forName(msg.getNozzle());
Method addMethod = classType.getMethod(msg.getMethodName(), msg.getParamTypes());
Object objectBean = applicationContext.getBean(msg.getRef());
Object result = addMethod.invoke(objectBean, msg.getArgs());
Response request = new Response();
request.setRequestId(msg.getRequestId());
request.setResult(result);
ctx.writeAndFlush(request);
ReferenceCountUtil.release(msg);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
}
请求类
public class Request {
private transient Channel channel;
private String requestId;
private String methodName;
private Class[] paramTypes;
private Object[] args;
private String nozzle;
private String ref;
private String alias;
public Channel getChannel() {
return channel;
}
public void setChannel(Channel channel) {
this.channel = channel;
}
public String getRequestId() {
return requestId;
}
public void setRequestId(String requestId) {
this.requestId = requestId;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Class[] getParamTypes() {
return paramTypes;
}
public void setParamTypes(Class[] paramTypes) {
this.paramTypes = paramTypes;
}
public Object[] getArgs() {
return args;
}
public void setArgs(Object[] args) {
this.args = args;
}
public String getNozzle() {
return nozzle;
}
public void setNozzle(String nozzle) {
this.nozzle = nozzle;
}
public String getRef() {
return ref;
}
public void setRef(String ref) {
this.ref = ref;
}
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
响应类
public class Response {
private transient Channel channel;
private String requestId;
private Object result;
public Channel getChannel() {
return channel;
}
public void setChannel(Channel channel) {
this.channel = channel;
}
public String getRequestId() {
return requestId;
}
public void setRequestId(String requestId) {
this.requestId = requestId;
}
public Object getResult() {
return result;
}
public void setResult(Object result) {
this.result = result;
}
}
给RPC进行编码
public class RpcEncoder extends MessageToByteEncoder {
private Class<?> genericClass;
public RpcEncoder(Class<?> genericClass) {
this.genericClass = genericClass;
}
protected void encode(ChannelHandlerContext ctx, Object in, ByteBuf out) {
if (genericClass.isInstance(in)) {
byte[] data = SerializationUtil.serialize(in);
out.writeInt(data.length);
out.writeBytes(data);
}
}
}
RPC解码器
public class RpcDecoder extends ByteToMessageDecoder {
private Class<?> genericClass;
public RpcDecoder(Class<?> genericClass) {
this.genericClass = genericClass;
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
if (in.readableBytes() < 4) {
return;
}
in.markReaderIndex();
int dataLength = in.readInt();
if (in.readableBytes() < dataLength) {
in.resetReaderIndex();
return;
}
byte[] data = new byte[dataLength];
in.readBytes(data);
out.add(SerializationUtil.deserialize(data, genericClass));
}
}
输出
public class SyncWrite {
public Response writeAndSync(final Channel channel, final Request request, final long timeout) throws Exception {
if (channel == null) {
throw new NullPointerException("channel");
}
if (request == null) {
throw new NullPointerException("request");
}
if (timeout <= 0) {
throw new IllegalArgumentException("timeout <= 0");
}
String requestId = UUID.randomUUID().toString();
request.setRequestId(requestId);
WriteFuture<Response> future = new SyncWriteFuture(request.getRequestId());
SyncWriteMap.syncKey.put(request.getRequestId(), future);
Response response = doWriteAndSync(channel, request, timeout, future);
SyncWriteMap.syncKey.remove(request.getRequestId());
return response;
}
private Response doWriteAndSync(final Channel channel, final Request request, final long timeout, final WriteFuture<Response> writeFuture) throws Exception {
channel.writeAndFlush(request).addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) {
writeFuture.setWriteResult(future.isSuccess());
writeFuture.setCause(future.cause());
if (!writeFuture.isWriteSuccess()) {
SyncWriteMap.syncKey.remove(writeFuture.requestId());
}
}
});
Response response = writeFuture.get(timeout, TimeUnit.MILLISECONDS);
if (response == null) {
if (writeFuture.isTimeout()) {
throw new TimeoutException();
} else {
// write exception
throw new Exception(writeFuture.cause());
}
}
return response;
}
}
存放的容器
public class SyncWriteMap {
public static Map<String, WriteFuture> syncKey = new ConcurrentHashMap<String, WriteFuture>();
}
缓冲接口和具体实现类
public class SyncWriteFuture implements WriteFuture<Response> {
private CountDownLatch latch = new CountDownLatch(1);
private final long begin = System.currentTimeMillis();
private long timeout;
private Response response;
private final String requestId;
private boolean writeResult;
private Throwable cause;
private boolean isTimeout = false;
public SyncWriteFuture(String requestId) {
this.requestId = requestId;
}
public SyncWriteFuture(String requestId, long timeout) {
this.requestId = requestId;
this.timeout = timeout;
writeResult = true;
isTimeout = false;
}
public Throwable cause() {
return cause;
}
public void setCause(Throwable cause) {
this.cause = cause;
}
public boolean isWriteSuccess() {
return writeResult;
}
public void setWriteResult(boolean result) {
this.writeResult = result;
}
public String requestId() {
return requestId;
}
public Response response() {
return response;
}
public void setResponse(Response response) {
this.response = response;
latch.countDown();
}
public boolean cancel(boolean mayInterruptIfRunning) {
return true;
}
public boolean isCancelled() {
return false;
}
public boolean isDone() {
return false;
}
public Response get() throws InterruptedException, ExecutionException {
latch.wait();
return response;
}
public Response get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
if (latch.await(timeout, unit)) {
return response;
}
return null;
}
public boolean isTimeout() {
if (isTimeout) {
return isTimeout;
}
return System.currentTimeMillis() - begin > timeout;
}
}
public class SyncWriteFuture implements WriteFuture<Response> {
private CountDownLatch latch = new CountDownLatch(1);
private final long begin = System.currentTimeMillis();
private long timeout;
private Response response;
private final String requestId;
private boolean writeResult;
private Throwable cause;
private boolean isTimeout = false;
public SyncWriteFuture(String requestId) {
this.requestId = requestId;
}
public SyncWriteFuture(String requestId, long timeout) {
this.requestId = requestId;
this.timeout = timeout;
writeResult = true;
isTimeout = false;
}
public Throwable cause() {
return cause;
}
public void setCause(Throwable cause) {
this.cause = cause;
}
public boolean isWriteSuccess() {
return writeResult;
}
public void setWriteResult(boolean result) {
this.writeResult = result;
}
public String requestId() {
return requestId;
}
public Response response() {
return response;
}
public void setResponse(Response response) {
this.response = response;
latch.countDown();
}
public boolean cancel(boolean mayInterruptIfRunning) {
return true;
}
public boolean isCancelled() {
return false;
}
public boolean isDone() {
return false;
}
public Response get() throws InterruptedException, ExecutionException {
latch.wait();
return response;
}
public Response get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
if (latch.await(timeout, unit)) {
return response;
}
return null;
}
public boolean isTimeout() {
if (isTimeout) {
return isTimeout;
}
return System.currentTimeMillis() - begin > timeout;
}
}
动态代理调用
public class JDKInvocationHandler implements InvocationHandler {
private Request request;
public JDKInvocationHandler(Request request) {
this.request = request;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
Class[] paramTypes = method.getParameterTypes();
if ("toString".equals(methodName) && paramTypes.length == 0) {
return request.toString();
} else if ("hashCode".equals(methodName) && paramTypes.length == 0) {
return request.hashCode();
} else if ("equals".equals(methodName) && paramTypes.length == 1) {
return request.equals(args[0]);
}
request.setMethodName(methodName);
request.setParamTypes(paramTypes);
request.setArgs(args);
request.setRef(request.getRef());
Response response = new SyncWrite().writeAndSync(request.getChannel(), request, 5000);
return response.getResult();
}
}
}
代理
public class JDKProxy {
public static <T> T getProxy(Class<T> interfaceClass, Request request) throws Exception {
InvocationHandler handler = new JDKInvocationHandler(request);
ClassLoader classLoader = ClassLoaderUtils.getCurrentClassLoader();
T result = (T) Proxy.newProxyInstance(classLoader, new Class[]{interfaceClass}, handler);
return result;
}
序列化工具类
public class SerializationUtil {
@SuppressWarnings("rawtypes")
private static Map<Class<?>, Schema> cachedSchema = new ConcurrentHashMap();
private static Objenesis objenesis = new ObjenesisStd();
private SerializationUtil() {
}
@SuppressWarnings("unchecked")
public static <T> byte[] serialize(T obj) {
Class<T> cls = (Class<T>) obj.getClass();
LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
try {
Schema schema = getSchema(cls);
return ProtostuffIOUtil.toByteArray(obj, schema, buffer);
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
} finally {
buffer.clear();
}
}
@SuppressWarnings("unchecked")
public static <T> T deserialize(byte[] data, Class<T> cls) {
try {
T message = objenesis.newInstance(cls);
Schema schema = getSchema(cls);
ProtostuffIOUtil.mergeFrom(data, message, schema);
return message;
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
@SuppressWarnings("rawtypes")
private static <T> Schema getSchema(Class<T> cls) {
Schema schema = (Schema) cachedSchema.get(cls);
if (schema == null) {
schema = RuntimeSchema.createFrom(cls);
cachedSchema.put(cls, schema);
}
return schema;
}
}
public class Constants {
public static final char HIDE_KEY_PREFIX = '.';
public static final char INTERNAL_KEY_PREFIX = '_';
}
字符串工具
public class StringUtils {
public static final String EMPTY = "";
public static boolean isEmpty(CharSequence cs) {
return cs == null || cs.length() == 0;
}
public static boolean isNotEmpty(CharSequence cs) {
return !StringUtils.isEmpty(cs);
}
public static boolean isBlank(CharSequence cs) {
int strLen;
if (cs == null || (strLen = cs.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if (Character.isWhitespace(cs.charAt(i)) == false) {
return false;
}
}
return true;
}
public static boolean isNotBlank(CharSequence cs) {
return !StringUtils.isBlank(cs);
}
public static String trim(String str) {
return str == null ? null : str.trim();
}
public static String trimToNull(String str) {
String ts = trim(str);
return isEmpty(ts) ? null : ts;
}
public static String trimToEmpty(String str) {
return str == null ? EMPTY : str.trim();
}
public static String toString(byte[] bytes, String charsetName) throws UnsupportedEncodingException {
return charsetName == null ? new String(bytes) : new String(bytes, charsetName);
}
public static String defaultString(final String str) {
return str == null ? EMPTY : str;
}
public static String[] split(String src, String separator) {
if (isEmpty(separator)) {
return new String[]{src};
}
if (isEmpty(src)) {
return new String[0];
}
return src.split(separator, -1);
}
public static String[] splitWithCommaOrSemicolon(String src) {
if (isEmpty(src)) {
return new String[0];
}
String[] ss = split(src.replace(',', ';'), ";");
List<String> list = new ArrayList<String>();
for (String s : ss) {
if (!isBlank(s)) {
list.add(s.trim());
}
}
return list.toArray(new String[list.size()]);
}
public static String join(String[] strings, String separator) {
if (strings == null || strings.length == 0) {
return EMPTY;
}
StringBuilder sb = new StringBuilder();
for (String string : strings) {
if (isNotBlank(string)) {
sb.append(string).append(separator);
}
}
return sb.length() > 0 ? sb.substring(0, sb.length() - separator.length()) : StringUtils.EMPTY;
}
public static String joinWithComma(String... strings) {
return join(strings, ",");
}
public static boolean isValidParamKey(String paramkey) {
char c = paramkey.charAt(0);
return c != Constants.HIDE_KEY_PREFIX && c != Constants.INTERNAL_KEY_PREFIX;
}
public static boolean isInternalParamKey(String paramkey) {
char c = paramkey.charAt(0);
return c == Constants.INTERNAL_KEY_PREFIX;
}
public static String toString(Object o) {
return o != null ? o.toString() : null;
}
}
通讯工具
public class NetUtil {
public static boolean isPortUsing(int port) throws UnknownHostException {
boolean flag = false;
try {
Socket socket = new Socket("localhost", port);
socket.close();
flag = true;
} catch (IOException e) {
e.printStackTrace();
}
return flag;
}
public static String getHost() throws UnknownHostException {
return InetAddress.getLocalHost().getHostAddress();
}
public static void main(String[] args) throws UnknownHostException {
NetUtil.isPortUsing(8080);
}
}
类加载工具
public class ClassLoaderUtils {
private static Set<Class> primitiveSet = new HashSet<Class>();
static {
primitiveSet.add(Integer.class);
primitiveSet.add(Long.class);
primitiveSet.add(Float.class);
primitiveSet.add(Byte.class);
primitiveSet.add(Short.class);
primitiveSet.add(Double.class);
primitiveSet.add(Character.class);
primitiveSet.add(Boolean.class);
}
public static ClassLoader getCurrentClassLoader() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl == null) {
cl = ClassLoaderUtils.class.getClassLoader();
}
return cl == null ? ClassLoader.getSystemClassLoader() : cl;
}
public static ClassLoader getClassLoader(Class<?> clazz) {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader != null) {
return loader;
}
if (clazz != null) {
loader = clazz.getClassLoader();
if (loader != null) {
return loader;
}
return clazz.getClassLoader();
}
return ClassLoader.getSystemClassLoader();
}
public static Class forName(String className)
throws ClassNotFoundException {
return forName(className, true);
}
public static Class forName(String className, boolean initialize)
throws ClassNotFoundException {
return Class.forName(className, initialize, getCurrentClassLoader());
}
public static Class forName(String className, ClassLoader cl)
throws ClassNotFoundException {
return Class.forName(className, true, cl);
}
public static <T> T newInstance(Class<T> clazz) throws Exception {
if(primitiveSet.contains(clazz)){
return null;
}
if (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers())) {
Constructor constructorList[] = clazz.getDeclaredConstructors();
Constructor defaultConstructor = null;
for (Constructor con : constructorList) {
if (con.getParameterTypes().length == 1) {
defaultConstructor = con;
break;
}
}
if (defaultConstructor != null) {
if (defaultConstructor.isAccessible()) {
return (T) defaultConstructor.newInstance(new Object[]{null});
} else {
try {
defaultConstructor.setAccessible(true);
return (T) defaultConstructor.newInstance(new Object[]{null});
} finally {
defaultConstructor.setAccessible(false);
}
}
} else {
throw new Exception("The " + clazz.getCanonicalName() + " has no default constructor!");
}
}
try {
return clazz.newInstance();
} catch (Exception e) {
Constructor<T> constructor = clazz.getDeclaredConstructor();
if (constructor.isAccessible()) {
throw new Exception("The " + clazz.getCanonicalName() + " has no default constructor!", e);
} else {
try {
constructor.setAccessible(true);
return constructor.newInstance();
} finally {
constructor.setAccessible(false);
}
}
}
}
}
这篇文章,本来我是写了一个简单版的,就是简单的map做注册中心就完事了的。后面被一个京东六年的老哥怼了,经他指点的基础上完成了的中国。测试我就不写了。如果看不懂,就把代码抄下来。运行看效果,然后再慢慢看。