Proxy代理代码示例

jdk动态代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

/**
* 代理类
*/
public interface IDao {
String doThings(String metarita);
}

/**
* 被代理类
*/
public class DaoImpl implements IDao {
@Override
public String doThings(String metarita) {
System.out.println("原材料:" + metarita);
System.out.println("我是A,我在doThings");
return "成品";
}
}

/**
* 动态代理工厂
*/
public class ProxyFactory {

private Object target;

public ProxyFactory(Object target) {
this.target = target;
}

public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理类干活前我先干的......");
Object invoke = method.invoke(target, args);
System.out.println("代理类干完活我先后的......");
return invoke;
}
}
);
}
}

/**
* 测试main
*/
class Test {
public static void main(String[] args) {
IDao target = new DaoImpl();
// 输出目标对象信息
System.out.println(target.getClass());
IDao proxy = (IDao) new ProxyFactory(target).getProxyInstance();
// 输出代理对象信息
System.out.println(proxy.getClass());
// 执行代理方法
String things = proxy.doThings("000000000");
System.out.println(things);
}
}

cglib动态代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency>

/**
* 被代理类
*/
public class Dao {

public String doThings(String metarita) {
System.out.println("原材料:" + metarita);
System.out.println("我是A,我在doThings");
return "成品";
}
}


import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
* 代理工厂
*/
public class ProxyFactory implements MethodInterceptor {

private Object target;

public ProxyFactory(Object target) {
this.target = target;
}

/**
* 生成代理类
* @return
*/
public Object getProxyInstance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

System.out.println("干活前");
// 注意不能使用o,会死循环
Object invoke = method.invoke(this.target, objects);
System.out.println("干活后");

return invoke;
}
}

/**
* 测试main
*/
class Test {
public static void main(String[] args) {
//目标对象
Dao target = new Dao();
System.out.println(target.getClass());
//代理对象
Dao proxy = (Dao) new ProxyFactory(target).getProxyInstance();
System.out.println(proxy.getClass());
//执行代理对象方法
String things = proxy.doThings("0000000");
System.out.println(things);
}
}
  • jdk动态代理对象必须实现接口
  • cglib使用字节码处理框架ASM,通过生成被代理对象的子类方式实现
  • cglib无法代理final类

设计模式-工厂

设计模式-工厂

  • 是什么

    • 包含简单工厂、工厂方法、抽象工厂
    • 属于创建型设计模式
    • 顾名思义,生产创建对象
  • 解决什么问题

    • 将对象创建与使用解耦
    • 代码扩展性
  • 为什么要使用工厂

    • 复习一下,什么是Solid原则
    • 按照Solid设计原则,添加新功能对代码只加不改,单独加该功能的逻辑实现,同时加对应的工厂,齐活了。当然现实是不是这样,要对更多情况分析取舍
  • 简单工厂,一个工厂生产所有Bean

  • 工厂方法,一个工厂接口,一个Bean对应一个工厂实现类,生产那个Bean使用对应工厂

  • 抽象工厂,多个工厂接口,一类Bean对应一个工厂接口。

线程状态、切换、创建

线程状态、切换、创建

  1. 线程状态

    • New,新建
    • Runnable,可运行状态
    • Running,运行中
    • Block,阻塞中。分为释放锁和不释放锁的阻塞
    • Terminal,结束
  2. 线程切换

    • Thread 静态方法
      • sleep(), 当前线程停止,不释放锁。
      • yield(), 当前线程让出CPU时间片进入可运行状态从新竞争获取CPU时间片
    • Thread对象方法
      • join(), 当前线程等待join()线程结束后再继续,不释放锁
    • Object方法
      • wait(), 等待并释放锁。
      • notify(), notifyAll(),等待状态的线程重新进入Runable状态竞争CPU时间片。
      • 这几个方法需要在加锁的代码中执行,否则会异常。
  3. 线程创建

    • 继承Thread
    • 实现Runnable
    • 实现Callable
    • 线程池

​ 另附Java内存模型笔记

设计模式——准备:Solid设计原则、UML类图、设计模式分类

设计模式——准备:Solid设计原则、UML类图、设计模式分类

1. 导读

设计模式是程序员进阶、面试无法躲避的内容,也是阅读源代码、提升代码质量最重要的内功。

今天下决心好好学一遍设计模式,先做一些准备工作。

  • 记住Solid设计原则,设计原则略抽象,记住名字和含义,在后面学习中细品
  • 学会看UML类图,大部分设计模式的文章都会用UML类图展示设计模式,学会看UML类图有助于看懂别人的文章
  • 记住设计模式分类,以及每个类别下有哪些设计模式,厚的先读薄,脑海有目录和节奏

2. Solid设计原则

1 .单一职责原则(Single Responsibility Principal)

​ 一个类只包含单一职责,有且仅有一个原因使类发生变化。

2.开放封闭原则(Open-Closed Principal)

​ 对扩展开放,对修改封闭。即可扩展,不可修改。需求变更后通过添加类而不是修改类实现。

3.里氏替换原则(Liskov Substitution Principal)

​ 所有使用父类的地方,都可以使用子类替换。

4.接口隔离原则(Interface Segregation Principal)

​ 实现类不应该包含不需要但必须实现的方法。也就是接口功能要足够聚合。

5.依赖倒置原则(Dependency Inversion Principal)

​ 抽象不应该依赖细节,细节要依赖抽象,也就是要面向接口编程而不针对实现编程。

看到这里的各位萌亲,就问你蒙不蒙圈(不蒙圈的应该是大神,左手出门不送),我反正蒙圈了,但大神还是建议我先记住Solid原则,学完23种设计再回来理解。他说“跟产品大大相爱相杀几年后再回来理解设计原则,一定会明白大神们总结的原则有多重要”。

3. UML类图

3.1 类

由类名、属性、操作组成

3.1.1 类名

类的名字,如图中的Employee

3.1.2 属性

类的成员变量,格式

可见性 名称:类型[=默认值]

可见性符号

  • public: +
  • private: -
  • protected: #
  • package: ~

3.1.3 操作

类的方法,格式

可见性 名称(参数列表)[:返回类型]

可见性同属性

3.2 接口

接口由名字、操作组成,名字上部有<>做标识符

3.3 关系

  • 关联:成员变量
    • 双向关联:直线
    • 单向关联:直线+箭头
    • 自关联:直线+箭头
  • 继承:继承抽象类,空心三角形+直线表示
  • 泛华:继承非抽象类,空心三角形+直线表示
  • 实现:实现接口,空心三角形+虚线表示
  • 聚合:成员变量,不是强依赖(部门与员工),空心菱形箭头+直线表示
  • 组合:成员变量,强依赖(公司与部门),实心菱形箭头+直线表示
  • 依赖:构造函数、方法入参。

4. 时序图

  • 时序图(Sequence Diagram)按照时间顺序显示对象之间交互,包括角色(Actor)、对象(Object)、生命线(Lifeline)、控制焦点(Focus of control)、消息(Message)

  • 角色(Actor)

  • 对象:对象名+类名

  • 生命线:对象向下延伸的虚线

  • 控制焦点:生命线上的矩形,执行操作

  • 消息:

    同步消息,实线+实心箭头

    异步消息,实线+箭头

    返回消息,虚线+箭头

  • 自关联消息,对象内部方法调用

  • Combined Fragments

Alternative fragment(denoted “alt”) 与 if…then…else对应
Option fragment (denoted “opt”) 与 Switch对应
Parallel fragment (denoted “par”) 表示同时发生
Loop fragment(denoted “loop”) 与 for 或者 Foreach对应

5. 设计模式分类

  • 创建型
    • 单例
    • 工厂方法
    • 抽象工厂
    • 建造者
    • 原型
  • 结构型
    • 适配器
    • 桥接
    • 装饰器
    • 组合
    • 外观
    • 享元
    • 代理
  • 行为型
    • 模版方法
    • 命令
    • 迭代器
    • 观察者
    • 中介者
    • 备忘录
    • 解释器
    • 状态
    • 策略
    • 职责链
    • 访问者

设计模式——单例

设计模式——单例

  • 是什么

    • 单例是创建型设计模式
    • 在内存中只有一个实例化对象
    • 全局只有一个访问点获取实例化对象
  • 解决什么问题

    • 对象重复创建,浪费开销
    • 内存有多个相同的对象,浪费空间
  • 实现方式分类

    • 饿汉模式,类初始化完创建对象
    • 懒汉模式,第一次调用时创建对象
  • 饿汉模式实现方式

    • 私有化构造方法

    • 初始化私有的static final属性为实例化对象

    • 对外暴露getInstance静态方法

    • 代码示例

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      class Singleton {
      private static final Singleton INSTANCE = new Singleton();

      private Singleton() {
      }

      public static Singleton getInstance() {
      return INSTANCE;
      }
      }
  • 懒汉模式实现方式

    • getInstance方法加synchronized,防止多线程同时调用创建多个对象。所有获取单例实例化对象都会加锁。单例、线程安全、性能差。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      class Singleton {
      private static Singleton INSTANCE = null;

      private Singleton() {
      }

      public static synchronized Singleton getInstance() {
      if (INSTANCE == null) {
      INSTANCE = new Singleton();
      }
      return INSTANCE;
      }
      }
    • 双重检查锁,只有在INSTANCE为空的时候加锁,常规获取单例不加锁,避免频繁加锁;给INSTANCE添加volatile,多线程其他线程可以获取INSTANCE最新创建情况。单例、线程安全、性能好。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      class Singleton {
      private volatile static Singleton INSTANCE = null;

      private Singleton() {
      }

      public static Singleton getInstance() {
      if (INSTANCE == null) {
      synchronized (Singleton.class) {
      if (INSTANCE == null) {
      INSTANCE = new Singleton();
      }
      }
      }
      return INSTANCE;
      }
      }
    • 静态内部类,利用类加载机制保障单例及线程安全。单例、线程安全、性能好。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      class Singleton {
      private static class SingletonHolder {
      private static final Singleton INSTANCE = new Singleton();
      }

      private Singleton() {
      }

      public static final Singleton getInstance() {
      return SingletonHolder.INSTANCE;
      }
      }
    • 枚举,枚举类型及枚举变量在JVM中都是唯一的,同时枚举类型在序列化和反序列化在JVM也是同一个,可以保证绝对单例。序列化单例、线程安全、性能好。

      1
      2
      3
      public enum Singleton {
      INSTANCE;
      }
  • 关联知识点

    • 类加载过程,加载->验证->准备->解析->初始化,初始化会对静态变量赋值,由此可知饿汉模式类加载完成对象即创建完。

      • 加载:字节码加载到内存
      • 验证:验证格式
      • 准备:静态变量分配内存,初始化默认值
      • 解析:静态链接,符号引用转换为直接引用
      • 初始化:静态变量赋值,静态方法区执行
    • 静态内部类,静态内部类在使用的时候才会加载,类加载会初始化static变量。

    • 线程安全,内存模型,volatile,synchronized,设计知识点略多,以后单独写。

    • 枚举特性,枚举类型及枚举变量在JVM中都是唯一的。在序列化的时候Java将枚举对象的name属性输出到结果中,反序列化的时候通过java.lang.Enum的valueOf方法来根据名字查找枚举对象。