Skip to content

Commit 18b16a6

Browse files
committed
add spaces
1 parent 166e6f5 commit 18b16a6

File tree

1 file changed

+21
-1
lines changed

1 file changed

+21
-1
lines changed

1. Fundamentals/2023-06-16-微服务架构-Microservice-Driven Architecture.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ categories: [VSCode, Fundamentals]
55
---
66

77
# What is a Microservice?
8-
![image](https://github.com/Bistard/vscode-source-code-analysis/assets/38385498/3b1bb539-ad13-42f0-8cf1-66a52afdc6a4)
8+
<div align="center">
9+
<img src="https://github.com/Bistard/vscode-source-code-analysis/assets/38385498/3b1bb539-ad13-42f0-8cf1-66a52afdc6a4" alt="image" />
10+
</div>
911

1012
Microservice-driven architecture, or simply microservices, is an architectural style that structures an application as a collection of loosely coupled services.
1113

@@ -50,6 +52,7 @@ export class ApplicationInstance extends Disposable implements INotaInstance {
5052

5153
## Microservices Depends on Microservices
5254
Similarly, microservices are not special classes, they can also depend on other microservices as well. As an example, the following `MainWindowService` also depends on all sorts of different microservices:
55+
5356
```ts
5457
class MainWindowService implements IMainWindowService {
5558
constructor(
@@ -66,6 +69,7 @@ class MainWindowService implements IMainWindowService {
6669
From a framework perspective, I can construct `MainWindowService` as follows:
6770
* Regardless of the specific microservice instance passed through the framework, as long as that instance implements the corresponding interface, the system will function seamlessly.
6871
* For instance, as long as `FileService`, `TestFileService`, and `NullFileService` have all implemented the interface `IFileService`, the system will operate without issues.
72+
6973
```ts
7074
// normal case
7175
const mainWindowService = new MainWindowService(
@@ -106,6 +110,7 @@ Let's address some potential questions that might arise so far:
106110
* `InstantiationService` is a concrete solution to achieve the **Dependency Injection (DI) principle**.
107111

108112
To illustrate how `InstantiationService` operates, consider the following API example:
113+
109114
```ts
110115
// initialization (acting as DI)
111116
const instantiationService = new InstantiationService();
@@ -124,6 +129,7 @@ Don’t worry, I will explain these concepts to you step by step.
124129

125130
## 1. What Is a Dependency Tree?
126131
A dependency tree represents a hierarchical relationship between different modules (or classes). Recall the previous example, `ApplicationInstance`, its dependency tree would look like the following:
132+
127133
```
128134
ApplicationInstance
129135
├─ IInstantiationService
@@ -138,6 +144,7 @@ ApplicationInstance
138144
├─ IMainLifecycleService
139145
└─ IEnvironmentService
140146
```
147+
141148
## 2. How Do We Determine a Dependency Tree?
142149
Following the earlier example, where `MainWindowService` depends on `IFileService`. We can draw a few conclusions about `IFileService`:
143150
* `IFileService` serves as an abstraction. `IFileService` as an interface, is a syntax sugar from TypeScript, which only exists on compile-time.
@@ -152,6 +159,7 @@ VSCode provide a useful function, `createDecorator`, which creates a unique deco
152159
> Sidenote: In TypeScript, a decorator is essentially a function.
153160
154161
* The decorator created by `createDecorator`, acts like an identifier, which can be stored in DI to make a connection between the microservice and the concrete class implementation as follows:
162+
155163
```ts
156164
// fileService.ts
157165
const IFileService = createDecorator('file-service'); // note: a variable in TypeScript can have the same name as an interface.
@@ -170,6 +178,7 @@ const instantiationService = new InstantiationService();
170178
// DI registration (⭐)
171179
instantiationService.register(IFileService, new FileService()); // we've seen this line of code before
172180
```
181+
173182
The decorator performs two functionalities in our cases:
174183
1. First, since the decorator is a variable, thus it exists in run-time, it can be used in our DI system (`InstantiationService`). As previously mentioned, It establishes a connection between the abstraction concept (`IFileService`) and a concrete implementation (our case is `FileService`), as we've just done in the above example.
175184
* At line 16, the DI system now recognizes an abstraction (`IFileService`), and a way to construct its corresponding class (`FileService`).
@@ -181,6 +190,7 @@ The decorator performs two functionalities in our cases:
181190
182191
### 2.2 Build a Dependency Tree at Runtime Using Decorator
183192
Let’s see what can this decorator be used for:
193+
184194
```ts
185195
class MainWindowService implements IMainWindowService {
186196
constructor(
@@ -194,24 +204,28 @@ class MainWindowService implements IMainWindowService {
194204
}
195205
}
196206
```
207+
197208
A decorator, as the name tells, is used to add something extra to a class parameter. It does one key job:
198209
* It marks the decorated class (in this case, `MainWindowService`), which depends on the parameter (e.g. `IFileService`), at runtime.
199210

200211
> You do not need to worry about the black magic behind the decorators created by createDecorator. It works and works elgantly, I can promise you.
201212
202213
> To give you a better illustration of what decorators do, let us consider the following class:
214+
>
203215
> ```ts
204216
> class TestService {
205217
> constructor() {}
206218
> }
207219
> ```
208220
> Currently, the class does not depend on anything. We can use an imagined function `getDependencyTreeFor`:
221+
>
209222
> ```ts
210223
> const dependencies = getDependencyTreeFor(TestService);
211224
> console.log(dependencies);
212225
> // []
213226
> ```
214227
> Now, we let `TestService` depends on two other services:
228+
>
215229
> ```ts
216230
> class TestService{
217231
> constructor(
@@ -221,6 +235,7 @@ A decorator, as the name tells, is used to add something extra to a class parame
221235
> }
222236
> ```
223237
> If we print out its dependency tree again, we will see different things:
238+
>
224239
> ```ts
225240
> const dependencies = getDependencyTreeFor(TestService);
226241
> console.log(dependencies);
@@ -245,6 +260,7 @@ A decorator, as the name tells, is used to add something extra to a class parame
245260
> ]
246261
> */
247262
> ```
263+
>
248264
> **In essence, the decorator's job is to create and store the above dependency tree at runtime.**
249265
250266
Continuing our example, the complete dependency tree of `MainWindowService` will look like the following:
@@ -275,6 +291,7 @@ Now, we already covered a way to create a dependency tree for our classes. We fi
275291
For every dependency tree, its tree leaf (the dependency that depends on nothing) cannot be constructed automatically. **It means the leaf must be provided by ourselves**. We call this the registration process.
276292

277293
It is quite simple, recall our previous example:
294+
278295
```ts
279296
// initialization (acting as DI)
280297
const instantiationService = new InstantiationService();
@@ -290,6 +307,7 @@ instantiationService.register(IFileService, new FileService());
290307
291308
### 3.2 Assembly Factory - `InstantiationService`
292309
Here comes the final step of constructing a microservice: **assembling**. This is done inside the method `createInstance`:
310+
293311
```ts
294312
// construct the service (by its corresponding dependency tree)
295313
const mainWindowService = instantiationService.createInstance(MainWindowService);
@@ -306,6 +324,7 @@ After all the dependencies have been constructed, the `InstantiationService` use
306324
Recall the second step when assembling in `InstantiationService`, where it checks 'if the dependency has not been constructed yet'.
307325

308326
One might wonder how a microservice can be registered into the DI system without actually constructing one. For that, VSCode introduce a utility tool named `SyncDescriptor`:
327+
309328
```ts
310329
export class SyncDescriptor<T> {
311330

@@ -321,6 +340,7 @@ export class SyncDescriptor<T> {
321340
}
322341
```
323342
With the help of `SyncDescriptor`, we can achieve lazy loading when registering a microservice:
343+
324344
```ts
325345
// initialization (acting as DI)
326346
const instantiationService = new InstantiationService();

0 commit comments

Comments
 (0)