diff --git a/README.md b/README.md
index 126ae21..cbbe5f5 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,12 @@
-#JavaTutorial(Java教程)
+# JavaTutorial(Java教程)
在成长的过程中,会学到许多新的知识;在项目实践过程中,经常需要学习新的技术。但经过一段时间后,这些知识点和技术又忘得差不多了,等到要用的时候又要搜索很多的资料从头到尾学习一次,浪费很多的时间,没有沉淀和积累。
在这里,通过文章和代码,把这些知识点和技术的主要内容记录并汇总,供自己快速回顾,也分享给他人。
+注:部分例子基于JDK8。
+
## 关键字
-* [transient与序列化](src/cn/aofeng/demo/java/lang/TransientDemo.java)
+* [transient与序列化](src/cn/aofeng/demo/java/lang/serialization/TransientDemo.java)
## 数据结构
* [在控制台输出类似目录树的结构](src/cn/aofeng/demo/tree)
@@ -62,9 +64,12 @@
* [Java网络处理模型-阻塞I/O+线程池](http://aofengblog.com/2013/10/24/Java%E7%BD%91%E7%BB%9C%E5%A4%84%E7%90%86%E6%A8%A1%E5%9E%8B-%E9%98%BB%E5%A1%9EI-O-%E7%BA%BF%E7%A8%8B%E6%B1%A0/)
* [Reactor模式与非阻塞I/O | Reactor Pattern and NIO](http://aofengblog.com/2013/11/04/Reactor%E6%A8%A1%E5%BC%8F%E4%B8%8E%E9%9D%9E%E9%98%BB%E5%A1%9EI-O/)
+### RMI
+* [RMI服务端与客户端示例](src/cn/aofeng/demo/java/rmi)
+
### HTTP
* [使用Fluent API发起HTTP请求(Get和Post)](src/cn/aofeng/demo/httpclient/FluentApi.java)
-* [使用HttpClient发起HTTP请求(Get, Post和上传文件)](src/cn/aofeng/demo/httpclient/FluentApi.java)
+* [使用HttpClient发起HTTP请求(Get, Post和上传文件)](src/cn/aofeng/demo/httpclient/HttpClientBasic.java)
* [使用JDK中的API建立简单的HTTP Server](src/cn/aofeng/demo/httpclient/server/SimpleHttpServer.java)
### Netty 4.0.x
@@ -73,6 +78,7 @@
## 线程&并发
+* [守护线程](src/cn/aofeng/demo/thread/DaemonThreadDemo.java)
* [fork/join](src/cn/aofeng/demo/java/util/forkjoin/HelloForkJoin.java)
* [Future](src/cn/aofeng/demo/java/util/future/HelloFuture.java)
* [Future接口关系图](src/cn/aofeng/demo/java/util/future/Future.ucls)
@@ -88,6 +94,10 @@
* [获取/设置字段值](src/cn/aofeng/demo/java/lang/reflect/InvokeField.java)
* [静态代理&动态代理](src/cn/aofeng/demo/proxy/AccountServiceClient.java)
+## AOP
+* [AspectJ-编译时织入和加载类时织入](src/cn/aofeng/demo/aspectj)
+* [Instrumentation入门](src/cn/aofeng/demo/java/lang/instrument)
+
## 脚本语言
* [在Java中执行JavaScript脚本](src/cn/aofeng/demo/script/ScriptRunPerformence.java)
* [多个脚本引擎执行JavaScript的性能比较](src/cn/aofeng/demo/script/MultiScriptEngineCompare.java)
@@ -100,6 +110,10 @@
* [HMAC-SHA1签名算法](src/cn/aofeng/demo/encrypt/HmacSha1.java)
## 开源组件
+
+### Slf4j
+* [slf4j使用示例](src/cn/aofeng/demo/slf4j/HelloSlf4j.java)
+
### Redis
* [Redis客户端Jedis使用示例](src/cn/aofeng/demo/redis/JedisDemo.java)
diff --git a/conf/META-INF/aop.xml b/conf/META-INF/aop.xml
new file mode 100644
index 0000000..d6666a2
--- /dev/null
+++ b/conf/META-INF/aop.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lib/aspectjrt-1.8.10.jar b/lib/aspectjrt-1.8.10.jar
new file mode 100644
index 0000000..b5e8ce5
Binary files /dev/null and b/lib/aspectjrt-1.8.10.jar differ
diff --git a/lib/aspectjtools-1.8.10.jar b/lib/aspectjtools-1.8.10.jar
new file mode 100644
index 0000000..2e4a08d
Binary files /dev/null and b/lib/aspectjtools-1.8.10.jar differ
diff --git a/lib/aspectjweaver-1.8.10.jar b/lib/aspectjweaver-1.8.10.jar
new file mode 100755
index 0000000..4dbcaaf
Binary files /dev/null and b/lib/aspectjweaver-1.8.10.jar differ
diff --git a/src/cn/aofeng/demo/aspectj/BusinessService.java b/src/cn/aofeng/demo/aspectj/BusinessService.java
new file mode 100644
index 0000000..36f465c
--- /dev/null
+++ b/src/cn/aofeng/demo/aspectj/BusinessService.java
@@ -0,0 +1,142 @@
+package cn.aofeng.demo.aspectj;
+
+/**
+ * 模拟业务方法,将被Aspectj织入代码,增加功能。
+ *
+ * @author 聂勇
+ */
+public class BusinessService {
+
+ public long add(int a, int b) {
+ return a+b;
+ }
+
+ public long add(int a, int b, int... other) {
+ long result = a + b;
+ for (int i : other) {
+ result += i;
+ }
+
+ return result;
+ }
+
+ public String join(String first, String... appends) {
+ if (null == first) {
+ throw new IllegalArgumentException("first is null");
+ }
+ StringBuilder buffer = new StringBuilder();
+ buffer.append(first);
+ for (String str : appends) {
+ buffer.append(str);
+ }
+
+ return buffer.toString();
+ }
+
+ public String addPrefix(String src) {
+ if (null == src) {
+ throw new IllegalArgumentException("src is null");
+ }
+
+ return "-->"+src;
+ }
+
+ public static void printLine(char style) {
+ if ('=' == style) {
+ System.out.println("========================================================================================");
+ } else if ('-' == style) {
+ System.out.println("----------------------------------------------------------------------------------------");
+ } else {
+ System.out.println(" ");
+ }
+ }
+
+ public static void main(String[] args) {
+ final BusinessService bs = new BusinessService();
+
+ System.out.println("1、执行方法add(int, int)");
+ RunMethod rm = new RunMethod() {
+
+ @Override
+ public void run() {
+ long result = bs.add(1, 2);
+ System.out.println(">>> 结果:" + result);
+ }
+ };
+ rm.execute();
+
+ System.out.println("2、执行方法add(int, int, int...)");
+ rm = new RunMethod() {
+
+ @Override
+ public void run() {
+ long result = bs.add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+ System.out.println(">>> 结果:" + result);
+ }
+ };
+ rm.execute();
+
+ System.out.println("3、执行方法join(String, String...)");
+ rm = new RunMethod() {
+
+ @Override
+ public void run() {
+ String str = bs.join("first", "-second", "-third");
+ System.out.println(">>> 结果:" + str);
+ }
+ };
+ rm.execute();
+
+ System.out.println("4、执行方法join(String, String...)");
+ rm = new RunMethod() {
+
+ @Override
+ public void run() {
+ String str = bs.join(null, "-second", "-third");
+ System.out.println(">>> 结果:" + str);
+ }
+ };
+ rm.execute();
+
+ System.out.println("5、执行方法addPrefix(String)");
+ rm = new RunMethod() {
+
+ @Override
+ public void run() {
+ String str = bs.addPrefix("原字符串");
+ System.out.println(">>> 结果:" + str);
+ }
+ };
+ rm.execute();
+
+ System.out.println("6、执行方法addPrefix(String)");
+ rm = new RunMethod() {
+
+ @Override
+ public void run() {
+ String str = bs.addPrefix(null);
+ System.out.println(">>> 结果:" + str);
+ }
+ };
+ rm.execute();
+ }
+
+ public static abstract class RunMethod {
+
+ private char _style = '=';
+
+ public void execute() {
+ printLine(_style);
+ try {
+ run();
+ } catch (Exception e) {
+ e.printStackTrace(System.err);
+ }
+ printLine(_style);
+ printLine(' ');
+ }
+
+ public abstract void run();
+ }
+
+}
diff --git a/src/cn/aofeng/demo/aspectj/BusinessServiceInterceptor.java b/src/cn/aofeng/demo/aspectj/BusinessServiceInterceptor.java
new file mode 100644
index 0000000..847a2a4
--- /dev/null
+++ b/src/cn/aofeng/demo/aspectj/BusinessServiceInterceptor.java
@@ -0,0 +1,122 @@
+package cn.aofeng.demo.aspectj;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.After;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 拦截器。
+ *
+ * @author 聂勇
+ */
+@Aspect
+public class BusinessServiceInterceptor {
+
+ private static Logger _logger = LoggerFactory.getLogger(BusinessServiceInterceptor.class);
+
+ private char _style = '-';
+
+ /**
+ *
+ * Before通知不能修改方法传入的参数。
+ *
+ */
+ @Before("execution(public * cn.aofeng.demo.aspectj.BusinessService.add(..))")
+ public void beforeAdd(JoinPoint joinPoint) {
+ _logger.info( String.format("拦截到方法:%s, 传入参数:%s",
+ joinPoint.getSignature().getName(),
+ ArrayUtils.toString(joinPoint.getArgs()) ) );
+ BusinessService.printLine(_style);
+ }
+
+ /**
+ *
+ * After通知不能修改方法的返回值。
+ * 如果被拦截的方法抛出异常,拦截代码仍然正常执行。
+ *
+ */
+ @After("execution(public * cn.aofeng.demo.aspectj.BusinessService.join(..))")
+ public void beforeAddSupportMultiArgs(JoinPoint joinPoint) {
+ _logger.info("Signature.name:"+joinPoint.getSignature().getName());
+ _logger.info("Args:" + ArrayUtils.toString(joinPoint.getArgs()));
+ _logger.info("Target:" + ArrayUtils.toString(joinPoint.getTarget()));
+ _logger.info("This:" + ArrayUtils.toString(joinPoint.getThis()));
+ _logger.info("Kind:" + ArrayUtils.toString(joinPoint.getKind()));
+ _logger.info("SourceLocation:" + ArrayUtils.toString(joinPoint.getSourceLocation()));
+
+ // 试图修改传入的参数
+ joinPoint.getArgs()[0] = "100";
+
+ BusinessService.printLine(_style);
+ }
+
+ /**
+ *
+ * AfterReturning通知不能修改方法的返回值。
+ * 如果被拦截的方法抛出异常,拦截代码不再执行。
+ *
+ */
+ @AfterReturning(pointcut="execution(public * cn.aofeng.demo.aspectj.BusinessService.join(..))", returning="result")
+ public void afterReturnAdd(JoinPoint joinPoint, Object result) {
+ _logger.info( String.format("拦截到方法:%s, 传入参数:%s, 执行结果:%s",
+ joinPoint.getSignature().getName(),
+ ArrayUtils.toString(joinPoint.getArgs()),
+ result) );
+
+ // 试图修改返回值
+ result = "hello, changed";
+
+ BusinessService.printLine(_style);
+ }
+
+ /**
+ *
+ * 只在被拦截的方法抛出异常时才执行。
+ *
+ */
+ @AfterThrowing(pointcut="execution(public * cn.aofeng.demo.aspectj.BusinessService.join(..))", throwing="ex")
+ public void afterThrowingAdd(JoinPoint joinPoint, Exception ex) {
+ _logger.info( String.format("拦截到方法:%s, 传入参数:%s",
+ joinPoint.getSignature().getName(),
+ ArrayUtils.toString(joinPoint.getArgs()) ) );
+ if (null != ex) {
+ _logger.info("拦截到异常:", ex);
+ }
+
+ BusinessService.printLine(_style);
+ }
+
+ /**
+ *
+ * {@link ProceedingJoinPoint}只能在Around通知中使用。
+ * Around通知可以修改被拦截方法的传入参数和返回值。
+ *
+ */
+ @Around("execution(public * cn.aofeng.demo.aspectj.BusinessService.addPrefix(..))")
+ public Object afterAround(ProceedingJoinPoint joinPoint) throws Throwable {
+ _logger.info( String.format("拦截到方法:%s, 传入参数:%s",
+ joinPoint.getSignature().getName(),
+ ArrayUtils.toString(joinPoint.getArgs()) ) );
+
+ Object result = null;
+ try {
+ result = joinPoint.proceed();
+ _logger.info("执行结果:" + result);
+ } catch (Throwable e) {
+ throw e;
+ } finally {
+ BusinessService.printLine(_style);
+ }
+
+ return result;
+ }
+
+}
diff --git a/src/cn/aofeng/demo/aspectj/build.xml b/src/cn/aofeng/demo/aspectj/build.xml
new file mode 100644
index 0000000..b5375f9
--- /dev/null
+++ b/src/cn/aofeng/demo/aspectj/build.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/cn/aofeng/demo/java/lang/instrument/FirstInstrumentation.java b/src/cn/aofeng/demo/java/lang/instrument/FirstInstrumentation.java
new file mode 100644
index 0000000..d4319ca
--- /dev/null
+++ b/src/cn/aofeng/demo/java/lang/instrument/FirstInstrumentation.java
@@ -0,0 +1,25 @@
+package cn.aofeng.demo.java.lang.instrument;
+
+import java.lang.instrument.Instrumentation;
+
+import org.apache.commons.lang.StringUtils;
+
+import cn.aofeng.demo.util.LogUtil;
+
+/**
+ * Instrument入口类。
+ *
+ * @author 聂勇
+ */
+public class FirstInstrumentation {
+
+ public static void premain(String options, Instrumentation ins) {
+ if (StringUtils.isBlank(options)) {
+ LogUtil.log("instrument without options");
+ } else {
+ LogUtil.log("instrument with options:%s", options);
+ }
+
+ ins.addTransformer(new FirstTransformer());
+ }
+}
diff --git a/src/cn/aofeng/demo/java/lang/instrument/FirstTransformer.java b/src/cn/aofeng/demo/java/lang/instrument/FirstTransformer.java
new file mode 100644
index 0000000..48ce691
--- /dev/null
+++ b/src/cn/aofeng/demo/java/lang/instrument/FirstTransformer.java
@@ -0,0 +1,26 @@
+/**
+ *
+ */
+package cn.aofeng.demo.java.lang.instrument;
+
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.IllegalClassFormatException;
+import java.security.ProtectionDomain;
+
+import cn.aofeng.demo.util.LogUtil;
+
+/**
+ * 只输出问候语,不进行字节码修改的Class转换器。
+ *
+ * @author 聂勇
+ */
+public class FirstTransformer implements ClassFileTransformer {
+
+ @Override
+ public byte[] transform(ClassLoader loader, String className, Class> classBeingRedefined,
+ ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
+ LogUtil.log(">>> %s", className);
+ return null;
+ }
+
+}
diff --git a/src/cn/aofeng/demo/java/lang/instrument/Hello.java b/src/cn/aofeng/demo/java/lang/instrument/Hello.java
new file mode 100644
index 0000000..01fd76f
--- /dev/null
+++ b/src/cn/aofeng/demo/java/lang/instrument/Hello.java
@@ -0,0 +1,14 @@
+package cn.aofeng.demo.java.lang.instrument;
+
+/**
+ * Instrumentation启动类。 *
+ *
+ * @author 聂勇
+ */
+public class Hello {
+
+ public static void main(String[] args) {
+ // nothing
+ }
+
+}
diff --git a/src/cn/aofeng/demo/java/lang/instrument/README.md b/src/cn/aofeng/demo/java/lang/instrument/README.md
new file mode 100644
index 0000000..53fe4e5
--- /dev/null
+++ b/src/cn/aofeng/demo/java/lang/instrument/README.md
@@ -0,0 +1,40 @@
+# 一、Instrumentation入门
+
+* [FirstTransformer.java](FirstTransformer.java) 处理字节码,由类FirstInstrumentation执行
+* [FirstInstrumentation.java](FirstInstrumentation.java) instrumentation入口类,由javaagent载入执行
+* [build.xml](build.xml) Ant脚本,负责编译、打包和运行
+
+在当前目录下执行命令:
+```bash
+ant
+```
+
+输出信息如下:
+> [java] instrument with options:"Hello, Instrumentation"
+> [java] >>> java/lang/invoke/MethodHandleImpl
+> [java] >>> java/lang/invoke/MethodHandleImpl$1
+> [java] >>> java/lang/invoke/MethodHandleImpl$2
+> [java] >>> java/util/function/Function
+> [java] >>> java/lang/invoke/MethodHandleImpl$3
+> [java] >>> java/lang/invoke/MethodHandleImpl$4
+> [java] >>> java/lang/ClassValue
+> [java] >>> java/lang/ClassValue$Entry
+> [java] >>> java/lang/ClassValue$Identity
+> [java] >>> java/lang/ClassValue$Version
+> [java] >>> java/lang/invoke/MemberName$Factory
+> [java] >>> java/lang/invoke/MethodHandleStatics
+> [java] >>> java/lang/invoke/MethodHandleStatics$1
+> [java] >>> sun/misc/PostVMInitHook
+> [java] >>> sun/usagetracker/UsageTrackerClient
+> [java] >>> java/util/concurrent/atomic/AtomicBoolean
+> [java] >>> sun/usagetracker/UsageTrackerClient$1
+> [java] >>> sun/usagetracker/UsageTrackerClient$4
+> [java] >>> sun/usagetracker/UsageTrackerClient$3
+> [java] >>> java/io/FileOutputStream$1
+> [java] >>> sun/launcher/LauncherHelper
+> [java] >>> cn/aofeng/demo/java/lang/instrument/Hello
+> [java] >>> sun/launcher/LauncherHelper$FXHelper
+> [java] >>> java/lang/Class$MethodArray
+> [java] >>> java/lang/Void
+> [java] >>> java/lang/Shutdown
+> [java] >>> java/lang/Shutdown$Lock
diff --git a/src/cn/aofeng/demo/java/lang/instrument/build.xml b/src/cn/aofeng/demo/java/lang/instrument/build.xml
new file mode 100644
index 0000000..2abfbb1
--- /dev/null
+++ b/src/cn/aofeng/demo/java/lang/instrument/build.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/cn/aofeng/demo/java/rmi/Gender.java b/src/cn/aofeng/demo/java/rmi/Gender.java
new file mode 100644
index 0000000..2ba3e7b
--- /dev/null
+++ b/src/cn/aofeng/demo/java/rmi/Gender.java
@@ -0,0 +1,20 @@
+package cn.aofeng.demo.java.rmi;
+
+/**
+ * 性别。
+ *
+ * @author 聂勇
+ */
+public class Gender {
+
+ /**
+ * 男。
+ */
+ public final static char MALE = 'M';
+
+ /**
+ * 女。
+ */
+ public final static char FEMALE = 'F';
+
+}
diff --git a/src/cn/aofeng/demo/java/rmi/RmiClient.java b/src/cn/aofeng/demo/java/rmi/RmiClient.java
new file mode 100644
index 0000000..96f3c75
--- /dev/null
+++ b/src/cn/aofeng/demo/java/rmi/RmiClient.java
@@ -0,0 +1,60 @@
+package cn.aofeng.demo.java.rmi;
+
+import java.net.MalformedURLException;
+import java.rmi.Naming;
+import java.rmi.NotBoundException;
+import java.rmi.RemoteException;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ *
+ * @author 聂勇
+ */
+public class RmiClient {
+
+ private static Logger _logger = LoggerFactory.getLogger(RmiClient.class);
+
+ private static String assembleUrl(String hostUrl, String bindName) {
+ if (StringUtils.isBlank(hostUrl) || StringUtils.isBlank(bindName)) {
+ return null;
+ }
+
+ String host = hostUrl.endsWith("/") ? hostUrl.substring(0, hostUrl.length()-1) : hostUrl;
+ String name = bindName.startsWith("/") ? bindName.substring(1) : bindName;
+
+ return host + "/" + name;
+ }
+
+ /**
+ * @param args
+ *
+ * - [0]:待连接的RMI主机。如:rmi://192.168.56.102:9999
+ * - [1]:服务名称。如:UserService
+ *
+ */
+ public static void main(String[] args) throws MalformedURLException, RemoteException, NotBoundException {
+ String host = args[0];
+ String serviceName = args[1];
+ String url = assembleUrl(host, serviceName);
+ UserService userService = (UserService) Naming.lookup(url);
+
+ String userId = "10000";
+ User user = userService.findById(userId);
+ _logger.info("身份证号为{}的用户信息{}", userId, user);
+ userId = "10001";
+ user = userService.findById(userId);
+ _logger.info("身份证号为{}的用户信息{}", userId, user);
+
+ String userName = "小明";
+ user = userService.findByName(userName);
+ _logger.info("姓名为{}的用户信息{}", userName, user);
+ userName = "张三";
+ user = userService.findByName(userName);
+ _logger.info("姓名为{}的用户信息{}", userName, user);
+ }
+
+}
diff --git a/src/cn/aofeng/demo/java/rmi/RmiServer.java b/src/cn/aofeng/demo/java/rmi/RmiServer.java
new file mode 100644
index 0000000..24f9e9f
--- /dev/null
+++ b/src/cn/aofeng/demo/java/rmi/RmiServer.java
@@ -0,0 +1,53 @@
+package cn.aofeng.demo.java.rmi;
+
+import java.rmi.AlreadyBoundException;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * RMI服务端。
+ *
+ * @author 聂勇
+ */
+public class RmiServer {
+
+ private static Logger _logger = LoggerFactory.getLogger(RmiServer.class);
+
+ public static Registry createRegistry(int port) {
+ Registry registry = null;
+ try {
+ registry = LocateRegistry.createRegistry(port);
+ } catch (RemoteException e) {
+ _logger.info( String.format("注册端口%s失败", port), e);
+ }
+
+ return registry;
+ }
+
+ /**
+ * @param args [0]:绑定端口
+ * @throws RemoteException
+ */
+ public static void main(String[] args) throws RemoteException {
+ int port = Integer.parseInt(args[0]);
+ UserService userService = new UserServiceImpl();
+ Registry registry = createRegistry(port);
+ if (null == registry) {
+ System.exit(0);
+ }
+
+ String bindName = "UserService";
+ try {
+ registry.bind(bindName, userService);
+ } catch (AlreadyBoundException e) {
+ _logger.info("服务{}已经绑定过", bindName);
+ }
+
+ _logger.info("RMI Server started, listen port:{}", port);
+ }
+
+}
diff --git a/src/cn/aofeng/demo/java/rmi/User.java b/src/cn/aofeng/demo/java/rmi/User.java
new file mode 100644
index 0000000..3f54cfa
--- /dev/null
+++ b/src/cn/aofeng/demo/java/rmi/User.java
@@ -0,0 +1,170 @@
+package cn.aofeng.demo.java.rmi;
+
+import java.io.Serializable;
+
+/**
+ * 用户信息。
+ *
+ * @author 聂勇
+ */
+public class User implements Serializable {
+
+ private static final long serialVersionUID = 7616705579045104892L;
+
+ /**
+ * 身份证号。
+ */
+ private String id;
+
+ /**
+ * 姓名。
+ */
+ private String name;
+
+ /**
+ * 性别:M-男;F-女。
+ */
+ private char gender;
+
+ /**
+ * 出生日期。以毫秒存储。
+ */
+ private long birthday;
+
+ /**
+ * 国家。
+ */
+ private String country;
+
+ /**
+ * 省/州。
+ */
+ private String province;
+
+ /**
+ * 市/区。
+ */
+ private String city;
+
+ /**
+ * 街道详细地址。
+ */
+ private String address;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public char getGender() {
+ return gender;
+ }
+
+ public void setGender(char gender) {
+ this.gender = gender;
+ }
+
+ public long getBirthday() {
+ return birthday;
+ }
+
+ public void setBirthday(long birthday) {
+ this.birthday = birthday;
+ }
+
+ public String getCountry() {
+ return country;
+ }
+
+ public void setCountry(String country) {
+ this.country = country;
+ }
+
+ public String getProvince() {
+ return province;
+ }
+
+ public void setProvince(String province) {
+ this.province = province;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((country == null) ? 0 : country.hashCode());
+ result = prime * result + ((id == null) ? 0 : id.hashCode());
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ User other = (User) obj;
+ if (country == null) {
+ if (other.country != null)
+ return false;
+ } else if (!country.equals(other.country))
+ return false;
+ if (id == null) {
+ if (other.id != null)
+ return false;
+ } else if (!id.equals(other.id))
+ return false;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buffer = new StringBuilder(256)
+ .append("User [id=").append(id)
+ .append(", name=").append(name)
+ .append(", gender=").append(gender)
+ .append(", birthday=").append(birthday)
+ .append(", country=").append(country)
+ .append(", province=").append(province)
+ .append(", city=").append(city)
+ .append(", address=").append(address)
+ .append("]");
+ return buffer.toString();
+ }
+
+}
diff --git a/src/cn/aofeng/demo/java/rmi/UserService.java b/src/cn/aofeng/demo/java/rmi/UserService.java
new file mode 100644
index 0000000..2469743
--- /dev/null
+++ b/src/cn/aofeng/demo/java/rmi/UserService.java
@@ -0,0 +1,19 @@
+package cn.aofeng.demo.java.rmi;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * 用户信息服务。
+ *
+ * @author 聂勇
+ */
+public interface UserService extends Remote {
+
+ public User findByName(String name) throws RemoteException;
+
+ public User findById(String id) throws RemoteException;
+
+ public boolean add(User user) throws RemoteException;
+
+}
diff --git a/src/cn/aofeng/demo/java/rmi/UserServiceImpl.java b/src/cn/aofeng/demo/java/rmi/UserServiceImpl.java
new file mode 100644
index 0000000..60e44b8
--- /dev/null
+++ b/src/cn/aofeng/demo/java/rmi/UserServiceImpl.java
@@ -0,0 +1,70 @@
+package cn.aofeng.demo.java.rmi;
+
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * 用户信息服务。
+ *
+ * @author 聂勇
+ */
+public class UserServiceImpl extends UnicastRemoteObject implements UserService {
+
+ public UserServiceImpl() throws RemoteException {
+ super();
+ }
+
+ private static final long serialVersionUID = -9134952963637302483L;
+
+ @Override
+ public User findByName(String name) throws RemoteException {
+ if (StringUtils.isBlank(name)) {
+ return null;
+ }
+
+ if ("小明".equals(name)) {
+ return createUser("10000", "小明", Gender.MALE);
+ }
+
+ return null;
+ }
+
+ @Override
+ public User findById(String id) throws RemoteException {
+ if (StringUtils.isBlank(id)) {
+ return null;
+ }
+
+ if ("10000".equals(id)) {
+ return createUser("10000", "小丽", Gender.FEMALE);
+ }
+
+ return null;
+ }
+
+ @Override
+ public boolean add(User user) throws RemoteException {
+ if (null == user || StringUtils.isBlank(user.getId()) || StringUtils.isBlank(user.getName())) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private User createUser(String id, String name, char gender) {
+ User user = new User();
+ user.setId(id);
+ user.setName(name);
+ user.setGender(gender);
+ user.setBirthday(System.currentTimeMillis());
+ user.setCountry("中国");
+ user.setProvince("广东");
+ user.setCity("广州");
+ user.setAddress("xxx区xxx街道xxx号");
+
+ return user;
+ }
+
+}
diff --git a/src/cn/aofeng/demo/mybatis/README.md b/src/cn/aofeng/demo/mybatis/README.md
new file mode 100644
index 0000000..e214deb
--- /dev/null
+++ b/src/cn/aofeng/demo/mybatis/README.md
@@ -0,0 +1,5 @@
+* [MyBatisClien.java](MyBatisClient.java) 入口类。读取配置文件,生成SqlSessionFactory,使用DAO操作表。
+* [mybatis-config.xml](../../../../../conf/mybatis-config.xml) mybatis配置文件
+* [MonitNotifyHistoryDao](dao/MonitNotifyHistoryDao.java) DAO类
+* [MonitNotifyHisto.java](entity/MonitNotifyHistory.java) 实体类
+* [MonitNotifyHistoryMapper.xml](mapper/MonitNotifyHistoryMapper.xml) SQL模板映射配置文件
diff --git a/src/cn/aofeng/demo/slf4j/HelloSlf4j.java b/src/cn/aofeng/demo/slf4j/HelloSlf4j.java
new file mode 100644
index 0000000..dce7ffd
--- /dev/null
+++ b/src/cn/aofeng/demo/slf4j/HelloSlf4j.java
@@ -0,0 +1,31 @@
+package cn.aofeng.demo.slf4j;
+
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * slf4j使用示例。
+ *
+ * @author 聂勇
+ */
+public class HelloSlf4j {
+
+ private static Logger _logger = LoggerFactory.getLogger(HelloSlf4j.class);
+
+ public static void main(String[] args) {
+ // 直接输出字符串
+ _logger.info("Hello, slf4j logger.");
+
+ // 输出格式字符串(携带多个填充参数)
+ _logger.info("{} + {} = {}", 1, 2, (1+2));
+
+ // 输出错误信息和异常堆栈
+ _logger.error("错误信息", new IOException("测试抛出IO异常信息"));
+
+ // 输出错误信息(携带多个填充参数)和异常堆栈
+ _logger.error("两个参数。agrs1:{};agrs2:{}的info级别日志", "args1", "args2", new IOException("测试抛出IO异常信息"));
+ }
+
+}
diff --git a/src/cn/aofeng/demo/thread/DaemonThreadDemo.java b/src/cn/aofeng/demo/thread/DaemonThreadDemo.java
new file mode 100644
index 0000000..541d133
--- /dev/null
+++ b/src/cn/aofeng/demo/thread/DaemonThreadDemo.java
@@ -0,0 +1,45 @@
+/**
+ * 公司:阿里游戏
+ * 创建时间:2018年11月2日下午5:56:43
+ */
+package cn.aofeng.demo.thread;
+
+import java.util.Date;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 守护线程DEMO。
+ *
+ * @author 聂勇
+ */
+public class DaemonThreadDemo extends Thread {
+
+ private static Logger logger = LoggerFactory.getLogger(DaemonThreadDemo.class);
+
+ @Override
+ public void run() {
+ while (true) {
+ System.out.println("守护线程运行, 时间:" + new Date());
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ logger.error("守护线程运行出错", e);
+ }
+ }
+ }
+
+ public static void main(String[] args) {
+ DaemonThreadDemo thread = new DaemonThreadDemo();
+ thread.setDaemon(true);
+ thread.start();
+
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException e) {
+ logger.error("主线程运行出错", e);
+ }
+ }
+
+}
diff --git a/src/cn/aofeng/demo/util/LogUtil.java b/src/cn/aofeng/demo/util/LogUtil.java
index 6046793..44558c9 100644
--- a/src/cn/aofeng/demo/util/LogUtil.java
+++ b/src/cn/aofeng/demo/util/LogUtil.java
@@ -7,8 +7,12 @@
*/
public class LogUtil {
+ public static void log(String msg) {
+ System.out.println(msg);
+ }
+
public static void log(String msg, Object... param) {
- System.out.println( String.format(msg, param) );
+ log( String.format(msg, param) );
}
}