为什么叫Summer
因为夏天到了 :D
特点
- 使用了JPMS作为模块化的基础
- 可以通过配置文件动态的选择启动哪些模块
- 使用SPI的方式进行创建对象,并能自动注入所需要的服务(也可以选择手动)
- 自动注入模块配置文件
项目结构
项目主要分为三个模块
- 核心模块: 对模块和提供者进行定义,发现加载模块和注入
- 启动模块: 引导模块
- 工具模块: 基础工具
使用方式
模块
首先需要定义模块类,例如仓库中的例子A模块,默认情况下,你只要定义类就行.
除了模块定义之外还需要定义该模块应能提供的服务1
2
3
4
5
6public interface ModuleAService extends Service {
void startAService();
Integer doSomeWork();
}
以下是ModuleA的module-info.java1
2
3
4
5
6
7
8module module.a {
requires summer.modular;
exports io.whileaway.code.summer.example.module.a.services;
exports io.whileaway.code.summer.example.module.a;
provides ModuleDefine with ModuleA; // 需要进行指定实现了ModuleDefine 便于SPI使用
}
提供者
我们先来看A模块的第一个提供者A11
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// 需要指定是哪个模块的提供者
public class A1Provider extends ModuleProvider {
ModuleConfig config = new ProviderConfigA();
public A1Provider() {
// 传入lookup是为了service的自动注入
// 在Java模块系统中由于模块之间的限制,可以使用这种方式进行传递
// 虽然可以使用open 但那样的话感觉给的权限就过大了
super(MethodHandles.lookup());
}
public ModuleConfig providerConfig() {
return config; // 返回持有的config对象用于框架自动注入配置
}
}
如果不需要config可以不创建config对象,创建的config对象需要继承ModuleConfig类
创建配置类中的成员变量可以仅指定getter方法
配置类是从application.yml中进行读取配置1
2
3
4
5
6module.a:
selector: ${A_S:provider.a1} # 当前选择使用a1
provider.a1: # 针对提供者a1的配置 以下的配置都会被自动填入config中
name: providerA1
provider.a2: # 针对提供者a2的配置
name: providerA2
接下来创建模块定义接口的实现1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 继承于模块中的接口
public class ModuleAServiceImpl implements ModuleAService {
// 成员变量config会自动进行注入 后面会有注入其他模块中类的方法
private ProviderConfigA config;
public void startAService() {
System.out.println("module A config name: " + config.getName());
}
public Integer doSomeWork() {
return 42;
}
}
以下是a1提供者module-info.java1
2
3
4
5
6
7
8
9
10
11
12
13import io.whileaway.code.summer.example.provider.a1.A1Provider;
import io.whileaway.code.summer.example.provider.a1.ModuleAServiceImpl;
import io.whileaway.code.summer.modular.ModuleProvider;
import io.whileaway.code.summer.modular.Service;
module provider.a1 {
requires summer.modular;
requires module.a;
requires lombok;
provides Service with ModuleAServiceImpl; // 表明模块中需要被发现的服务
provides ModuleProvider with A1Provider; // 标识模块中的提供者类
}
当提供者之间出现依赖的情况
在样例代码中有提供者B1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 所要求的模块列表
public class BProvider extends ModuleProvider {
ModuleConfig config = new ProviderConfigB();
public BProvider() {
super(MethodHandles.lookup());
}
public ModuleConfig providerConfig() {
return config;
}
public void start() throws ServiceException { // 模块启动后所要执行的方法
getService(ModuleBService.class).startBService();
}
}
这时B的服务中若有定义A的服务并标注注入注解就能自动的注入1
2
3
4
5
6
7
8
9
10
11
12
13
14public class ModuleBServiceImpl implements ModuleBService {
private ProviderConfigB config;
private ModuleAService aService;
public void startBService() {
aService.startAService();
System.out.println("B config: " + config.getName());
System.out.println("in B Service get A service number: " + aService.doSomeWork());
}
}