diff --git a/README.md b/README.md
index 9460318..cbbe5f5 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,13 @@
-#JavaTutorial(Java教程)
+# JavaTutorial(Java教程)
在成长的过程中,会学到许多新的知识;在项目实践过程中,经常需要学习新的技术。但经过一段时间后,这些知识点和技术又忘得差不多了,等到要用的时候又要搜索很多的资料从头到尾学习一次,浪费很多的时间,没有沉淀和积累。
在这里,通过文章和代码,把这些知识点和技术的主要内容记录并汇总,供自己快速回顾,也分享给他人。
+注:部分例子基于JDK8。
+
+## 关键字
+* [transient与序列化](src/cn/aofeng/demo/java/lang/serialization/TransientDemo.java)
+
## 数据结构
* [在控制台输出类似目录树的结构](src/cn/aofeng/demo/tree)
@@ -13,6 +18,7 @@
## 数据库
* [Apache DbUtils - JDBC Utility Component](src/cn/aofeng/demo/dbutils)
* [JDBC元数据使用示例](src/cn/aofeng/demo/jdbc/MetaDataExample.java)
+* [MyBatis3使用示例](src/cn/aofeng/demo/mybatis)
## XML
* [XPath](src/cn/aofeng/demo/xml/XPathDemo.java)
@@ -45,7 +51,7 @@
* [使用Mockito作单元测试](src/cn/aofeng/demo/mockito)
-## 网络与I/O
+## 网络&I/O
* [多线程网络echo服务](src/cn/aofeng/demo/io/MultiThreadEchoServer.java)
* [线程池网络echo服务](src/cn/aofeng/demo/io/ThreadPoolEchoServer.java)
* [NIO 缓冲区](src/cn/aofeng/demo/nio/BufferIO.java)
@@ -58,12 +64,21 @@
* [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/HttpClientBasic.java)
+* [使用JDK中的API建立简单的HTTP Server](src/cn/aofeng/demo/httpclient/server/SimpleHttpServer.java)
+
### Netty 4.0.x
* [EchoServer](src/cn/aofeng/demo/netty40x/echo/EchoServer.java)
* [EchoClient](src/cn/aofeng/demo/netty40x/echo/EchoClient.java)
-## 线程与并发
+## 线程&并发
+* [守护线程](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)
@@ -72,11 +87,16 @@
* [事件驱动的异步化框架:event4j](http://aofengblog.blog.163.com/blog/static/63170212014102463624267/)
* [JDK HashMap源码分析 | HashMap Source Code Analysis](http://aofengblog.com/2014/08/14/JDK-HashMap%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/)
-##反射
+## 反射&代理
* [获取构造方法、普通方法、字段和注解](src/cn/aofeng/demo/java/lang/reflect/ClassAnalyze.java)
* [使用构造方法创建对象实例](src/cn/aofeng/demo/java/lang/reflect/CreateInstance.java)
* [调用方法](src/cn/aofeng/demo/java/lang/reflect/InvokeMethod.java)
* [获取/设置字段值](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)
@@ -90,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)
@@ -100,7 +124,7 @@
* [Spring IBatis Struts2 集成之二:Spring与Struts2集成 | Spring IBatis Struts2 Integration II: Spring Integrates with Struts2](http://aofengblog.com/2011/03/22/Spring-IBatis-Struts2-%E9%9B%86%E6%88%90%E4%B9%8B%E4%BA%8C%EF%BC%9ASpring%E4%B8%8EStruts2%E9%9B%86%E6%88%90/)
### Tomcat
-* [JMX管理Tomcat/Resin](http://aofengblog.blog.163.com/blog/static/6317021200871711013857/)
+* [JMX管理Tomcat/Resin](http://aofengblog.com/2008/08/17/Tomcat-JMX%E7%AE%A1%E7%90%86Tomcat-Resin/)
### JBoss
* [JBoss5.1.0 GA - 部署项目类库兼容和类库冲突问题解决方法](http://aofengblog.blog.163.com/blog/static/631702120113674626533/)
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/conf/gneratorConfig.xml b/conf/gneratorConfig.xml
new file mode 100644
index 0000000..51d6f85
--- /dev/null
+++ b/conf/gneratorConfig.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/log4j.properties b/conf/log4j.properties
index 70af5a7..075b90d 100644
--- a/conf/log4j.properties
+++ b/conf/log4j.properties
@@ -1,12 +1,18 @@
log4j.rootLogger=INFO, console
+# 应用本身
log4j.logger.cn.aofeng.demo=DEBUG, console
log4j.additivity.cn.aofeng.demo=false
-log4j.logger.org.jboss.netty.handler.logging=DEBUG, console
+
+# Netty
+log4j.logger.org.jboss.netty.handler.logging=INFO, console
log4j.additivity.org.jboss.netty.handler.logging=false
-# 控制台Console
-log4j.additivity.console=false
+# MyBatis
+log4j.logger.org.apache.ibatis=INFO, console
+log4j.additivity.org.apache.ibatis=false
+
+# 控制台输出
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
-log4j.appender.console.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] %p ~ %m%n
+log4j.appender.console.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] %p %m%n
diff --git a/conf/mybatis-config.xml b/conf/mybatis-config.xml
new file mode 100644
index 0000000..e3cab5d
--- /dev/null
+++ b/conf/mybatis-config.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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/lib/mybatis-3.4.4.jar b/lib/mybatis-3.4.4.jar
new file mode 100644
index 0000000..16c6d9e
Binary files /dev/null and b/lib/mybatis-3.4.4.jar differ
diff --git a/lib/mysql-connector-java-5.1.22-bin.jar b/lib/mysql-connector-java-5.1.22-bin.jar
deleted file mode 100644
index a50424d..0000000
Binary files a/lib/mysql-connector-java-5.1.22-bin.jar and /dev/null differ
diff --git a/lib/mysql-connector-java-5.1.40-bin.jar b/lib/mysql-connector-java-5.1.40-bin.jar
new file mode 100644
index 0000000..60bef5c
Binary files /dev/null and b/lib/mysql-connector-java-5.1.40-bin.jar differ
diff --git a/lib/slf4j-api-1.7.21.jar b/lib/slf4j-api-1.7.21.jar
new file mode 100644
index 0000000..7811fa0
Binary files /dev/null and b/lib/slf4j-api-1.7.21.jar differ
diff --git a/lib/slf4j-log4j12-1.7.21.jar b/lib/slf4j-log4j12-1.7.21.jar
new file mode 100644
index 0000000..d07a6dc
Binary files /dev/null and b/lib/slf4j-log4j12-1.7.21.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/lang/serialization/Man.java b/src/cn/aofeng/demo/java/lang/serialization/Man.java
new file mode 100644
index 0000000..840867b
--- /dev/null
+++ b/src/cn/aofeng/demo/java/lang/serialization/Man.java
@@ -0,0 +1,74 @@
+package cn.aofeng.demo.java.lang.serialization;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+/**
+ * 自定义序列化和反序列化。
+ *
+ * @author 聂勇
+ */
+public class Man implements Externalizable {
+
+ private String manName;
+
+ private int manAge;
+
+ private transient String password;
+
+ public Man() {
+ // nothing
+ }
+
+ public Man(String name, int age) {
+ this.manName = name;
+ this.manAge = age;
+ }
+
+ public Man(String name, int age, String password) {
+ this.manName = name;
+ this.manAge = age;
+ this.password = password;
+ }
+
+ public String getManName() {
+ return manName;
+ }
+
+ public void setManName(String manName) {
+ this.manName = manName;
+ }
+
+ public int getManAge() {
+ return manAge;
+ }
+
+ public void setManAge(int manAge) {
+ this.manAge = manAge;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ @Override
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeObject(manName);
+ out.writeInt(manAge);
+ out.writeObject(password);
+ }
+
+ @Override
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+ manName = (String) in.readObject();
+ manAge = in.readInt();
+ password = (String) in.readObject();
+ }
+
+}
diff --git a/src/cn/aofeng/demo/java/lang/serialization/People.java b/src/cn/aofeng/demo/java/lang/serialization/People.java
new file mode 100644
index 0000000..70fbb13
--- /dev/null
+++ b/src/cn/aofeng/demo/java/lang/serialization/People.java
@@ -0,0 +1,79 @@
+package cn.aofeng.demo.java.lang.serialization;
+
+import java.io.Serializable;
+
+/**
+ * 默认序列化和
+ *
+ * @author 聂勇
+ */
+public class People implements Serializable {
+
+ private static final long serialVersionUID = 6235620243018494633L;
+
+ private String name;
+
+ private int age;
+
+ private transient String address;
+
+ private static String sTestNormal;
+
+ private static transient String sTestTransient;
+
+ public People(String name) {
+ this.name = name;
+ }
+
+ public People(String name, int age) {
+ this.name = name;
+ this.age = age;
+ }
+
+ public People(String name, int age, String address) {
+ this.name = name;
+ this.age = age;
+ this.address = address;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public String getsTestNormal() {
+ return sTestNormal;
+ }
+
+ public void setsTestNormal(String sTestNormal) {
+ People.sTestNormal = sTestNormal;
+ }
+
+ public String getsTestTransient() {
+ return sTestTransient;
+ }
+
+ public void setsTestTransient(String sTestTransient) {
+ People.sTestTransient = sTestTransient;
+ }
+
+}
diff --git a/src/cn/aofeng/demo/java/lang/serialization/TransientDemo.java b/src/cn/aofeng/demo/java/lang/serialization/TransientDemo.java
new file mode 100644
index 0000000..c6f82f5
--- /dev/null
+++ b/src/cn/aofeng/demo/java/lang/serialization/TransientDemo.java
@@ -0,0 +1,126 @@
+package cn.aofeng.demo.java.lang.serialization;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 关键字 transient 测试。
+ *
+ * @author 聂勇
+ */
+public class TransientDemo {
+
+ private static Logger _logger = LoggerFactory.getLogger(TransientDemo.class);
+
+ private String _tempFileName = "TransientDemo";
+
+ /**
+ * 将对象序列化并保存到文件。
+ *
+ * @param obj 待序列化的对象
+ */
+ public void save(Object obj) {
+ ObjectOutputStream outs = null;
+ try {
+ outs = new ObjectOutputStream(
+ new FileOutputStream( getTempFile(_tempFileName) ));
+ outs.writeObject(obj);
+ } catch (IOException e) {
+ _logger.error("save object to file occurs error", e);
+ } finally {
+ IOUtils.closeQuietly(outs);
+ }
+ }
+
+ /**
+ * 从文件读取内容并反序列化成对象。
+ *
+ * @return {@link People}对象。如果读取文件出错 或 对象类型转换失败,返回null。
+ */
+ public T load() {
+ ObjectInputStream ins = null;
+ try {
+ ins = new ObjectInputStream(
+ new FileInputStream( getTempFile(_tempFileName)) );
+ return ((T) ins.readObject());
+ } catch (IOException e) {
+ _logger.error("load object from file occurs error", e);
+ } catch (ClassNotFoundException e) {
+ _logger.error("load object from file occurs error", e);
+ } finally {
+ IOUtils.closeQuietly(ins);
+ }
+
+ return null;
+ }
+
+ private File getTempFile(String filename) {
+ return new File(getTempDir(), filename);
+ }
+
+ private String getTempDir() {
+ return System.getProperty("java.io.tmpdir");
+ }
+
+ private void displayPeople(People people) {
+ if (null == people) {
+ return;
+ }
+ String template = "People[name:%s, age:%d, address:%s, sTestNormal:%s, sTestTransient:%s]";
+ System.out.println( String.format(template, people.getName(), people.getAge(),
+ people.getAddress(), people.getsTestNormal(), people.getsTestTransient()));
+ }
+
+ private void displayMan(Man man) {
+ if (null == man) {
+ return;
+ }
+ String template = "Man[manName:%s, manAge:%d, password:%s]";
+ System.out.println( String.format(template, man.getManName(), man.getManAge(), man.getPassword()) );
+ }
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) {
+ System.out.println(">>> Serializable测试");
+ TransientDemo demo = new TransientDemo();
+
+ People people = new People("张三", 30, "中国广州");
+ people.setsTestNormal("normal-first");
+ people.setsTestTransient("transient-first");
+ System.out.println("序列化之前的对象信息:");
+ demo.displayPeople(people);
+ demo.save(people);
+
+ // 修改静态变量的值
+ people.setsTestNormal("normal-second");
+ people.setsTestTransient("transient-second");
+
+ People fromLoad = demo.load();
+ System.out.println("反序列化之后的对象信息:");
+ demo.displayPeople(fromLoad);
+
+
+
+ System.out.println("");
+ System.out.println(">>> Externalizable测试");
+ Man man = new Man("李四", 10, "假密码");
+ System.out.println("序列化之前的对象信息:");
+ demo.displayMan(man);
+ demo.save(man);
+
+ Man manFromLoadMan = demo.load();
+ System.out.println("反序列化之后的对象信息:");
+ demo.displayMan(manFromLoadMan);
+ }
+
+}
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/MyBatisClient.java b/src/cn/aofeng/demo/mybatis/MyBatisClient.java
new file mode 100644
index 0000000..6b6f3f1
--- /dev/null
+++ b/src/cn/aofeng/demo/mybatis/MyBatisClient.java
@@ -0,0 +1,62 @@
+package cn.aofeng.demo.mybatis;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.ibatis.io.Resources;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.apache.ibatis.session.SqlSessionFactoryBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import cn.aofeng.demo.mybatis.dao.MonitNotifyHistoryDao;
+import cn.aofeng.demo.mybatis.entity.MonitNotifyHistory;
+
+/**
+ *
+ *
+ * @author 聂勇
+ */
+public class MyBatisClient {
+
+ private static Logger _logger = LoggerFactory.getLogger(MyBatisClient.class);
+
+ public static void main(String[] args) throws IOException {
+ String resource = "mybatis-config.xml";
+ InputStream ins = Resources.getResourceAsStream(resource);
+ SqlSessionFactory ssFactory = new SqlSessionFactoryBuilder().build(ins);
+ MonitNotifyHistoryDao dao = new MonitNotifyHistoryDao(ssFactory);
+
+ // 插入一条记录
+ long recordId = 999;
+ MonitNotifyHistory record = new MonitNotifyHistory();
+ record.setRecordId(recordId);
+ record.setMonitId(9999);
+ record.setAppId(99);
+ record.setNotifyTarget(1);
+ record.setNotifyType(1);
+ record.setNotifyContent("通知内容测试");
+ record.setStatus(0);
+ record.setCreateTime(1492061400000L);
+ int count = dao.insert(record);
+ _logger.info("insert complete, effects {} rows", count);
+
+ // 查询记录
+ MonitNotifyHistory entity = dao.selectByPrimaryKey(recordId);
+ _logger.info("query record id {}, result: {}", recordId, entity);
+
+ // 更新一个字段再执行查询
+ entity.setRetryTimes(99);
+ count = dao.updateByPrimaryKeySelective(entity);
+ _logger.info("update complete, record id:{}, effects {} rows", recordId, count);
+ entity = dao.selectByPrimaryKey(recordId);
+ _logger.info("query record id {}, result: {}", recordId, entity);
+
+ // 删除记录后再执行查询
+ count = dao.deleteByPrimaryKey(recordId);
+ _logger.info("delete complete, record id {}, effects {} rows", recordId, count);
+ entity = dao.selectByPrimaryKey(recordId);
+ _logger.info("query record id {}, result: {}", recordId, entity);
+ }
+
+}
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/mybatis/dao/MonitNotifyHistoryDao.java b/src/cn/aofeng/demo/mybatis/dao/MonitNotifyHistoryDao.java
new file mode 100644
index 0000000..d549e87
--- /dev/null
+++ b/src/cn/aofeng/demo/mybatis/dao/MonitNotifyHistoryDao.java
@@ -0,0 +1,79 @@
+package cn.aofeng.demo.mybatis.dao;
+
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+
+import cn.aofeng.demo.mybatis.entity.MonitNotifyHistory;
+
+/**
+ * 监控通知历史CURD。
+ *
+ * @author 聂勇
+ */
+public class MonitNotifyHistoryDao {
+
+ private SqlSessionFactory _ssFactory = null;
+
+ public MonitNotifyHistoryDao(SqlSessionFactory factory) {
+ this._ssFactory = factory;
+ }
+
+ private String assembleStatement(String id) {
+ return "cn.aofeng.demo.mybatis.dao.MonitNotifyHistoryMapper."+id;
+ }
+
+ private void close(SqlSession session) {
+ if (null != session) {
+ session.close();
+ }
+ }
+
+ public int deleteByPrimaryKey(Long recordId) {
+ SqlSession session = _ssFactory.openSession(true);
+ int result = 0;
+ try {
+ session.delete(assembleStatement("deleteByPrimaryKey"), recordId);
+ } finally {
+ close(session);
+ }
+
+ return result;
+ }
+
+ public int insert(MonitNotifyHistory record) {
+ SqlSession session = _ssFactory.openSession(true);
+ int result = 0;
+ try {
+ result = session.insert(assembleStatement("insertSelective"), record);
+ } finally {
+ close(session);
+ }
+
+ return result;
+ }
+
+ public MonitNotifyHistory selectByPrimaryKey(Long recordId) {
+ SqlSession session = _ssFactory.openSession();
+ MonitNotifyHistory result = null;
+ try {
+ result = session.selectOne(assembleStatement("selectByPrimaryKey"), recordId);
+ } finally {
+ close(session);
+ }
+
+ return result;
+ }
+
+ public int updateByPrimaryKeySelective(MonitNotifyHistory record) {
+ SqlSession session = _ssFactory.openSession(true);
+ int result = 0;
+ try {
+ session.update(assembleStatement("updateByPrimaryKeySelective"), record);
+ } finally {
+ close(session);
+ }
+
+ return result;
+ }
+
+}
\ No newline at end of file
diff --git a/src/cn/aofeng/demo/mybatis/entity/MonitNotifyHistory.java b/src/cn/aofeng/demo/mybatis/entity/MonitNotifyHistory.java
new file mode 100644
index 0000000..2bae4f5
--- /dev/null
+++ b/src/cn/aofeng/demo/mybatis/entity/MonitNotifyHistory.java
@@ -0,0 +1,105 @@
+package cn.aofeng.demo.mybatis.entity;
+
+/**
+ * 监控通知历史实体类。
+ *
+ * @author 聂勇
+ */
+public class MonitNotifyHistory {
+ private Long recordId;
+
+ private Integer monitId;
+
+ private Integer appId;
+
+ private Integer notifyType;
+
+ private Integer notifyTarget;
+
+ private String notifyContent;
+
+ private Integer status;
+
+ private Integer retryTimes;
+
+ private Long createTime;
+
+ public Long getRecordId() {
+ return recordId;
+ }
+
+ public void setRecordId(Long recordId) {
+ this.recordId = recordId;
+ }
+
+ public Integer getMonitId() {
+ return monitId;
+ }
+
+ public void setMonitId(Integer monitId) {
+ this.monitId = monitId;
+ }
+
+ public Integer getAppId() {
+ return appId;
+ }
+
+ public void setAppId(Integer appId) {
+ this.appId = appId;
+ }
+
+ public Integer getNotifyType() {
+ return notifyType;
+ }
+
+ public void setNotifyType(Integer notifyType) {
+ this.notifyType = notifyType;
+ }
+
+ public Integer getNotifyTarget() {
+ return notifyTarget;
+ }
+
+ public void setNotifyTarget(Integer notifyTarget) {
+ this.notifyTarget = notifyTarget;
+ }
+
+ public String getNotifyContent() {
+ return notifyContent;
+ }
+
+ public void setNotifyContent(String notifyContent) {
+ this.notifyContent = notifyContent;
+ }
+
+ public Integer getStatus() {
+ return status;
+ }
+
+ public void setStatus(Integer status) {
+ this.status = status;
+ }
+
+ public Integer getRetryTimes() {
+ return retryTimes;
+ }
+
+ public void setRetryTimes(Integer retryTimes) {
+ this.retryTimes = retryTimes;
+ }
+
+ public Long getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(Long createTime) {
+ this.createTime = createTime;
+ }
+
+ @Override
+ public String toString() {
+ return "MonitNotifyHistory [recordId=" + recordId + ", monitId=" + monitId + ", appId=" + appId + ", notifyType=" + notifyType + ", notifyTarget="
+ + notifyTarget + ", notifyContent=" + notifyContent + ", status=" + status + ", retryTimes=" + retryTimes + ", createTime=" + createTime + "]";
+ }
+
+}
\ No newline at end of file
diff --git a/src/cn/aofeng/demo/mybatis/mapper/MonitNotifyHistoryMapper.xml b/src/cn/aofeng/demo/mybatis/mapper/MonitNotifyHistoryMapper.xml
new file mode 100644
index 0000000..e6ac688
--- /dev/null
+++ b/src/cn/aofeng/demo/mybatis/mapper/MonitNotifyHistoryMapper.xml
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ delete from monit_notify_history
+ where record_id = #{recordId,jdbcType=BIGINT}
+
+
+ insert into monit_notify_history (record_id, monit_id, app_id,
+ notify_type, notify_target, notify_content,
+ status, retry_times, create_time
+ )
+ values (#{recordId,jdbcType=BIGINT}, #{monitId,jdbcType=INTEGER}, #{appId,jdbcType=TINYINT},
+ #{notifyType,jdbcType=TINYINT}, #{notifyTarget,jdbcType=INTEGER}, #{notifyContent,jdbcType=VARCHAR},
+ #{status,jdbcType=TINYINT}, #{retryTimes,jdbcType=TINYINT}, #{createTime,jdbcType=BIGINT}
+ )
+
+
+ insert into monit_notify_history
+
+
+ record_id,
+
+
+ monit_id,
+
+
+ app_id,
+
+
+ notify_type,
+
+
+ notify_target,
+
+
+ notify_content,
+
+
+ status,
+
+
+ retry_times,
+
+
+ create_time,
+
+
+
+
+ #{recordId,jdbcType=BIGINT},
+
+
+ #{monitId,jdbcType=INTEGER},
+
+
+ #{appId,jdbcType=TINYINT},
+
+
+ #{notifyType,jdbcType=TINYINT},
+
+
+ #{notifyTarget,jdbcType=INTEGER},
+
+
+ #{notifyContent,jdbcType=VARCHAR},
+
+
+ #{status,jdbcType=TINYINT},
+
+
+ #{retryTimes,jdbcType=TINYINT},
+
+
+ #{createTime,jdbcType=BIGINT},
+
+
+
+
+ update monit_notify_history
+
+
+ monit_id = #{monitId,jdbcType=INTEGER},
+
+
+ app_id = #{appId,jdbcType=TINYINT},
+
+
+ notify_type = #{notifyType,jdbcType=TINYINT},
+
+
+ notify_target = #{notifyTarget,jdbcType=INTEGER},
+
+
+ notify_content = #{notifyContent,jdbcType=VARCHAR},
+
+
+ status = #{status,jdbcType=TINYINT},
+
+
+ retry_times = #{retryTimes,jdbcType=TINYINT},
+
+
+ create_time = #{createTime,jdbcType=BIGINT},
+
+
+ where record_id = #{recordId,jdbcType=BIGINT}
+
+
+ update monit_notify_history
+ set monit_id = #{monitId,jdbcType=INTEGER},
+ app_id = #{appId,jdbcType=TINYINT},
+ notify_type = #{notifyType,jdbcType=TINYINT},
+ notify_target = #{notifyTarget,jdbcType=INTEGER},
+ notify_content = #{notifyContent,jdbcType=VARCHAR},
+ status = #{status,jdbcType=TINYINT},
+ retry_times = #{retryTimes,jdbcType=TINYINT},
+ create_time = #{createTime,jdbcType=BIGINT}
+ where record_id = #{recordId,jdbcType=BIGINT}
+
+
\ No newline at end of file
diff --git a/src/cn/aofeng/demo/proxy/AccountService.java b/src/cn/aofeng/demo/proxy/AccountService.java
new file mode 100644
index 0000000..83c8f21
--- /dev/null
+++ b/src/cn/aofeng/demo/proxy/AccountService.java
@@ -0,0 +1,27 @@
+package cn.aofeng.demo.proxy;
+
+/**
+ * 账号服务接口定义。
+ *
+ * @author 聂勇
+ */
+public interface AccountService {
+
+ /**
+ * 注册。
+ *
+ * @param username 账号名
+ * @return 具体含义查看{@link Result}的说明。
+ */
+ Result register(String username);
+
+ /**
+ * 登录。
+ *
+ * @param username 账号名
+ * @param password 密码
+ * @return 具体含义查看{@link Result}的说明。
+ */
+ Result login(String username, String password);
+
+}
diff --git a/src/cn/aofeng/demo/proxy/AccountServiceClient.java b/src/cn/aofeng/demo/proxy/AccountServiceClient.java
new file mode 100644
index 0000000..946409a
--- /dev/null
+++ b/src/cn/aofeng/demo/proxy/AccountServiceClient.java
@@ -0,0 +1,28 @@
+package cn.aofeng.demo.proxy;
+
+/**
+ * 代理调用示例。
+ *
+ * @author 聂勇
+ */
+public class AccountServiceClient {
+
+ public static void main(String[] args) {
+ AccountService as = new AccountServiceImpl();
+
+ // 静态代理
+ AccountService staticProxy = new AccountServiceStaticProxy(as);
+ staticProxy.register(null);
+ staticProxy.register("A0001");
+ staticProxy.login(null, null);
+ staticProxy.login("A0001", "PWD0001");
+
+ // 动态代理
+ AccountService dynamicProxy = AccountServiceDynamicProxy.newInstance(as);
+ dynamicProxy.register(null);
+ dynamicProxy.register("A0001");
+ dynamicProxy.login(null, null);
+ dynamicProxy.login("A0001", "PWD0001");
+ }
+
+}
diff --git a/src/cn/aofeng/demo/proxy/AccountServiceDynamicProxy.java b/src/cn/aofeng/demo/proxy/AccountServiceDynamicProxy.java
new file mode 100644
index 0000000..562543c
--- /dev/null
+++ b/src/cn/aofeng/demo/proxy/AccountServiceDynamicProxy.java
@@ -0,0 +1,42 @@
+package cn.aofeng.demo.proxy;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 账号服务动态代理。
+ *
+ * @author 聂勇
+ */
+public class AccountServiceDynamicProxy implements InvocationHandler {
+
+ private final static Logger _LOGGER = LoggerFactory.getLogger(AccountServiceDynamicProxy.class);
+
+ private AccountService _accountService;
+
+ public AccountServiceDynamicProxy(AccountService accountService) {
+ this._accountService = accountService;
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ _LOGGER.debug("execute method {}, arguments: {}", method.getName(), args);
+ Object result = method.invoke(_accountService, args);
+ _LOGGER.debug("execute method {}, result:{}", method.getName(), result);
+
+ return result;
+ }
+
+ public static AccountService newInstance(AccountService accountService) {
+ ClassLoader loader = accountService.getClass().getClassLoader();
+ Class>[] interfaces = accountService.getClass().getInterfaces();
+
+ return (AccountService) Proxy.newProxyInstance(loader,
+ interfaces,
+ new AccountServiceDynamicProxy(accountService));
+ }
+}
diff --git a/src/cn/aofeng/demo/proxy/AccountServiceImpl.java b/src/cn/aofeng/demo/proxy/AccountServiceImpl.java
new file mode 100644
index 0000000..f527efc
--- /dev/null
+++ b/src/cn/aofeng/demo/proxy/AccountServiceImpl.java
@@ -0,0 +1,53 @@
+package cn.aofeng.demo.proxy;
+
+import java.util.Random;
+
+import wiremock.org.apache.commons.lang.StringUtils;
+
+/**
+ *
+ *
+ * @author 聂勇
+ */
+public class AccountServiceImpl implements AccountService {
+
+ private final static Random NUM = new Random(System.currentTimeMillis());
+
+ @Override
+ public Result register(String username) {
+ if (StringUtils.isBlank(username)) {
+ return createResult(4000001, "注册失败");
+ }
+
+ User user = new User();
+ user.setUid(NUM.nextInt());
+ user.setNickname("用户"+user.getUid());
+ return createResult(2000001, "注册成功", user);
+ }
+
+ @Override
+ public Result login(String username, String password) {
+ if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
+ return createResult(4000001, "登录失败");
+ }
+
+ User user = new User();
+ user.setUid(NUM.nextInt());
+ user.setNickname("用户"+user.getUid());
+ return createResult(2000001, "登录成功", user);
+ }
+
+ private Result createResult(int code, String msg) {
+ Result result = new Result(code, msg);
+
+ return result;
+ }
+
+ private Result createResult(int code, String msg, User user) {
+ Result result = new Result(code, msg);
+ result.setData(user);
+
+ return result;
+ }
+
+}
diff --git a/src/cn/aofeng/demo/proxy/AccountServiceStaticProxy.java b/src/cn/aofeng/demo/proxy/AccountServiceStaticProxy.java
new file mode 100644
index 0000000..9705868
--- /dev/null
+++ b/src/cn/aofeng/demo/proxy/AccountServiceStaticProxy.java
@@ -0,0 +1,39 @@
+package cn.aofeng.demo.proxy;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link AccountServiceImpl}的代理类,增加了输出入参和响应的日志。
+ *
+ * @author 聂勇
+ */
+public class AccountServiceStaticProxy implements AccountService {
+
+ private AccountService _delegate;
+
+ private final static Logger _LOGGER = LoggerFactory.getLogger(AccountServiceStaticProxy.class);
+
+ public AccountServiceStaticProxy(AccountService accountService) {
+ this._delegate = accountService;
+ }
+
+ @Override
+ public Result register(String username) {
+ _LOGGER.debug("execute method register, arguments: username={}", username);
+ Result result = _delegate.register(username);
+ _LOGGER.debug("execute method register, result:{}", result);
+
+ return result;
+ }
+
+ @Override
+ public Result login(String username, String password) {
+ _LOGGER.debug("execute method login, arguments: username={}, password={}", username, password);
+ Result result = _delegate.login(username, password);
+ _LOGGER.debug("execute method login, result:{}", result);
+
+ return result;
+ }
+
+}
diff --git a/src/cn/aofeng/demo/proxy/Result.java b/src/cn/aofeng/demo/proxy/Result.java
new file mode 100644
index 0000000..66ee038
--- /dev/null
+++ b/src/cn/aofeng/demo/proxy/Result.java
@@ -0,0 +1,65 @@
+package cn.aofeng.demo.proxy;
+
+/**
+ * 账号服务操作结果。
+ *
+ * @author 聂勇
+ */
+public class Result {
+
+ /**
+ * 200xxxx 表示成功。
+ * 400xxxx 表示参数错误。
+ * 500xxxx 表示服务内部错误。
+ */
+ private int code;
+
+ /**
+ * code对应的描述信息。
+ */
+ private String msg;
+
+ /**
+ * 只有code为200xxxx时才有值,其他情况下为null。
+ */
+ private User data;
+
+ public Result() {
+ // nothing
+ }
+
+ public Result(int code, String msg) {
+ this.code = code;
+ this.msg = msg;
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ public void setCode(int code) {
+ this.code = code;
+ }
+
+ public String getMsg() {
+ return msg;
+ }
+
+ public void setMsg(String msg) {
+ this.msg = msg;
+ }
+
+ public User getData() {
+ return data;
+ }
+
+ public void setData(User data) {
+ this.data = data;
+ }
+
+ @Override
+ public String toString() {
+ return "Result [code=" + code + ", msg=" + msg + ", data=" + data + "]";
+ }
+
+}
diff --git a/src/cn/aofeng/demo/proxy/User.java b/src/cn/aofeng/demo/proxy/User.java
new file mode 100644
index 0000000..a9cbd69
--- /dev/null
+++ b/src/cn/aofeng/demo/proxy/User.java
@@ -0,0 +1,38 @@
+/**
+ *
+ */
+package cn.aofeng.demo.proxy;
+
+/**
+ * 用户信息。
+ *
+ * @author 聂勇
+ */
+public class User {
+
+ private long uid;
+
+ private String nickname;
+
+ public long getUid() {
+ return uid;
+ }
+
+ public void setUid(long uid) {
+ this.uid = uid;
+ }
+
+ public String getNickname() {
+ return nickname;
+ }
+
+ public void setNickname(String nickname) {
+ this.nickname = nickname;
+ }
+
+ @Override
+ public String toString() {
+ return "User [uid=" + uid + ", nickname=" + nickname + "]";
+ }
+
+}
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) );
}
}