+ * 5 s + * 5 seconds + * 10m + * 10 minutes + *+ */ + public static Duration of(String duration) { + Matcher matcher = PATTERN.matcher(duration); + if (!matcher.matches()) { + throw new IllegalArgumentException("Invalid duration: " + duration); + } + + if (matcher.group(1) != null) { + return INFINITE; + } else { + String unit = matcher.group(4); + String value = matcher.group(3); + return new Duration(Long.parseLong(value), SUFFIXES.get(unit)); + } + } + + /** + * Returns a Duration of {@code count} seconds. + */ + public static Duration seconds(long count) { + return new Duration(count, TimeUnit.SECONDS); + } + + /** + * Returns a Duration of {@code count} seconds. + */ + public static Duration secs(long count) { + return new Duration(count, TimeUnit.SECONDS); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if ((obj == null) || (getClass() != obj.getClass())) { + return false; + } + final Duration duration = (Duration) obj; + return (length == duration.length) && (timeUnit == duration.timeUnit); + } + + @Override + public int hashCode() { + return (31 * (int) (length ^ (length>>> 32))) + timeUnit.hashCode(); + } + + @Override + public String toString() { + String units = timeUnit.toString().toLowerCase(); + if (length == 1) + units = units.substring(0, units.length() - 1); + return Long.toString(length) + ' ' + units; + } +} diff --git a/src/main/java/org/javacore/time/TimeUtil.java b/src/main/java/org/javacore/time/TimeUtil.java new file mode 100644 index 0000000..34d0011 --- /dev/null +++ b/src/main/java/org/javacore/time/TimeUtil.java @@ -0,0 +1,118 @@ +package org.javacore.time; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * 基于 JDK 8 time包的时间工具类 + * + * Created by bysocket on 16/8/23. + */ +public final class TimeUtil { + + /** + * 获取默认时间格式: yyyy-MM-dd HH:mm:ss + */ + private static final DateTimeFormatter DEFAULT_DATETIME_FORMATTER = TimeFormat.LONG_DATE_PATTERN_LINE.formatter; + + private TimeUtil() { + // no construct function + } + + /** + * String 转时间 + * + * @param timeStr + * @return + */ + public static LocalDateTime parseTime(String timeStr) { + return LocalDateTime.parse(timeStr, DEFAULT_DATETIME_FORMATTER); + } + + /** + * String 转时间 + * + * @param timeStr + * @param format 时间格式 + * @return + */ + public static LocalDateTime parseTime(String timeStr, TimeFormat format) { + return LocalDateTime.parse(timeStr, format.formatter); + } + + /** + * 时间转 String + * + * @param time + * @return + */ + public static String parseTime(LocalDateTime time) { + return DEFAULT_DATETIME_FORMATTER.format(time); + } + + /** + * 时间转 String + * + * @param time + * @param format 时间格式 + * @return + */ + public static String parseTime(LocalDateTime time, TimeFormat format) { + return format.formatter.format(time); + } + + /** + * 获取当前时间 + * + * @return + */ + public static String getCurrentDatetime() { + return DEFAULT_DATETIME_FORMATTER.format(LocalDateTime.now()); + } + + /** + * 获取当前时间 + * + * @param format 时间格式 + * @return + */ + public static String getCurrentDatetime(TimeFormat format) { + return format.formatter.format(LocalDateTime.now()); + } + + /** + * 时间格式 + */ + public enum TimeFormat { + + /** + * 短时间格式 + */ + SHORT_DATE_PATTERN_LINE("yyyy-MM-dd"), + SHORT_DATE_PATTERN_SLASH("yyyy/MM/dd"), + SHORT_DATE_PATTERN_DOUBLE_SLASH("yyyy\\MM\\dd"), + SHORT_DATE_PATTERN_NONE("yyyyMMdd"), + + /** + * 长时间格式 + */ + LONG_DATE_PATTERN_LINE("yyyy-MM-dd HH:mm:ss"), + LONG_DATE_PATTERN_SLASH("yyyy/MM/dd HH:mm:ss"), + LONG_DATE_PATTERN_DOUBLE_SLASH("yyyy\\MM\\dd HH:mm:ss"), + LONG_DATE_PATTERN_NONE("yyyyMMdd HH:mm:ss"), + + /** + * 长时间格式 带毫秒 + */ + LONG_DATE_PATTERN_WITH_MILSEC_LINE("yyyy-MM-dd HH:mm:ss.SSS"), + LONG_DATE_PATTERN_WITH_MILSEC_SLASH("yyyy/MM/dd HH:mm:ss.SSS"), + LONG_DATE_PATTERN_WITH_MILSEC_DOUBLE_SLASH("yyyy\\MM\\dd HH:mm:ss.SSS"), + LONG_DATE_PATTERN_WITH_MILSEC_NONE("yyyyMMdd HH:mm:ss.SSS"); + + private transient DateTimeFormatter formatter; + + TimeFormat(String pattern) { + formatter = DateTimeFormatter.ofPattern(pattern); + } + } +} diff --git a/src/main/java/org/jee/rpc/EchoService.java b/src/main/java/org/jee/rpc/EchoService.java new file mode 100644 index 0000000..e329980 --- /dev/null +++ b/src/main/java/org/jee/rpc/EchoService.java @@ -0,0 +1,9 @@ +package org.jee.rpc; + +/** + * 描述:服务Echo接口类 + * Created by bysocket on 16/2/28. + */ +public interface EchoService { + String echo(String ping); +} diff --git a/src/main/java/org/jee/rpc/EchoServiceImpl.java b/src/main/java/org/jee/rpc/EchoServiceImpl.java new file mode 100644 index 0000000..0403ea9 --- /dev/null +++ b/src/main/java/org/jee/rpc/EchoServiceImpl.java @@ -0,0 +1,12 @@ +package org.jee.rpc; + +/** + * 描述:服务Echo实现类 + * Created by bysocket on 16/2/28. + */ +public class EchoServiceImpl implements EchoService { + @Override + public String echo(String ping) { + return ping != null ? ping + " --> I am ok." : "I am ok."; + } +} diff --git a/src/main/java/org/jee/rpc/RpcExporter.java b/src/main/java/org/jee/rpc/RpcExporter.java new file mode 100644 index 0000000..567e187 --- /dev/null +++ b/src/main/java/org/jee/rpc/RpcExporter.java @@ -0,0 +1,107 @@ +package org.jee.rpc; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Method; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +/** + * 描述:RPC服务发布者 + * Created by bysocket on 16/2/28. + */ +public class RpcExporter { + // 创建线程池 + static Executor executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); + + public static void exporter(String hostName,int port) throws IOException { + ServerSocket serverSocket = new ServerSocket(); + serverSocket.bind(new InetSocketAddress(hostName,port)); + try { + while (true) { + /** + * 监听Client的TCP连接,将其封装成Task,由线程池执行. + */ + executor.execute(new ExporterTask(serverSocket.accept())); + } + } finally { + serverSocket.close(); + } + } + + /** + * 线程Task: + * 1. 将客户端发送的二进制流反序列化成对象,反射调用服务实现者,获取执行结果 + * 2. 将执行结果对象反序列化,通过Socket发送给客户端 + * 3. 远程服务调用完成之后,释放Socket等连接资源,防止句柄泄漏 + */ + private static class ExporterTask implements Runnable { + Socket client = null; + public ExporterTask(Socket accept) { + this.client = accept; + } + + @Override + public void run() { + ObjectInputStream input = null; + ObjectOutputStream output = null; + try { + // 对象输入流 + input = new ObjectInputStream(client.getInputStream()); + + // 获取接口名 + String interfaceName = input.readUTF(); + // 获取方法名 + String methodName = input.readUTF(); + // 获取方法的参数数组 + Class>[] paramTypes = (Class>[]) input.readObject(); + // 获取传入参数对象数组 + Object[] arguments = (Object[]) input.readObject(); + + // 获取服务对象类 + Class> service = Class.forName(interfaceName); + // 获取服务方法 + Method method = service.getMethod(methodName,paramTypes); + // 获取服务方法返回对象 + Object result = method.invoke(service.newInstance(),arguments); + + // 对象输出流 + output = new ObjectOutputStream(client.getOutputStream()); + output.writeObject(result); + + } catch (Exception e) { + e.printStackTrace(); + } finally { + // 关闭流的操作 + if (output != null) { + try { + output.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + if (input != null) { + try { + input.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + if (client != null) { + try { + client.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + } +} diff --git a/src/main/java/org/jee/rpc/RpcImporter.java b/src/main/java/org/jee/rpc/RpcImporter.java new file mode 100644 index 0000000..c4359fc --- /dev/null +++ b/src/main/java/org/jee/rpc/RpcImporter.java @@ -0,0 +1,60 @@ +package org.jee.rpc; + +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.net.InetSocketAddress; +import java.net.Socket; + +/** + * 描述:Rpc本地服务代理类 + * 1. 将本地接口调用转化为JDK的动态调用,在动态调用中实现接口的远程调用 + * 2. 创建Socket客户端,根据制定地址连接远程服务提供者 + * 3. 将远程服务调用所需的接口类,方法名,参数列表等编码后发送给服务提供者 + * 4. 同步阻塞等待服务端返回应答,获取应答后返回 + * Created by bysocket on 16/2/29. + */ +public class RpcImporter