-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBreakSingleton.java
176 lines (153 loc) · 5.19 KB
/
BreakSingleton.java
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package other;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import sun.misc.Unsafe;
import java.io.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
/**
* 破坏单例
* <pre>
* enum checkCaller
* reflect F F
* MethodHandle T F
* Serialization F T
* Unsafe T T
* </pre>
*/
public class BreakSingleton {
@BeforeAll
public static void setup() {
// 确保已加载单例
System.out.println(ByCallerCheck.INSTANT);
}
/**
* 枚举法 vs 反射
* 破坏失败
*/
@Test
public void enumVsReflect() throws Throwable {
Constructor<ByEnum> constructor = ByEnum.class.getDeclaredConstructor(String.class, int.class);
constructor.setAccessible(true);
Assertions.assertThrows(IllegalArgumentException.class, () -> constructor.newInstance("INSTANT", 0));
}
/**
* 枚举法 vs 方法句柄
* 破坏成功
*/
@Test
public void enumVsMethodHandle() throws Throwable {
MethodHandle constructor = MethodHandles.lookup().findConstructor(ByEnum.class, MethodType.methodType(void.class, String.class, int.class));
ByEnum instant = (ByEnum) constructor.invokeExact("INSTANT", 0);
Assertions.assertNotSame(ByEnum.INSTANT, instant);
Assertions.assertEquals(1, ByEnum.values().length);
}
/**
* 枚举法 vs 序列化
* 破坏失败
*/
@Test
public void enumVsSerialization() throws Throwable {
Assertions.assertEquals(ByEnum.INSTANT, serialization(ByEnum.INSTANT));
}
/**
* 枚举法 vs Unsafe
* 破坏成功
*/
@Test
public void enumVsUnsafe() throws Exception {
ByEnum instance = (ByEnum) getUnsafe().allocateInstance(ByEnum.class);
Assertions.assertNotSame(ByEnum.INSTANT, instance);
Assertions.assertEquals(1, ByEnum.values().length);
}
/**
* 枚举法单例
*/
enum ByEnum {
INSTANT
}
/**
* 测试检查调用者
*/
@Test
public void check() {
Assertions.assertThrows(IllegalArgumentException.class, ByCallerCheck::new);
}
/**
* 检查调用者 vs 反射
* 破坏失败
*/
@Test
public void checkVsReflect() {
try {
Constructor<ByCallerCheck> constructor = ByCallerCheck.class.getDeclaredConstructor();
constructor.newInstance();
} catch (Exception e) {
Assertions.assertEquals(InvocationTargetException.class, e.getClass());
Assertions.assertEquals(IllegalArgumentException.class, e.getCause().getClass());
}
}
/**
* 检查调用者 vs 方法句柄
* 破坏失败
*/
@Test
public void checkVsMethodHandle() throws Throwable {
MethodHandle constructor = MethodHandles.lookup().findConstructor(ByCallerCheck.class, MethodType.methodType(void.class));
Assertions.assertThrows(IllegalArgumentException.class, () -> {
ByCallerCheck instanct = (ByCallerCheck) constructor.invokeExact();
});
}
/**
* 检查调用者 vs 序列化
* 破坏成功
*/
@Test
public void checkVsSerialization() throws Throwable {
Assertions.assertNotEquals(ByCallerCheck.INSTANT, serialization(ByCallerCheck.INSTANT));
}
/**
* 检查调用者 vs Unsafe
* 破坏成功
*/
@Test
public void checkVsUnsafe() throws Exception {
ByCallerCheck instance = (ByCallerCheck) getUnsafe().allocateInstance(ByCallerCheck.class);
Assertions.assertNotSame(ByCallerCheck.INSTANT, instance);
}
private static Unsafe getUnsafe() throws NoSuchFieldException, IllegalAccessException {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
return (Unsafe) field.get(null);
}
private static <T> T serialization(T src) throws IOException, ClassNotFoundException {
byte[] bytes;
try (ByteArrayOutputStream os = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(os)){
outputStream.writeObject(src);
bytes = os.toByteArray();
}
try (ByteArrayInputStream is = new ByteArrayInputStream(bytes);
ObjectInputStream inputStream = new ObjectInputStream(is)) {
return (T) inputStream.readObject();
}
}
/**
* 检查调用者
* 于构造函数中检查调用者为当前类
*/
static class ByCallerCheck implements Serializable {
static ByCallerCheck INSTANT = new ByCallerCheck();
private ByCallerCheck() {
StackTraceElement[] stackTraceElements = Thread.getAllStackTraces().get(Thread.currentThread());
if (!stackTraceElements[3].getClassName().contains(ByCallerCheck.class.getSimpleName())) {
throw new IllegalArgumentException();
}
}
}
}