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 + * + */ + 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) ); } }