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