diff --git a/README.md b/README.md
index de1796a..cbbe5f5 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@
在这里,通过文章和代码,把这些知识点和技术的主要内容记录并汇总,供自己快速回顾,也分享给他人。
+注:部分例子基于JDK8。
+
## 关键字
* [transient与序列化](src/cn/aofeng/demo/java/lang/serialization/TransientDemo.java)
@@ -67,7 +69,7 @@
### 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
@@ -76,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)
@@ -91,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)
@@ -103,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/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) );
}
}