diff --git a/README.md b/README.md index 8120c37..54b40bb 100644 --- a/README.md +++ b/README.md @@ -15,21 +15,23 @@ - [CAS](https://github.com/lihengming/java-codes/tree/master/concurrent/src/main/java/cas) - [Unsafe](https://github.com/lihengming/java-codes/tree/master/concurrent/src/main/java/unsafe) - [生产者 - 消费者模型](https://github.com/lihengming/java-codes/tree/master/concurrent/src/main/java/pcmodel) - +- [网络](https://github.com/lihengming/java-codes/tree/master/socket) + - [一个类实现RPC框架](https://github.com/lihengming/java-codes/tree/master/socket/src/main/java/rpc) - [设计模式](https://github.com/lihengming/java-codes/tree/master/design-pattern) - [创建型模式(Creational)](https://github.com/lihengming/java-codes/tree/master/design-pattern/src/main/java/creational) - [简单工厂模式(Simple Factory)](https://github.com/lihengming/java-codes/blob/master/design-pattern/src/main/java/creational/SimpleFactoryPattern.java) - [工厂方法模式(Factory Method)](https://github.com/lihengming/java-codes/blob/master/design-pattern/src/main/java/creational/FactoryMethodPattern.java) - - 抽象工厂模式(Abstract Factory) - - 创建者模式(Builder) - - 原型模式(Prototype) - - 单例模式(Singleton) + - [抽象工厂模式(Abstract Factory)](https://github.com/lihengming/java-codes/blob/master/design-pattern/src/main/java/creational/AbstractFactoryPattern.java) + - [静态工厂方法模式(Static Factory Method)](https://github.com/lihengming/java-codes/blob/master/design-pattern/src/main/java/creational/StaticFactoryMethodPattern.java) + - [创建者模式(Builder)](https://github.com/lihengming/java-codes/blob/master/design-pattern/src/main/java/creational/BuilderPattern.java) + - [原型模式(Prototype)](https://github.com/lihengming/java-codes/blob/master/design-pattern/src/main/java/creational/PrototypePattern.java) + - [单例模式(Singleton)](https://github.com/lihengming/java-codes/blob/master/design-pattern/src/main/java/creational/SingletonPattern.java) - [结构型模式(Structural)](https://github.com/lihengming/java-codes/tree/master/design-pattern/src/main/java/structural) - - 外观模式(Facade) - - 适配器模式(Adapter) - - 代理模式(Proxy) - - 装饰模式(Decorator) - - 桥模式(Bridge) + - [外观(门面)模式(Facade)](https://github.com/lihengming/java-codes/blob/master/design-pattern/src/main/java/structural/FacadePattern.java) + - [适配器模式(Adapter)](https://github.com/lihengming/java-codes/blob/master/design-pattern/src/main/java/structural/AdapterPattern.java) + - [代理模式(Proxy)](https://github.com/lihengming/java-codes/blob/master/design-pattern/src/main/java/structural/ProxyPattern.java) + - [装饰模式(Decorator)](https://github.com/lihengming/java-codes/blob/master/design-pattern/src/main/java/structural/DecoratorPattern.java) + - [桥接模式(Bridge)](https://github.com/lihengming/java-codes/blob/master/design-pattern/src/main/java/structural/BridgePattern.java) - 组合模式(Composite) - 享元模式(Flyweight) - [行为型模式(Behavioral)](https://github.com/lihengming/java-codes/tree/master/design-pattern/src/main/java/behavioral) diff --git a/concurrent/src/main/java/juc/CountDownLatchTest.java b/concurrent/src/main/java/juc/CountDownLatchTest.java index 8c30e98..7bed6bd 100644 --- a/concurrent/src/main/java/juc/CountDownLatchTest.java +++ b/concurrent/src/main/java/juc/CountDownLatchTest.java @@ -6,7 +6,7 @@ * Created by 李恒名 on 2017/6/18. */ public class CountDownLatchTest { - static CountDownLatch latch = new CountDownLatch(3);//创建计数器并设置初始值为 + static CountDownLatch latch = new CountDownLatch(3);//创建计数器并设置初始值为3 static void work() { System.out.println(Thread.currentThread().getName() + " Work End"); diff --git a/concurrent/src/main/java/juc/SemaphoreTest.java b/concurrent/src/main/java/juc/SemaphoreTest.java index a5080f5..0ab226c 100644 --- a/concurrent/src/main/java/juc/SemaphoreTest.java +++ b/concurrent/src/main/java/juc/SemaphoreTest.java @@ -41,10 +41,11 @@ public void use() { System.out.println(Thread.currentThread().getName() +" 正在使用卫生间"); TimeUnit.SECONDS.sleep(3); System.out.println(Thread.currentThread().getName() +" 使用完毕"); - //释放许可 - semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); + } finally{ + //释放许可 + semaphore.release(); } } } diff --git a/concurrent/src/main/java/thread/DeadlockTest.java b/concurrent/src/main/java/thread/DeadlockTest.java new file mode 100644 index 0000000..88e90ef --- /dev/null +++ b/concurrent/src/main/java/thread/DeadlockTest.java @@ -0,0 +1,57 @@ +package thread; + +import java.util.concurrent.TimeUnit; + +/** + * Created by 李恒名 on 2017/8/29. + * + * 死锁测试,线程1获得A锁(monitor)之后尝试获得B锁,线程2获得B锁后尝试获得A锁,线程1和线程2即产生死锁。 + */ +public class DeadlockTest { + public static void main(String[] args) { + Object lockA = new Object(); + Object lockB = new Object(); + new Thread(() -> { + //线程1获得A锁 + synchronized (lockA){ + System.out.println("Thread 1 get lock A ."); + //增加死锁发生几率 + try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {} + //尝试获得B锁 + System.out.println("Thread 1 try get lock B, waiting..."); + synchronized (lockB){ + //永远无法获得B锁,所以不会打印出来 + System.out.println("Thread 1 get lock B ."); + } + + } + }, "Thread 1").start(); + new Thread(() -> { + //线程2获得B锁 + synchronized (lockB){ + System.out.println("Thread 2 get lock B ."); + //增加死锁发生几率 + try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {} + //尝试获得A锁 + System.out.println("Thread 2 try get lock A, waiting..."); + synchronized (lockA){ + //永远无法获得A锁,所以不会打印出来 + System.out.println("Thread 2 get lock A ."); + } + + } + }, "Thread 2").start(); + + /** + > jstack [pid] + + "Thread 2": + waiting to lock monitor 0x0000000002cc7338 (object 0x000000076b7b31d8, a java.lang.Object), + which is held by "Thread 1" + "Thread 1": + waiting to lock monitor 0x0000000002cc9bc8 (object 0x000000076b7b31e8, a java.lang.Object), + which is held by "Thread 2" + + */ + } +} diff --git a/data-structure-algorithm/src/main/java/data/structure/queue/QueueLinkedImpl.java b/data-structure-algorithm/src/main/java/data/structure/queue/QueueLinkedImpl.java index abefe8b..c0c8e9c 100644 --- a/data-structure-algorithm/src/main/java/data/structure/queue/QueueLinkedImpl.java +++ b/data-structure-algorithm/src/main/java/data/structure/queue/QueueLinkedImpl.java @@ -22,7 +22,8 @@ public void enQueue(Object element) { if (first == null) { first = last; } else { - oldLast.element = last; + //2017年7月26日17:28:33 原始链表尾的next指针指向新加的节点 + oldLast.next = last; } } diff --git a/design-pattern/src/main/java/creational/AbstractFactoryPattern.java b/design-pattern/src/main/java/creational/AbstractFactoryPattern.java new file mode 100644 index 0000000..a40d8b9 --- /dev/null +++ b/design-pattern/src/main/java/creational/AbstractFactoryPattern.java @@ -0,0 +1,107 @@ +package creational; + +/** + * Created by 李恒名 on 2017/7/16. + *

+ * 抽象工厂模式,与简单工厂、工厂方法模式的区别在于,前者只有一个产品线只为创建一个 + * 产品服务,而后者则拥有多个产品线。 + */ +public class AbstractFactoryPattern { + //汽车抽象 + static abstract class Car { + abstract void run(); + } + + //SUV产品抽象 + static abstract class Suv extends Car { + } + + //商务轿车产品抽象 + static abstract class Sedan extends Car { + } + + //奔驰SUV + static class BenzSuv extends Suv { + @Override + void run() { + System.out.println("奔驰(SUV)车在跑"); + } + } + + //奔驰轿车 + static class BenzSedan extends Sedan { + @Override + void run() { + System.out.println("奔驰(轿车)车在跑"); + } + } + + //宝马SUV + static class BMWSuv extends Suv { + @Override + void run() { + System.out.println("宝马(SUV)车在跑"); + } + } + + //宝马轿车 + static class BMWSedan extends Sedan { + @Override + void run() { + System.out.println("宝马(轿车)车在跑"); + } + } + + //抽象汽车工厂(拥有两个产品线) + static abstract class CarFactory { + abstract Suv getSuv(); + + abstract Sedan getSedan(); + } + + //奔驰汽车工厂 + static class BenzCarFactory extends CarFactory { + + @Override + Suv getSuv() { + return new BenzSuv(); + } + + @Override + Sedan getSedan() { + return new BenzSedan(); + } + } + + //宝马汽车工厂 + static class BMWCarFactory extends CarFactory { + + @Override + Suv getSuv() { + return new BMWSuv(); + } + + @Override + Sedan getSedan() { + return new BMWSedan(); + } + } + + public static void main(String[] args) { + CarFactory carFactory = new BenzCarFactory(); + //CarFactory carFactory = new BMWCarFactory(); + Sedan sedan = carFactory.getSedan(); + sedan.run(); + Suv suv = carFactory.getSuv(); + suv.run(); + } + + /** + * 总结: + * 所谓抽象工厂模式就是她提供一个接口,用于创建相关或者依赖对象的家族,而不需要明确 + * 指定具体类。他允许客户端使用抽象的接口来创建一组相关的产品,而不需要关系实际产出 + * 的具体产品是什么。这样一来,客户就可以从具体的产品中被解耦。它的优点是隔离了具体 + * 类的生成,使得客户端不需要知道什么被创建了,而缺点就在于新增新的行为会比较麻烦, + * 因为当添加一个新的产品对象时,需要更加需要更改接口及其下所有子类。 + */ +} diff --git a/design-pattern/src/main/java/creational/BuilderPattern.java b/design-pattern/src/main/java/creational/BuilderPattern.java new file mode 100644 index 0000000..3739873 --- /dev/null +++ b/design-pattern/src/main/java/creational/BuilderPattern.java @@ -0,0 +1,87 @@ +package creational; + +/** + * Created by Potato on 2017/7/16. + *

+ * 创建者模式,当创造一个对象需要很多步骤时适合使用建造者模式。而当只需调用一个方法 + * 就可以简单地创建整个对象时适合使用工厂模式。 + * @see StringBuilder + * @see StringBuffer + * @see java.sql.PreparedStatement + * @see javax.swing.GroupLayout.Group + */ +public class BuilderPattern { + + /** + * 被创建的对象,以手机为例。 + */ + static class Phone { + private String displayScreen;//显示器 + private String battery;//电池 + private String camera;//摄像头 + private String operatingSystem;//操作系统 + + public String getDisplayScreen() { + return displayScreen; + } + + public void setDisplayScreen(String displayScreen) { + this.displayScreen = displayScreen; + } + + public String getBattery() { + return battery; + } + + public void setBattery(String battery) { + this.battery = battery; + } + + public String getCamera() { + return camera; + } + + public void setCamera(String camera) { + this.camera = camera; + } + + public String getOperatingSystem() { + return operatingSystem; + } + + public void setOperatingSystem(String operatingSystem) { + this.operatingSystem = operatingSystem; + } + } + + static class PhoneBuilder { + public Phone build(){ + Phone phone = new Phone(); + phone.setBattery("三星电池"); + phone.setCamera("索尼摄像头"); + phone.setDisplayScreen("三星显示器"); + phone.setOperatingSystem("IOS 10 操作系统"); + System.out.println(String.format("手机创建完成,使用%s、%s、%s、%s。", + phone.getBattery(), + phone.getCamera(), + phone.getDisplayScreen(), + phone.getOperatingSystem())); + return phone; + } + } + + public static void main(String[] args) { + PhoneBuilder builder = new PhoneBuilder(); + Phone phone = builder.build(); + //手机创建完成,使用三星电池、索尼摄像头、三星显示器、IOS 10 操作系统。 + } + + /** + * 总结: + * 建造者模式将复杂产品的构建过程封装分解在不同的方法中,使得创建过程非常清晰,能够 + * 让我们更加精确的控制复杂产品对象的创建过程,同时它隔离了复杂产品对象的创建和使用 + * ,使得相同的创建过程能够创建不同的产品。但是如果某个产品的内部结构过于复杂,将会 + * 导致整个系统变得非常庞大,不利于控制,同时若几个产品之间存在较大的差异,则不适用 + * 建造者模式,毕竟这个世界上存在相同点大的两个产品并不是很多,所以它的使用范围有限。 + */ +} diff --git a/design-pattern/src/main/java/creational/FactoryMethodPattern.java b/design-pattern/src/main/java/creational/FactoryMethodPattern.java index a93fec0..eea01d1 100644 --- a/design-pattern/src/main/java/creational/FactoryMethodPattern.java +++ b/design-pattern/src/main/java/creational/FactoryMethodPattern.java @@ -6,18 +6,11 @@ * 工厂方法模式 */ public class FactoryMethodPattern { - - public static void main(String[] args) { - CarFactory factory = new BenzFactory(); - //CarFactory factory = new BMWFactory(); - Car car = factory.getCar(); - car.run(); - } - + //汽车抽象 static abstract class Car { abstract void run(); } - + //奔驰汽车 static class Benz extends Car { @Override @@ -25,7 +18,7 @@ void run() { System.out.println("奔驰车在跑"); } } - + //宝马汽车 static class BMW extends Car { @Override @@ -33,23 +26,41 @@ void run() { System.out.println("宝马车在跑"); } } - + //抽象的汽车工厂 static abstract class CarFactory { - abstract Car getCar(); + public abstract Car getCar(); } - + //奔驰汽车工厂 static class BenzFactory extends CarFactory { @Override - Car getCar() { + public Car getCar() { return new Benz(); } } - + //宝马汽车工厂 static class BMWFactory extends CarFactory { @Override - Car getCar() { + public Car getCar() { return new BMW(); } } + public static void main(String[] args) { + CarFactory factory = new BenzFactory(); + //CarFactory factory = new BMWFactory(); + Car car = factory.getCar(); + car.run(); + } + + /** + * 总结: + * 作为抽象工厂模式的孪生兄弟,工厂方法模式定义了一个创建对象的接口,但由子类决定要 + * 实例化的类是哪一个,也就是说工厂方法模式让实例化推迟到子类。 + * + * 工厂方法模式非常符合“开闭原则”,当需要增加一个新的产品时,我们只需要增加一个具 + * 体的产品类和与之对应的具体工厂即可,无须修改原有系统。同时在工厂方法模式中用户只 + * 需要知道生产产品的具体工厂即可,无须关系产品的创建过程,甚至连具体的产品类名称都 + * 不需要知道。虽然他很好的符合了“开闭原则”,但是由于每新增一个新产品时就需要增加 + * 两个类,这样势必会导致系统的复杂度增加。 + */ } diff --git a/design-pattern/src/main/java/creational/PrototypePattern.java b/design-pattern/src/main/java/creational/PrototypePattern.java new file mode 100644 index 0000000..33e1fd4 --- /dev/null +++ b/design-pattern/src/main/java/creational/PrototypePattern.java @@ -0,0 +1,47 @@ +package creational; + +/** + * Created by 李恒名 on 2017/7/16. + *

+ * 原型模式,即通过一个实例的原型来复制(克隆)出类似的实例,而不是去重新创建,这有 + * 点像克隆人。如果你使用过 Javascript ,你应该对 Prototype 很熟悉。 + */ +public class PrototypePattern { + + /** + * 简单来说就是通过实现 Cloneable 接口来进行复制,这种复制方式为浅复制。 + * + * @see Cloneable + */ + static class Man implements Cloneable { + private String name = "高富帅"; + + @Override + protected Man clone() throws CloneNotSupportedException { + return (Man) super.clone(); + } + + @Override + public String toString() { + return "Man{" + + "name='" + name + '\'' + + '}'; + } + } + + public static void main(String[] args) throws CloneNotSupportedException { + Man man = new Man(); + System.out.println(man); + System.out.println(man.clone()); + System.out.println(man.clone()); + System.out.println(man.clone()); + } + + /** + * 总结: + * 在开发过程中,有时会遇到为一个类创建多个实例的情况,这些实例内部成员往往完 + * 全相同或有细微的差异,而且实例的创建开销比较大或者需要输入较多参数,如果能通过复 + * 制一个已创建的对象实例来重复创建多个相同的对象,这就可以大大减少创建对象的开销, + * 这个时候就需要原型模式。 + */ +} diff --git a/design-pattern/src/main/java/creational/SimpleFactoryPattern.java b/design-pattern/src/main/java/creational/SimpleFactoryPattern.java index 88a9cd1..3ae9457 100644 --- a/design-pattern/src/main/java/creational/SimpleFactoryPattern.java +++ b/design-pattern/src/main/java/creational/SimpleFactoryPattern.java @@ -3,37 +3,28 @@ /** * Created by 李恒名 on 2017/6/14. *

- * 简单工厂模式 + * 简单工厂模式,简单来说就是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(该模式并不属于GOF 23) */ public class SimpleFactoryPattern { - - public static void main(String[] args) { - CarFactory factory = new CarFactory(); - Car car = factory.getCar("Benz"); - //Car car = factory.getCar("BMW"); - car.run(); - } - + //汽车抽象 static abstract class Car { abstract void run(); } - + //奔驰汽车 static class Benz extends Car { - @Override void run() { System.out.println("奔驰车在跑"); } } - + //宝马汽车 static class BMW extends Car { - @Override void run() { System.out.println("宝马车在跑"); } } - + //汽车工厂,根据汽车名称创建汽车 static class CarFactory { Car getCar(String name) { if (name.equals("Benz")) { @@ -45,5 +36,12 @@ Car getCar(String name) { } } } + + public static void main(String[] args) { + CarFactory factory = new CarFactory(); + Car car = factory.getCar("Benz"); + //Car car = factory.getCar("BMW"); + car.run(); + } } diff --git a/design-pattern/src/main/java/creational/SingletonPattern.java b/design-pattern/src/main/java/creational/SingletonPattern.java new file mode 100644 index 0000000..f73fec5 --- /dev/null +++ b/design-pattern/src/main/java/creational/SingletonPattern.java @@ -0,0 +1,122 @@ +package creational; + +import org.junit.Assert; + +import java.util.Objects; + +/** + * Created by 李恒名 on 2017/7/15. + *

+ * 单例模式,即一个类只允许存在一个实例。 + * + * @see java.lang.Runtime#getRuntime() + */ +public class SingletonPattern { + /** + * 懒汉式,线程不安全,在使用时初始化示例(懒加载) + */ + static class Singleton1 { + private static Singleton1 instance; + + private Singleton1() { + new AssertionError("don't support reflect."); + } + + public static Singleton1 getInstance() { + if (instance == null) { + instance = new Singleton1(); + } + return instance; + } + } + + /** + * 懒汉式,线程安全,在使用时初始化示例(懒加载) + */ + static class Singleton2 { + private static Singleton2 instance; + + private Singleton2() { + new AssertionError("don't support reflect."); + } + + public static synchronized Singleton2 getInstance() { + if (instance == null) { + instance = new Singleton2(); + } + return instance; + } + } + + /** + * 懒汉式线程安全的优化写法,双重检验锁模式(double checked locking pattern) + */ + static class Singleton3 { + private volatile static Singleton3 instance; + + private Singleton3() { + new AssertionError("don't support reflect."); + } + + public static Singleton3 getInstance() { + if (instance == null) { // Single Checked + synchronized (Singleton3.class) { + if (instance == null) { // Double checked + instance = new Singleton3(); + } + } + } + return instance; + } + } + + /** + * 饿汉式 static final field,在类被被类加载器加载时便创建实例 + */ + static class Singleton4 { + + private static final Singleton4 instance = new Singleton4(); + + private Singleton4() { + new AssertionError("don't support reflect."); + } + + public static Singleton4 getInstance() { + return instance; + } + } + + /** + * 使用静态内部类 static nested class ,这种方法是《Effective Java》上所推荐的 + */ + static class Singleton5 { + private static class SingletonHolder { + private static final Singleton5 INSTANCE = new Singleton5(); + } + + private Singleton5() { + new AssertionError("don't support reflect."); + } + + public static final Singleton5 getInstance() { + return SingletonHolder.INSTANCE; + } + } + + /** + * 使用枚举,这也是单例模式最简单的实现 ,这种方法也是《Effective Java》上所推荐的 + */ + public enum Singleton6 { + INSTANCE; + } + + public static void main(String[] args) { + Assert.assertTrue(Objects.equals(Singleton1.getInstance(), Singleton1.getInstance())); + Assert.assertTrue(Objects.equals(Singleton1.getInstance(), Singleton1.getInstance())); + Assert.assertTrue(Objects.equals(Singleton2.getInstance(), Singleton2.getInstance())); + Assert.assertTrue(Objects.equals(Singleton3.getInstance(), Singleton3.getInstance())); + Assert.assertTrue(Objects.equals(Singleton4.getInstance(), Singleton4.getInstance())); + Assert.assertTrue(Objects.equals(Singleton5.getInstance(), Singleton5.getInstance())); + Assert.assertTrue(Objects.equals(Singleton6.INSTANCE, Singleton6.INSTANCE)); + } +} diff --git a/design-pattern/src/main/java/creational/StaticFactoryMethodPattern.java b/design-pattern/src/main/java/creational/StaticFactoryMethodPattern.java new file mode 100644 index 0000000..7045354 --- /dev/null +++ b/design-pattern/src/main/java/creational/StaticFactoryMethodPattern.java @@ -0,0 +1,48 @@ +package creational; + +/** + * Created by 李恒名 on 2017/6/14. + *

+ * 静态工厂方法模式,准确来讲这并不是一种设计模式,只是为了简化创建对象的过程。 + * 这种创建对象形式很常见,比如 Guava 中的 Lists 、Maps 等。 + */ +public class StaticFactoryMethodPattern { + //汽车抽象 + static abstract class Car { + abstract void run(); + } + + //奔驰汽车 + static class Benz extends Car { + @Override + void run() { + System.out.println("奔驰车在跑"); + } + } + + //宝马汽车 + static class BMW extends Car { + @Override + void run() { + System.out.println("宝马车在跑"); + } + } + + //汽车工厂 + static final class CarFactory { + + public static Benz getBeznCar() { + return new Benz(); + } + public static BMW getBMWCar() { + return new BMW(); + } + } + + public static void main(String[] args) { + Car car = CarFactory.getBeznCar(); + //Car car = CarFactory.getBMWCar; + car.run(); + } +} + diff --git a/design-pattern/src/main/java/creational/package-info.java b/design-pattern/src/main/java/creational/package-info.java index 6c8399d..c0e2ccd 100644 --- a/design-pattern/src/main/java/creational/package-info.java +++ b/design-pattern/src/main/java/creational/package-info.java @@ -1,5 +1,15 @@ /** * 创建型模式 - * + *

+ * 在软件工程中,创建型模式是处理对象创建的设计模式,试图根据实际情况使用 + * 合适的方式创建对象。基本的对象创建方式可能会导致设计上的问题,或增加设 + * 计的复杂度。创建型模式通过以某种方式控制对象的创建来解决问题。 + *

+ * 创建型模式由两个主导思想构成。一是将系统使用的具体类封装起来,二是隐藏 + * 这些具体类的实例创建和结合的方式。 + *

+ * 创建型模式又分为对象创建型模式和类创建型模式。对象创建型模式处理对象的 + * 创建,类创建型模式处理类的创建。详细地说,对象创建型模式把对象创建的一 + * 部分推迟到另一个对象中,而类创建型模式将它对象的创建推迟到子类中。 */ package creational; \ No newline at end of file diff --git a/design-pattern/src/main/java/structural/AdapterPattern.java b/design-pattern/src/main/java/structural/AdapterPattern.java new file mode 100644 index 0000000..f6db536 --- /dev/null +++ b/design-pattern/src/main/java/structural/AdapterPattern.java @@ -0,0 +1,138 @@ +package structural; + +import org.junit.Test; + +/** + * Created by 李恒名 on 2017/7/27. + *

+ * 适配器模式,用于将一个类的接口转换成客户端所期待的另一种接口。 + */ +public class AdapterPattern { + + ////////////////////////////////////////////////////////////////////// + // 类适配器 // + ////////////////////////////////////////////////////////////////////// + + //被适配的源对象(Adaptee) + static class Power_220V { + public void in() { + System.out.print("220V电流输入"); + } + } + + //目标接口(Target) + interface Power_5V { + void in(); + } + + //适配器(Adapter),电源适配器为例 + static class PowerAdapter extends Power_220V implements Power_5V { + @Override + public void in() { + System.out.print("5V电流输入"); + System.out.print("("); + super.in(); + System.out.print(")"); + } + } + + //客户端,手机为例 + static class Iphone { + + public void charge(Power_5V power) { + System.out.print("充电中..."); + power.in(); + } + } + + @Test + public void testClassAdapter() { + Iphone iPhone = new Iphone(); + PowerAdapter powerAdapter = new PowerAdapter(); + iPhone.charge(powerAdapter); + //充电中...5V电流输入(220V电流输入) + } + + ////////////////////////////////////////////////////////////////////// + // 对象适配器 // + ////////////////////////////////////////////////////////////////////// + + //适配器(Adapter),电源适配器为例 + static class PowerAdapter2 implements Power_5V { + + private Power_220V power_220V; + + public PowerAdapter2(Power_220V power_220V) { + this.power_220V = power_220V; + } + + @Override + public void in() { + System.out.print("5V电流输入"); + System.out.print("("); + power_220V.in(); + System.out.print(")"); + } + } + + @Test + public void testObjectAdapter() { + Iphone iPhone = new Iphone(); + PowerAdapter2 powerAdapter = new PowerAdapter2(new Power_220V()); + iPhone.charge(powerAdapter); + //充电中...5V电流输入(220V电流输入) + } + + + ////////////////////////////////////////////////////////////////////// + // 接口适配器 // + ////////////////////////////////////////////////////////////////////// + + /** + * 有时候,我们需要实现一个接口,但只想实现其中一部分方法,又不 + * 想出现很多空的实现方法(这会让代码不那么优美),这时候就便可 + * 以使用接口适配器,把那些空的实现方法放在适配器内,去重写那些 + * 我们真正要实现的方法即可。 + *

+ * 如果你使用过 Spring MVC,你应该对下面这两个接口适配器很熟悉 + *

+ * - WebMvcConfigurerAdapter + * - HandlerInterceptorAdapter + */ + + //源接口 + interface Source { + void method1(); + + void method2(); + + void method3(); + } + + //接口适配器 + static abstract class SourceAdapter implements Source { + @Override + public void method1() {} + @Override + public void method2() { } + @Override + public void method3() { } + } + + //继承适配器,重写 method1 + static class SourceImpl extends SourceAdapter { + @Override + public void method1() { + System.out.println("method1 impl"); + } + } + + /** + * 总结: + * 在我们的应用程序中我们可能需要将两个不同接口的类来进行通信,在不修改这两个的前提 + * 下我们可能会需要某个中间件来完成这个衔接的过程。这个中间件就是适配器。所谓适配器 + * 模式就是将一个类的接口,转换成客户期望的另一个接口。它可以让原本两个不兼容的接口 + * 能够无缝完成对接。 + */ + +} diff --git a/design-pattern/src/main/java/structural/BridgePattern.java b/design-pattern/src/main/java/structural/BridgePattern.java new file mode 100644 index 0000000..510baf9 --- /dev/null +++ b/design-pattern/src/main/java/structural/BridgePattern.java @@ -0,0 +1,97 @@ +package structural; + +/** + * Created by 李恒名 on 2017/10/06. + * + * 桥接模式的意图是将抽象类与抽象方法的实现相互分离来实现解耦,以便二者可以相互独立地变化。 + * + * 比如太阳镜,太阳镜有很多种品牌,不管何种品牌它们都会提供不同的风格供顾客选择,比如复古 + * 风格、飞行员风格等,太阳镜与风格间的关系便可使用该模式来维护。 + */ +public class BridgePattern { + //太阳镜的抽象类 + static abstract class SunGlasses { + protected Style style; + + protected SunGlasses(Style style) { + this.style = style; + } + + //获取品牌名称 + abstract String getBrandName(); + + //戴眼镜 + public void putOn() { + System.out.println("戴上" + getBrandName() + "-" + style.getStyle() + "风格的太阳镜"); + } + } + + static class BolonSunGlasses extends SunGlasses { + public BolonSunGlasses(Style style) { + super(style); + } + + @Override + String getBrandName() { + return "暴龙"; + } + } + + static class DiorSunGlasses extends SunGlasses { + public DiorSunGlasses(Style style) { + super(style); + } + + @Override + String getBrandName() { + return "迪奥"; + } + } + + //太阳镜风格接口 + interface Style { + String getStyle(); + } + + //复古风格 + static class RetroStyle implements Style { + + @Override + public String getStyle() { + return "复古"; + } + } + + //飞行员风格 + static class PilotStyle implements Style { + + @Override + public String getStyle() { + return "飞行员"; + } + } + + public static void main(String[] args) { + RetroStyle retroStyle = new RetroStyle(); + PilotStyle pilotStyle = new PilotStyle(); + + SunGlasses glasses = new DiorSunGlasses(retroStyle); + glasses.putOn(); + //戴上迪奥-复古风格的太阳镜 + glasses = new DiorSunGlasses(pilotStyle); + glasses.putOn(); + //戴上迪奥-飞行员风格的太阳镜 + glasses = new BolonSunGlasses(pilotStyle); + glasses.putOn(); + //戴上暴龙-飞行员风格的太阳镜 + } + + /** + * 总结: + * 如果说某个系统能够从多个角度来进行分类,且每一种分类都可能会变化,那么我们需要做 + * 的就是讲这多个角度分离出来,使得他们能独立变化,减少他们之间的耦合,这个分离过 + * 程就使用了桥接模式。所谓桥接模式就是讲抽象部分和实现部分隔离开来,使得他们能够 + * 独立变化。桥接模式将继承关系转化成关联关系,封装了变化,完成了解耦,减少了系统 + * 中类的数量,也减少了代码量。 + */ +} diff --git a/design-pattern/src/main/java/structural/DecoratorPattern.java b/design-pattern/src/main/java/structural/DecoratorPattern.java new file mode 100644 index 0000000..4d5d9f8 --- /dev/null +++ b/design-pattern/src/main/java/structural/DecoratorPattern.java @@ -0,0 +1,117 @@ +package structural; + +/** + * Created by 李恒名 on 2017/7/27. + *

+ * 装饰者模式 + * + * @see java.io.InputStream 抽象构件 + * @see java.io.FilterInputStream 抽象装饰类 + * @see java.io.BufferedInputStream 具体的装饰类 + * @see java.io.DataInputStream 具体的装饰类 + */ +public class DecoratorPattern { + //抽象构件(Component) + static abstract class Man { + abstract void aboutMe(); + } + + //具体的构件(ConcreteComponent) + static class Potato extends Man { + + @Override + public void aboutMe() { + System.out.print("Hi,我是土豆"); + } + } + + //抽象装饰类(Decorator) + static abstract class Decorator extends Man { + private Man man; + + protected Decorator(Man man) { + this.man = man; + } + + @Override + public void aboutMe() { + man.aboutMe(); + } + } + + //具体装饰类(ConcreteDecorator) + static class ProgrammerDecorator extends Decorator { + public ProgrammerDecorator(Man man) { + super(man); + } + + @Override + public void aboutMe() { + super.aboutMe(); + System.out.print(",我的职业是程序员"); + } + } + + //具体装饰类(ConcreteDecorator) + static class ReaderDecorator extends Decorator { + public ReaderDecorator(Man man) { + super(man); + } + + @Override + public void aboutMe() { + super.aboutMe(); + System.out.print(",我喜欢读书"); + + } + } + + //具体装饰类(ConcreteDecorator) + static class GitHubDecorator extends Decorator { + public GitHubDecorator(Man man) { + super(man); + } + + @Override + public void aboutMe() { + super.aboutMe(); + System.out.print(",闲暇时我喜欢在 GitHub 上溜达"); + + } + } + + //具体装饰类(ConcreteDecorator) + static class WriterDecorator extends Decorator { + public WriterDecorator(Man man) { + super(man); + } + + @Override + public void aboutMe() { + super.aboutMe(); + System.out.print(",也会去写一些技术文章"); + + } + } + + //具体装饰类(ConcreteDecorator) + public static void main(String[] args) { + Man potato = new Potato(); + potato.aboutMe(); + //Hi,我是土豆 + + System.out.println(); + + potato = new WriterDecorator(new GitHubDecorator(new ReaderDecorator(new ProgrammerDecorator(potato)))); + potato.aboutMe(); + //Hi,我是土豆,我的职业是程序员,我喜欢读书,闲暇时我喜欢在 GitHub 上溜达,也会去写一些技术文章 + } + + /** + * 总结: + * 装饰者模式,可以动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更加有 + * 弹性的替代方案,有效的避免了类爆炸现象的产生。虽然装饰者模式能够动态将责任附加到 + * 对象上,但是他会产生许多的细小对象,增加了系统的复杂度。java.io 包可谓是装饰者 + * 模式的最佳实践。 + */ +} diff --git a/design-pattern/src/main/java/structural/FacadePattern.java b/design-pattern/src/main/java/structural/FacadePattern.java new file mode 100644 index 0000000..f491855 --- /dev/null +++ b/design-pattern/src/main/java/structural/FacadePattern.java @@ -0,0 +1,59 @@ +package structural; + +/** + * Created by 李恒名 on 2017/7/17. + *

+ * 外观模式,也称门面模式,用于为一个复杂的系统提供一个统一、简单的访问入口 + */ +public class FacadePattern { + + //系统门面 + static class SystemFacade { + void start() { + new SubSystemA().start(); + new SubSystemB().start(); + new SubSystemC().start(); + new SubSystemD().start(); + } + } + + static class SubSystemA { + void start() { + System.out.println("子系统A启动"); + } + } + + static class SubSystemB { + void start() { + System.out.println("子系统B启动"); + } + } + + static class SubSystemC { + void start() { + System.out.println("子系统C启动"); + } + } + + static class SubSystemD { + void start() { + System.out.println("子系统D启动"); + } + } + + public static void main(String[] args) { + SystemFacade facade = new SystemFacade(); + facade.start(); + } + + /** + * 总结: + * 我们都知道类与类之间的耦合越低,那么可复用性就越好,如果两个类不必彼此通信,那么 + * 就不要让这两个类发生直接的相互关系,如果需要调用里面的方法,可以通过第三者来转发 + * 调用。外观模式非常好的诠释了这段话。外观模式提供了一个统一的接口,用来访问子系统 + * 中的一群接口。它让一个应用程序中子系统间的相互依赖关系减少到了最少,它给子系统提 + * 供了一个简单、单一的屏障,客户通过这个屏障来与子系统进行通信。 + * 通过使用外观模式,使得客户对子系统的引用变得简单了,实现了客户与子系统之间的松耦 + * 合,但是它违背了“开闭原则”,因为增加新的子系统可能需要修改外观类或客户端的源代码。 + */ +} diff --git a/design-pattern/src/main/java/structural/ProxyPattern.java b/design-pattern/src/main/java/structural/ProxyPattern.java new file mode 100644 index 0000000..6079a82 --- /dev/null +++ b/design-pattern/src/main/java/structural/ProxyPattern.java @@ -0,0 +1,104 @@ +package structural; + +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by 李恒名 on 2017/7/19. + *

+ * 代理模式,为目标对象创建一个代理对象,其他对象可以通过代理对象来访问目标对象的方法,AOP、拦截器均为该模式的实践。 + * + * @see java.lang.reflect.Proxy JDK动态代理 + */ +public class ProxyPattern { + //唱歌的能力 + interface Singable { + void sing(); + } + + //歌手 + static class Singer implements Singable { + + @Override + public void sing() { + System.out.println("歌手唱歌"); + } + } + + //歌手的代理人 + static class SingerProxy implements Singable { + //歌手 + private Singable singer; + + public SingerProxy(Singable singer) { + this.singer = singer; + } + + @Override + public void sing() { + System.out.println("代理人承接演出"); + System.out.println("代理人布置演出场地"); + singer.sing(); + System.out.println("代理人结算演出费用"); + } + } + + public static void main(String[] args) { + Singer singer = new Singer(); + SingerProxy proxy = new SingerProxy(singer); + proxy.sing(); + + /** + * 代理人承接演出 + * 代理人布置演出场地 + * 歌手唱歌 + * 代理人结算演出费用 + */ + + // 如果,代理目标方法较多使用静态代理较为麻烦,可以使用动态代理,下面是使用JDK实 + // 现动态代理的方式,这种方式有一个要求,被代理的对象必须实现接口。 + + List list = DynamicProxy.proxy(new ArrayList()); + list.add("data"); + list.size(); + list.remove("data"); + + /** + * 前置代理,调用方法:add() + * 后置代理,方法返回:true + * 前置代理,调用方法:size() + * 后置代理,方法返回:1 + * 前置代理,调用方法:remove() + * 后置代理,方法返回:true + */ + + // 当然除了JDK 提供的方式外我们也可以使用 CGLIB 来使用动态代理,它不要求代理的对象 + // 必须实现接口,这基于ASM 字节码技术。 + } + + private static class DynamicProxy { + + public static T proxy(T target) { + + return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), + target.getClass().getInterfaces(), (proxy, method, args) -> { + System.out.println("前置代理,调用方法:" + method.getName()+"()"); + Object result = method.invoke(target, args); + System.out.println("后置代理,方法返回:" + result); + return result; + }); + } + } + + + /** + * 总结: + * 代理模式就是给一个对象提供一个代理,并由代理对象控制对原对象的引用。它使得客户不 + * 能直接与真正的目标对象通信。代理对象是目标对象的代表,其他需要与这个目标对象打交 + * 道的操作都是和这个代理对象在交涉。代理对象可以在客户端和目标对象之间起到中介的作 + * 用,这样起到了的作用和保护了目标对象的,同时也在一定程度上面减少了系统的耦合度。 + */ + + +} diff --git a/design-pattern/src/main/java/structural/package-info.java b/design-pattern/src/main/java/structural/package-info.java index b52a66f..21e0be3 100644 --- a/design-pattern/src/main/java/structural/package-info.java +++ b/design-pattern/src/main/java/structural/package-info.java @@ -1,5 +1,8 @@ /** * 结构型模式 - * + *

+ * 结构型模式主要是用于处理类或者对象的组合,它描述了如何来类或者对象更好的组合起来 + * ,是从程序的结构上来解决模块之间的耦合问题。它主要包括适配器模式、桥接模式、组合 + * 模式、装饰模式、外观模式、享元模式、代理模式这个七个模式。 */ package structural; \ No newline at end of file diff --git a/jvm/src/main/java/classloader/CustomClassLoader.java b/jvm/src/main/java/classloader/CustomClassLoader.java index eb22706..b9a0069 100644 --- a/jvm/src/main/java/classloader/CustomClassLoader.java +++ b/jvm/src/main/java/classloader/CustomClassLoader.java @@ -11,11 +11,6 @@ public class CustomClassLoader extends ClassLoader { private final String classesDir; - @Override - public Class loadClass(String name) throws ClassNotFoundException { - return super.loadClass(name,true); - } - public CustomClassLoader(String classesDir) { this.classesDir = classesDir; } @@ -23,11 +18,10 @@ public CustomClassLoader(String classesDir) { @Override protected Class findClass(String name) throws ClassNotFoundException { String fileName = name; - if (fileName.indexOf('.') > 0) { - fileName.replaceAll(".", "\\"); + if (fileName.indexOf('.') != -1) { + fileName = fileName.replaceAll("\\.", "\\\\"); } fileName = fileName + ".class"; - try { try (FileInputStream in = new FileInputStream(classesDir + fileName)) { try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { @@ -40,11 +34,9 @@ protected Class findClass(String name) throws ClassNotFoundException { return defineClass(name, data, 0, data.length); } } - } catch (IOException e) { - e.printStackTrace(); + throw new ClassNotFoundException(name); } - return super.findClass(name); } public static void main(String[] args) throws ReflectiveOperationException{ diff --git "a/shared-resources/Spring Boot\347\254\224\350\256\260.docx" "b/shared-resources/Spring Boot \347\254\224\350\256\260.docx" similarity index 100% rename from "shared-resources/Spring Boot\347\254\224\350\256\260.docx" rename to "shared-resources/Spring Boot \347\254\224\350\256\260.docx" diff --git a/shared-resources/github-images/druid-spring-boot-starter-ide-hint.jpg b/shared-resources/github-images/druid-spring-boot-starter-ide-hint.jpg new file mode 100644 index 0000000..c5d0fc2 Binary files /dev/null and b/shared-resources/github-images/druid-spring-boot-starter-ide-hint.jpg differ diff --git a/shared-resources/github-images/issue-31/step1.png b/shared-resources/github-images/issue-31/step1.png new file mode 100644 index 0000000..a68bef4 Binary files /dev/null and b/shared-resources/github-images/issue-31/step1.png differ diff --git a/shared-resources/github-images/issue-31/step2.png b/shared-resources/github-images/issue-31/step2.png new file mode 100644 index 0000000..a53437e Binary files /dev/null and b/shared-resources/github-images/issue-31/step2.png differ diff --git "a/shared-resources/\351\230\277\351\207\214\345\267\264\345\267\264Java\345\274\200\345\217\221\346\211\213\345\206\214V1.3.0.pdf" "b/shared-resources/\351\230\277\351\207\214\345\267\264\345\267\264Java\345\274\200\345\217\221\346\211\213\345\206\214V1.3.0.pdf" new file mode 100644 index 0000000..e6ed0c5 Binary files /dev/null and "b/shared-resources/\351\230\277\351\207\214\345\267\264\345\267\264Java\345\274\200\345\217\221\346\211\213\345\206\214V1.3.0.pdf" differ diff --git a/socket/pom.xml b/socket/pom.xml index 62e99a9..5a9cf57 100644 --- a/socket/pom.xml +++ b/socket/pom.xml @@ -10,6 +10,12 @@ 4.0.0 socket - - + + + + io.netty + netty + 3.5.2.Final + + \ No newline at end of file diff --git a/socket/src/main/java/netty/HelloClient.java b/socket/src/main/java/netty/HelloClient.java new file mode 100644 index 0000000..b722900 --- /dev/null +++ b/socket/src/main/java/netty/HelloClient.java @@ -0,0 +1,41 @@ +package netty; + +import org.jboss.netty.bootstrap.ClientBootstrap; +import org.jboss.netty.channel.*; +import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; + +import java.net.InetSocketAddress; +import java.util.concurrent.Executors; + +/** + * Created by 李恒名 on 2017/8/8. + */ +public class HelloClient { + public static void main(String args[]) { + // Client服务启动器 + ClientBootstrap bootstrap = new ClientBootstrap( + new NioClientSocketChannelFactory( + Executors.newCachedThreadPool(), + Executors.newCachedThreadPool())); + // 设置一个处理服务端消息和各种消息事件的类(Handler) + bootstrap.setPipelineFactory(() -> Channels.pipeline(new HelloClientHandler())); + // 连接到本地的8000端口的服务端 + bootstrap.connect(new InetSocketAddress("127.0.0.1", 8000)); + } + + private static class HelloClientHandler extends SimpleChannelHandler { + + + /** + * 当绑定到服务端的时候触发,打印"Hello world, I am client." + * + * @alia OneCoder + * @author lihzh + */ + @Override + public void channelConnected(ChannelHandlerContext ctx, + ChannelStateEvent e) { + System.out.println("Hello world, I am client."); + } + } +} diff --git a/socket/src/main/java/netty/NettyTest.java b/socket/src/main/java/netty/NettyTest.java new file mode 100644 index 0000000..f48e423 --- /dev/null +++ b/socket/src/main/java/netty/NettyTest.java @@ -0,0 +1,51 @@ +package netty; + + +import org.jboss.netty.bootstrap.ServerBootstrap; +import org.jboss.netty.channel.*; +import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; + +import java.net.InetSocketAddress; +import java.util.concurrent.Executors; + +/** + * Created by 李恒名 on 2017/8/8. + */ +public class NettyTest { + public static void main(String[] args) { + // Server服务启动器 + ServerBootstrap bootstrap = new ServerBootstrap( + new NioServerSocketChannelFactory( + Executors.newCachedThreadPool(), + Executors.newCachedThreadPool())); + // 设置一个处理客户端消息和各种消息事件的类(Handler) + bootstrap + .setPipelineFactory(new ChannelPipelineFactory() { + @Override + public ChannelPipeline getPipeline() + throws Exception { + return Channels + .pipeline(new HelloServerHandler()); + } + }); + // 开放8000端口供客户端访问。 + bootstrap.bind(new InetSocketAddress(8000)); + } + + private static class HelloServerHandler extends + SimpleChannelHandler { + + /** + * 当有客户端绑定到服务端的时候触发,打印"Hello world, I am server." + * + * @alia OneCoder + * @author lihzh + */ + @Override + public void channelConnected( + ChannelHandlerContext ctx, + ChannelStateEvent e) { + System.out.println("Hello world, I am server."); + } + } +} diff --git a/socket/src/main/java/rpc/RpcTest.java b/socket/src/main/java/rpc/RpcTest.java new file mode 100644 index 0000000..ef46e0a --- /dev/null +++ b/socket/src/main/java/rpc/RpcTest.java @@ -0,0 +1,60 @@ +package rpc; + +import java.util.concurrent.TimeUnit; + +import static rpc.SimpleRpcFramework.export; +import static rpc.SimpleRpcFramework.use; + +/** + * Created by 李恒名 on 2017/8/17. + */ +public class RpcTest { + private static final String HOST = "localhost"; + private static final int PORT = 8888; + + interface ComputeService { + int sum(int a, int b); + } + + + static class ComputeServiceImpl implements ComputeService { + + @Override + public int sum(int a, int b) { + return a + b; + } + } + + //服务提供者 + static class Provider implements Runnable { + @Override + public void run() { + //暴露服务 + export(new ComputeServiceImpl(), PORT); + } + } + + //服务消费者 + static class Customer implements Runnable { + @Override + public void run() { + //使用服务 + ComputeService computeService = use(ComputeService.class, HOST, PORT); + for (int i = 0; i < 10; i++) { + int sum = computeService.sum(1, 1); + System.out.println("SUM:" + sum); + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + public static void main(String[] args) { + new Thread(new Provider()).start(); + new Thread(new Customer()).start(); + new Thread(new Customer()).start(); + } +} diff --git a/socket/src/main/java/rpc/SimpleRpcFramework.java b/socket/src/main/java/rpc/SimpleRpcFramework.java new file mode 100644 index 0000000..dd90d16 --- /dev/null +++ b/socket/src/main/java/rpc/SimpleRpcFramework.java @@ -0,0 +1,67 @@ +package rpc; + +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.net.ServerSocket; +import java.net.Socket; + +/** + * Created by 李恒名 on 2017/8/17. + */ +public class SimpleRpcFramework { + + /** + * 暴漏服务 + * @param serviceImpl 服务的实现 + * @param port 服务所处的端口号 + */ + public static void export(Object serviceImpl, int port) { + try { + try (ServerSocket server = new ServerSocket(port)) { + while (!Thread.currentThread().isInterrupted()) { + Socket socket = server.accept(); + new Thread(() -> { + try (ObjectInputStream in = new ObjectInputStream(socket.getInputStream())) { + Method method = serviceImpl.getClass().getMethod(in.readUTF(), (Class[]) in.readObject()); + Object result = method.invoke(serviceImpl, (Object[]) in.readObject()); + try (ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream())) { + out.writeObject(result); + } + System.out.println("Invoke method [" + method.getName() + "()] success, form " + socket.getRemoteSocketAddress()); + } catch (Exception e) { + throw new RuntimeException("Export service fail .", e); + } + }).start(); + } + } + } catch (Exception e) { + throw new RuntimeException("Export service fail .", e); + } + System.out.println("Export service " + serviceImpl.getClass().getSimpleName() + " success on port " + port); + } + + /** + * 使用服务 + * @param serviceInterface 要使用的服务的接口 + * @param host 服务所处的主机名称 + * @param port 服务所处的端口号 + * @return 服务 + */ + public static T use(Class serviceInterface, String host, int port) { + System.out.println(String.format("Use remote service [%s] from [%s:%s]", serviceInterface.getSimpleName(), host, port)); + return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class[]{serviceInterface}, (proxy, method, args) -> { + try (Socket socket = new Socket(host, port)) { + try (ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream())) { + out.writeUTF(method.getName()); + out.writeObject(method.getParameterTypes()); + out.writeObject(args); + try (ObjectInputStream in = new ObjectInputStream(socket.getInputStream())) { + return in.readObject(); + } + } + } + }); + } +}