为什么叫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());
    }
}