操作系统中25 个关键术语及其简要定义,涵盖了操作系统中的核心概念。以下是总结:

  1. 进程与线程:进程是运行中的程序实例,拥有独立内存和资源;线程是进程内的最小执行单位,共享进程内存。
  2. 上下文切换与调度:上下文切换是 CPU 从一个进程/线程切换到另一个;调度由操作系统决定进程/线程的 CPU 时间分配。
  3. 内存管理:包括虚拟内存(允许程序使用超出物理内存的内存)、分页(将内存分为固定大小块)、分段(逻辑划分内存为代码、数据、栈等)、交换(在内存满时将数据移到磁盘)。
  4. 内核与用户空间:内核是操作系统核心,控制内存、进程、I/O;用户空间运行用户程序,受限访问,内核有完全权限。
  5. 中断与系统调用:中断是通知 CPU 处理紧急事件的信号;系统调用是程序请求操作系统执行底层操作。
  6. I/O 与文件系统:I/O 缓冲暂时存储数据以提升性能;文件描述符是操作系统对打开文件或套接字的引用;文件系统管理磁盘上的数据存储与访问。
  7. 并发与同步问题:死锁是进程互相等待资源导致无法继续;竞争条件是系统输出依赖于不可控事件时序。
  8. 信号与进程控制:信号用于通知进程事件(如终止或中断);Fork & Exec 在 Unix 中用于创建新进程和运行程序。
  9. 后台进程与内存问题:守护进程/服务是无需用户交互的后台进程;内存泄漏是分配的内存未释放导致系统变慢;僵尸进程是已终止但仍留在进程表中的进程。
  10. 孤儿进程与启动:孤儿进程是父进程退出后被 init(PID 1)收养的进程;引导加载程序是系统启动时加载操作系统的底层程序。
  11. 文件系统挂载:挂载是将文件系统(如 USB 或外部磁盘)附加到主文件系统树的过程。

对应英文:
20250520143256-2025-05-20

Comment and share

设计模式概览

1. Singleton(单例模式)

类别:创建型(Creational)
说明:确保一个类只有一个实例,并提供全局访问点。
使用场景:当需要确保只有一个实例时(例如,数据库连接、配置管理)。
独特性:限制实例化为单一对象。
常见用例:日志记录、线程池、缓存、配置设置。
UML图:
20250407152734-2025-04-07

2. Factory Method(工厂方法模式)

类别:创建型
说明:提供一个接口用于创建对象,但让子类决定创建对象的具体类型。
使用场景:当对象创建逻辑需要集中管理且动态时。
独特性:将对象创建逻辑封装在一个方法中。
常见用例:框架、库、依赖注入。
UML图:
20250407172852-2025-04-07

3. Abstract Factory(抽象工厂模式)

类别:创建型
说明:创建一组相关或依赖对象的接口,而无需指定具体类。
使用场景:当需要动态创建多个相关对象家族时。
独特性:封装多个工厂方法。
常见用例:跨平台UI工具包、插件架构、创建复杂对象(例如文档、UI组件、HTTP请求)。
UML图:
20250407173021-2025-04-07

4. Builder(建造者模式)

类别:创建型
说明:将对象的构造过程与其表示分离,允许分步创建。
使用场景:当对象构造逻辑复杂时。
独特性:允许分步构建对象。
常见用例:游戏开发(例如克隆敌人)、对象池。
UML图:
20250407173147-2025-04-07

5. Prototype(原型模式)

类别:创建型
说明:通过复制原型实例来创建对象。
使用场景:当对象创建成本高且克隆更高效时。
独特性:通过克隆现有对象创建。
常见用例:游戏开发(例如克隆敌人)、对象池。
UML图:
20250407173247-2025-04-07

6. Adapter(适配器模式)

类别:结构型(Structural)
说明:允许不兼容的接口协同工作。
使用场景:当需要整合遗留代码或第三方API时。
独特性:作为不兼容接口之间的桥梁。
常见用例:连接遗留系统、API兼容性。
UML图:
20250407173343-2025-04-07

7. Decorator(装饰者模式)

类别:结构型
说明:动态地为对象添加行为,而无需修改其类。
使用场景:当需要动态扩展功能时。
独特性:包装对象以添加行为。
常见用例:日志记录、缓存、权限、安全包装。
UML图:
20250407173502-2025-04-07

8. Facade(外观模式)

类别:结构型
说明:为子系统中的一组接口提供统一的接口。
使用场景:当需要简化复杂子系统供客户端使用时。
独特性:隐藏复杂性,提供简单接口。
常见用例:API网关、复杂库、应用程序。
UML图:
20250407173619-2025-04-07

9. Proxy(代理模式)

类别:结构型
说明:为另一个对象提供代理或占位符以控制访问。
使用场景:当需要控制对象访问时(例如,延迟初始化、安全、远程访问)。
独特性:作为受控访问的中间人。
常见用例:延迟加载、安全代理、远程代理。
UML图:
20250407173704-2025-04-07

10. Bridge(桥接模式)

类别:结构型
说明:将抽象与实现解耦,使两者可以独立变化。
使用场景:当抽象和实现需要独立扩展时。
独特性:分离抽象与实现。
常见用例:跨平台GUI框架、设备驱动。
UML图:
20250407173746-2025-04-07

11. Composite(组合模式)

类别:结构型
说明:允许以统一方式处理单个对象和对象组合。
使用场景:当处理树形结构时,组件和组合需要一致处理。
独特性:表示部分-整体层次。
常见用例:文件系统、UI元素。
UML图:
20250407173857-2025-04-07

12. Observer(观察者模式)

类别:行为型(Behavioral)
说明:定义对象间一对多的依赖关系,当状态变化时通知所有依赖对象。
使用场景:当多个对象需要对状态变化做出反应时。
独特性:封装事件驱动通信。
常见用例:事件处理、UI框架、发布-订阅系统。
UML图:
20250407173955-2025-04-07

13. Strategy(策略模式)

类别:行为型
说明:定义一组算法家族,使其可互换。
使用场景:当需要在运行时选择行为时。
独特性:封装可互换算法。
常见用例:排序算法、验证策略。
UML图:
20250407174040-2025-04-07

14. Command(命令模式)

类别:行为型
说明:将请求封装为对象,允许参数化客户端。
使用场景:当需要撤销/重做功能或排队请求时。
独特性:将请求封装为对象。
常见用例:事务系统、撤销/重做、远程操作。
UML图:
20250407174120-2025-04-07

15. State(状态模式)

类别:行为型
说明:允许对象在其内部状态改变时改变行为。
使用场景:当对象行为随状态变化时。
独特性:封装状态特定行为。
常见用例:状态机、工作流管理。
UML图:
20250407174208-2025-04-07

16. Mediator(中介者模式)

类别:行为型
说明:定义一个对象,封装对象间的交互。
使用场景:当需要减少对象间的直接依赖时。
独特性:集中通信。
常见用例:聊天室、事件处理、消息系统。
20250407174241-2025-04-07

17. Chain of Responsibility(责任链模式)

类别:行为型
说明:将请求沿处理者链传递,直到一个处理者处理它。
使用场景:当请求处理者需要动态处理时。
独特性:允许动态处理者委托。
常见用例:日志框架、事件传播。
20250407174319-2025-04-07

18. Template Method(模板方法模式)

类别:行为型
说明:定义算法骨架,子类按步骤填充。
使用场景:当需要强制执行一系列步骤但允许灵活性时。
独特性:封装算法结构。
常见用例:框架、算法定制。
UML图:
20250407174354-2025-04-07

工厂模式名称和别名的由来

  1. 简单工厂(Simple Factory)
    名称由来:被称为“简单”是因为它是最基础的工厂模式,逻辑简单,集中在一个类中。
    别名:有时称为“静态工厂”(Static Factory),因为创建方法通常是静态的。
    原因:它不属于GoF的23种模式,但因其简单性和实用性被广泛使用。
  2. 工厂方法(Factory Method)
    名称由来:强调“方法”这一核心概念,工厂方法模式通过定义一个方法(factoryMethod())来创建对象,具体实现由子类决定。
    别名:有时称为“虚拟构造器”(Virtual Constructor),因为它通过多态性“构造”对象。
    原因:通过方法的多态性实现对象的创建,符合面向对象设计原则。
  3. 抽象工厂(Abstract Factory)
    名称由来:被称为“抽象”是因为它定义了一个抽象接口(或抽象类)来创建一组对象,具体工厂实现由子类提供。
    别名:有时称为“工具包”(Kit),因为它提供了一套创建相关对象的工具。
    原因:它抽象了产品家族的创建,适合需要创建一组相关对象的场景。
    总结
    工厂模式对比:
    简单工厂:最简单,但扩展性差,适合小型系统。
    工厂方法:关注单一产品,扩展性好,符合开放-封闭原则。
    抽象工厂:处理产品家族,适合复杂对象创建场景。
    名称由来:工厂模式名称反映了其核心特点(简单性、方法、抽象性),别名则源于其功能或实现方式(如静态工厂、虚拟构造器、工具包)。
    UML图:通过类图展示了每种设计模式的结构和关系,帮助理解其实现方式和适用场景。

总结

创建型模式(Singleton, Factory Method, Abstract Factory, Builder, Prototype):关注对象创建,解决实例化问题,适合需要动态或复杂对象创建的场景。
结构型模式(Adapter, Decorator, Facade, Proxy, Bridge, Composite):关注对象和类的组织,简化结构或扩展功能,适合处理复杂系统或接口兼容性。
行为型模式(Observer, Strategy, Command, State, Mediator, Chain of Responsibility, Template Method):关注对象间的交互和职责分配,适合动态行为或事件驱动系统。

Comment and share

背景

在Spring 使用注入依赖bean的时候,可能既有使用@Autowired 的字段注入,也可能使用构造器注入。如此场景,在写单元测试的时候使用@Mock的Field就是null了。这是由于Mockito初始化@InjectMocks的被
测试对象时的策略会采用合适的构造器进行实例化,着用@Mock的Field在使用时就是null.

示例代码

OldService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Service
@RequiredArgsConstructor
public class OldService {

@Autowired
private OldService2 oldService;

//add new dependency bean
private final NewService newService;

public void save(SomeObject someObj) {
SomeObject newObject = oldService.handleSome(someObj);
newService.save(newObject);
}
}

OldServiceTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@ExtendWith(MockitoExtension.class)
public class OldServiceTest {
@InjectMocks
private OldService oldService;

@Mock
private OldService2 oldService;

@Mock
private NewService newService;

@Test
void should_save_but_oldService_will_NPE(){
//will NPE
when(oldService.handleSome(someObj)).thenReturn(newObject)
}

}

解决方案

自定义CustomInjectionExtension.java 处理字段注入的mock

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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
    import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Parameter;
import java.util.*;


/**
* JUnit 5 extension that enhances Mockito's dependency injection capabilities.
* This extension locates fields annotated with @InjectMocks and injects @Mock/@Spy objects
* into them, handling null instances and constructor injection automatically.
*/
public class CustomInjectionExtension implements BeforeEachCallback {

@Override
public void beforeEach(ExtensionContext context) throws Exception {
Object testInstance = context.getRequiredTestInstance();

// Find and process the field with @InjectMocks annotation
Field injectMocksField = findInjectMocksField(testInstance);
Object injectMocksInstance = getOrCreateInjectMocksInstance(testInstance, injectMocksField);

// Perform dependency injection
injectDependencies(testInstance, injectMocksInstance, injectMocksField.getType());
}

/**
* Finds the field annotated with @InjectMocks in the test class.
*
* @param testInstance the test class instance
* @return the field annotated with @InjectMocks
* @throws RuntimeException if no field with @InjectMocks is found
*/
private Field findInjectMocksField(Object testInstance) {
return Arrays.stream(testInstance.getClass().getDeclaredFields())
.filter(field -> field.isAnnotationPresent(InjectMocks.class))
.findFirst()
.orElseThrow(() -> new RuntimeException("No @InjectMocks annotation found in test class"));
}

/**
* Gets the existing @InjectMocks instance or creates a new one if null.
*
* @param testInstance the test class instance
* @param injectMocksField the field annotated with @InjectMocks
* @return the instance of the class to inject mocks into
* @throws Exception if instance creation fails
*/
private Object getOrCreateInjectMocksInstance(Object testInstance, Field injectMocksField) throws Exception {
injectMocksField.setAccessible(true);
Object injectMocksInstance = injectMocksField.get(testInstance);

if (injectMocksInstance == null) {
Map<Class<?>, Object> mocksByType = collectMockObjects(testInstance);
injectMocksInstance = createInstanceViaConstructor(injectMocksField.getType(), mocksByType);
injectMocksField.set(testInstance, injectMocksInstance);
}

return injectMocksInstance;
}

/**
* Collects all mock objects from the test class instance.
*
* @param testInstance the test class instance
* @return map of mock objects by their type
* @throws IllegalAccessException if field access fails
*/
private Map<Class<?>, Object> collectMockObjects(Object testInstance) throws IllegalAccessException {
Map<Class<?>, Object> mocksByType = new HashMap<>();

for (Field field : testInstance.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(Mock.class) || field.isAnnotationPresent(Spy.class)) {
field.setAccessible(true);
Object mockObject = field.get(testInstance);

// Create mock object if null
if (mockObject == null) {
mockObject = createMockObject(field);
field.set(testInstance, mockObject);
}

mocksByType.put(field.getType(), mockObject);
}
}

return mocksByType;
}

/**
* Creates a mock or spy object based on field annotations.
*
* @param field the field to create a mock for
* @return created mock or spy object
*/
private Object createMockObject(Field field) {
if (field.isAnnotationPresent(Mock.class)) {
return Mockito.mock(field.getType());
} else {
return Mockito.spy(field.getType());
}
}

/**
* Creates an instance of the target class by finding and using an appropriate constructor.
*
* @param targetClass the class to instantiate
* @param availableMocks map of available mock objects by type
* @return the created instance
* @throws RuntimeException if instance creation fails
*/
private Object createInstanceViaConstructor(Class<?> targetClass, Map<Class<?>, Object> availableMocks) {
Constructor<?>[] constructors = targetClass.getDeclaredConstructors();
Arrays.sort(constructors, (c1, c2) -> c2.getParameterCount() - c1.getParameterCount());

for (Constructor<?> constructor : constructors) {
constructor.setAccessible(true);
Object[] constructorArgs = prepareConstructorArguments(constructor, availableMocks);

try {
return constructor.newInstance(constructorArgs);
} catch (Exception e) {
// Continue to next constructor if this one fails
continue;
}
}

throw new RuntimeException(String.format(
"Could not instantiate %s. No suitable constructor found that can be called with available mocks.",
targetClass.getSimpleName()));
}

/**
* Prepares arguments for a constructor by matching parameter types with available mocks.
*
* @param constructor the constructor to prepare arguments for
* @param availableMocks map of available mock objects by type
* @return array of constructor arguments
*/
private Object[] prepareConstructorArguments(Constructor<?> constructor, Map<Class<?>, Object> availableMocks) {
Parameter[] parameters = constructor.getParameters();
Object[] args = new Object[parameters.length];

for (int i = 0; i < parameters.length; i++) {
Class<?> paramType = parameters[i].getType();
args[i] = findOrCreateMockForType(paramType, availableMocks);
}

return args;
}

/**
* Finds an existing mock for the given type or creates a new one.
*
* @param requiredType the type to find or create a mock for
* @param availableMocks map of available mock objects by type
* @return a mock object compatible with the required type
*/
private Object findOrCreateMockForType(Class<?> requiredType, Map<Class<?>, Object> availableMocks) {
// Try exact type match
Object mock = availableMocks.get(requiredType);
if (mock != null) {
return mock;
}

// Try assignable types (interfaces, superclasses)
mock = availableMocks.entrySet().stream()
.filter(entry -> requiredType.isAssignableFrom(entry.getKey()))
.map(Map.Entry::getValue)
.findFirst()
.orElse(null);

if (mock != null) {
return mock;
}

// Create new mock if no match found
mock = Mockito.mock(requiredType);
availableMocks.put(requiredType, mock);
return mock;
}

/**
* Injects mock dependencies into the target instance.
*
* @param testInstance the test class instance
* @param targetInstance the instance to inject mocks into
* @param targetClass the class of the target instance
* @throws Exception if injection fails
*/
private void injectDependencies(Object testInstance, Object targetInstance, Class<?> targetClass) throws Exception {
Map<Class<?>, Object> mocksByType = collectMockObjects(testInstance);

for (Map.Entry<Class<?>, Object> entry : mocksByType.entrySet()) {
Class<?> mockType = entry.getKey();
Object mockObject = entry.getValue();

injectMockIntoCompatibleFields(targetInstance, mockType, mockObject);
}
}

/**
* Injects a mock object into all compatible fields of the target instance.
*
* @param targetInstance the instance to inject mocks into
* @param mockType the type of the mock object
* @param mockObject the mock object to inject
* @throws IllegalAccessException if field access fails
*/
private void injectMockIntoCompatibleFields(Object targetInstance, Class<?> mockType, Object mockObject)
throws IllegalAccessException {
Class<?> targetClass = targetInstance.getClass();

for (Field field : getAllFields(targetClass)) {
if (isTypeCompatible(field.getType(), mockType)) {
field.setAccessible(true);
if (field.get(targetInstance) == null) {
field.set(targetInstance, mockObject);
}
}
}
}

/**
* Checks if two types are compatible for injection.
*
* @param fieldType the type of the field
* @param mockType the type of the mock
* @return true if the types are compatible, false otherwise
*/
private boolean isTypeCompatible(Class<?> fieldType, Class<?> mockType) {
return fieldType.isAssignableFrom(mockType) || mockType.isAssignableFrom(fieldType);
}

/**
* Gets all fields from a class and its superclasses.
*
* @param clazz the class to get fields from
* @return array of all fields
*/
public Field[] getAllFields(Class<?> clazz) {
List<Field> allFields = new ArrayList<>();
Class<?> currentClass = clazz;

while (currentClass != null) {
allFields.addAll(Arrays.asList(currentClass.getDeclaredFields()));
currentClass = currentClass.getSuperclass();
}

return allFields.toArray(new Field[0]);
}
}

OldServiceTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@ExtendWith({MockitoExtension.class, CustomInjectionExtension.class})
public class OldServiceTest {
@InjectMocks
private OldService oldService;

@Mock
private OldService2 oldService;

@Mock
private NewService newService;

@Test
void should_save_but_oldService_will_NPE(){
//will Fixed
when(oldService.handleSome(someObj)).thenReturn(newObject)
}

}

Comment and share

  • page 1 of 1
Author's picture

Topsion

Fullstack Developer


Coder


Xi'an China