## 简介
通常我们启动工程都是使用`SpringApplication.run(Application.class, args);`来启动,但是JPower工程已经设置了很多自定义参数用来集成不同组件,故采用`SpringApplicationBuilder`,将其封装进一个核心类中进行拓展,以便于所有微服务调用启动之用。
## 自定义启动器
* 如需要自行新增自定义参数在其核心启动类中的新增即可。
* 启动器核心代码如下
~~~
/**
* @ClassName JpowerApplication
* @Description TODO 项目启动器
* @Author Ding
* @Date 2020-08-02 17:04
* @Version 1.0
*/
@Slf4j
public class JpowerApplication {
/**
* @Author 郭丁志
* @Description //TODO 项目启动
* @Date 18:16 2020-08-02
* @Param appName 项目模块名称,必须与client表的code值相同
* @return org.springframework.context.ConfigurableApplicationContext
**/
public static ConfigurableApplicationContext run(String appName, Class source, String... args) {
SpringApplicationBuilder builder = createSpringApplicationBuilder(appName, source, args);
return builder.run(args);
}
private static SpringApplicationBuilder createSpringApplicationBuilder(String appName, Class source, String[] args) {
Assert.hasText(appName, "[appName]服务名不能为空");
SpringApplicationBuilder builder = new SpringApplicationBuilder(source);
//读取环境变量配置
ConfigurableEnvironment environment = new StandardEnvironment();
MutablePropertySources propertySources = environment.getPropertySources();
propertySources.addFirst(new SimpleCommandLinePropertySource(args));
propertySources.addLast(new MapPropertySource("systemProperties", environment.getSystemProperties()));
propertySources.addLast(new SystemEnvironmentPropertySource("systemEnvironment", environment.getSystemEnvironment()));
// 获取配置的环境变量
String[] activeProfiles = environment.getActiveProfiles();
// 判断环境:dev、test、prod
List<String> profiles = Arrays.asList(activeProfiles);
List<String> presetProfiles = new ArrayList(Arrays.asList("dev", "test", "prod"));
presetProfiles.retainAll(profiles);
List<String> activeProfileList = new ArrayList<>(presetProfiles);
String profile;
if (activeProfileList.isEmpty()) {
// 默认dev开发
profile = AppConstant.DEV_CODE;
activeProfileList.add(profile);
builder.profiles(profile);
} else if (activeProfileList.size() == 1) {
profile = activeProfileList.get(0);
} else {
// 同时存在dev、test、prod环境抛出错误
throw new RuntimeException("同时存在环境变量:[" + StringUtils.arrayToCommaDelimitedString(activeProfiles) + "]");
}
Properties props = System.getProperties();
props.setProperty("spring.application.name", appName);
props.setProperty("spring.profiles.active", profile);
props.setProperty("logging.config", "classpath:logback-spring.xml");
props.setProperty("jpower.is-local", String.valueOf(isLocalDev()));
props.setProperty("spring.main.allow-bean-definition-overriding", "true");
//nacos配置
props.setProperty("spring.cloud.nacos.discovery.server-addr", "${jpower.".concat(profile).concat(".nacos.server-addr:}"));
props.setProperty("spring.cloud.nacos.config.server-addr", "${jpower.".concat(profile).concat(".nacos.server-addr:}"));
props.setProperty("spring.cloud.nacos.discovery.namespace", "${jpower.".concat(profile).concat(".nacos.namespace:}"));
props.setProperty("spring.cloud.nacos.config.namespace", "${jpower.".concat(profile).concat(".nacos.namespace:}"));
//sentinel配置
props.setProperty("spring.cloud.sentinel.transport.dashboard", "${jpower.".concat(profile).concat(".sentinel.dashboard:}"));
//seata启用,默认关闭
props.setProperty("seata.enabled", "${jpower.seata.enabled:false}");
List<DeployService> deployServiceList = new ArrayList<>();
ServiceLoader.load(DeployService.class).forEach(deployServiceList::add);
deployServiceList.stream().sorted(Comparator.comparing(DeployService::getOrder)).collect(Collectors.toList())
.forEach(deployService -> deployService.launcher(builder, appName, profile));
log.warn("{}项目已启动,运行环境:{}",appName,profile);
return builder;
}
/**
* @Author 郭丁志
* @Description //TODO 判断是否为本地开发环境
* @Date 18:18 2020-08-02
* @return boolean
**/
public static boolean isLocalDev() {
String osName = System.getProperty("os.name");
return StringUtils.hasText(osName) && !(AppConstant.OS_NAME_LINUX.equals(osName.toUpperCase()));
}
}
~~~
## 如何使用
* 以`jpower-system`模块启动为例,代码如下
~~~
/**
* @ClassName SpringBootStartApplication
* @Description TODO 系统管理入口
* @Author Ding
* @Date 2020-02-24 18:41
* @Version 1.0
*/
@EnableTransactionManagement
@SpringBootApplication
@EnableFeignClients
public class SystemStartApplication {
public static void main(String[] args) {
JpowerApplication.run(AppConstant.JPOWER_SYSTEM,SystemStartApplication.class,args);
}
}
~~~
* 可以看到非常简约,与原生并没有太多变化,只是多了一个appName的参数,此参数正是做为服务名注册到注册中心,用于和其他服务分类。
## 扩展启动参数
* 有时我们可能单独一个模块需要额外加载自己的配置,而其他模块则无需这些配置,jpower也想到了这种情况,我们只需要在所在模块继承`DeployService`接口并实现`launcher`方法即可。
示例代码如下:
~~~
/**
* @ClassName DeployService
* @Description TODO 扩展启动参数配置
* @Author 郭丁志
* @Date 2020-08-19 16:22
* @Version 1.0
*/
public class DeployServiceImpl implements DeployService {
@Override
public void launcher(SpringApplicationBuilder builder, String appName, String profile) {
Properties props = System.getProperties();
props.setProperty("spring.cloud.nacos.config.file-extension", NacosConstants.FILE_EXTENSION);
props.setProperty("spring.cloud.nacos.config.shared-configs[0].data-id", NacosConstants.DATA_ID);
props.setProperty("spring.cloud.nacos.config.shared-configs[0].refresh", NacosConstants.CONFIG_REFRESH);
props.setProperty("spring.cloud.nacos.config.shared-configs[0].group", NacosConstants.CONFIG_GROUP);
props.setProperty("spring.cloud.nacos.config.shared-configs[1].data-id", NacosConstants.nacosPublicDataId(profile));
props.setProperty("spring.cloud.nacos.config.shared-configs[1].refresh", NacosConstants.CONFIG_REFRESH);
props.setProperty("spring.cloud.nacos.config.shared-configs[1].group", NacosConstants.CONFIG_GROUP);
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
~~~
* 看到这里,可能大家也会有疑问,启动参数、公共参数写到DeployService里,这相当于是写死了,那我如果要修改,还得全部重新打包,这岂不是很不方便?我们的理念就是一次打包,处处运行,所以这些问题都能轻松解决
* 若是直接命令行运行,我们可以通过命令行的形式这么覆盖配置
> java -jar app.jar --spring.profiles.active=test --server.port=8080
* 若是通过docker-compose启动容器,那么我们可以这么覆盖配置
~~~
jpower-system:
image: "192.168.0.10:99/jpower/system-server:1.0.1-SNAPSHOT"
privileged: true
volumes:
- /docker/skywalking/agent/:/jpower/skywalking/agent/
environment:
- JAVA_TOOL_OPTIONS=-javaagent:/jpower/skywalking/agent/skywalking-agent.jar
- SW_AGENT_COLLECTOR_BACKEND_SERVICES=skywalking-oap:11800
restart: always
command:
--spring.profiles.active=${PROFILE}
--spring.cloud.nacos.discovery.ip=${ADMIN_IP}
--spring.cloud.nacos.discovery.port=${ADMIN_PORT}
--spring.cloud.sentinel.transport.port=${ADMIN_SENTINEL_PORT}
--spring.cloud.nacos.config.namespace=${NACOS_NAMESPACE}
--spring.cloud.nacos.config.group=${NACOS_GROUP}
--spring.cloud.nacos.config.server-addr=${NACOS_SERVER_ADDR}
--spring.cloud.nacos.discovery.server-addr=${NACOS_SERVER_ADDR}
--spring.cloud.sentinel.transport.dashboard=${SENTINEL_DASHBOARD_ADDR}
--sentinel.heartbeat.client.ip=${ADMIN_IP}
networks:
- jpower_net
~~~
## 注意点
* 自定义启动器已经将环境变量也设置好,无需再到`application.yml`中配置`spring.profiles.active`再打包。
* 打包后的app启动时,若不设置`spring.profiles.active`,则默认为`dev`,如需设置只需在启动的命令行加上即可。
`java -jar app.jar --spring.profiles.active=prod --server.port=2333`
* 无论是打包了fat-jar,还是打包了docker,都只需要打包一次,搭配上注册中心就可以运行在任何设定好的环境中,这样一来就实现了`一次打包,处处运行`的理念。
* 开发中,如果要修改为非`DEV`环境,可参考如下配置。
![](https://img.kancloud.cn/d6/f4/d6f4ef28212ccd93bd441a2ee32090a9_2214x1424.png)
- 序言
- 开发环境准备
- 环境要求
- 环境安装
- 基础环境安装
- Nacos安装
- Sentinel安装
- 插件安装
- 导入工程
- 运行工程
- 工程测试
- JPower特性
- 系统启动器
- 多终端令牌认证
- 系统鉴权
- 鉴权API
- 鉴权配置
- API权限配置
- 接口放行配置
- 数据权限
- redis缓存
- 动态网关
- 聚合文档
- SaaS多租户
- 概念
- 使用
- Xss防注入
- 日志记录
- 操作日志&错误日志
- SQL打印
- feign请求日志&配置
- gateway日志
- 服务日志打印
- 导入导出
- 字典查询
- 系统文件上传下载
- 接口监控
- 代码生成器
- 配置文件共享
- Mybatis过滤器
- 配置说明
- 高级实战
- nacos动态配置
- Seata分布式事务
- 简介
- docker启动
- 微服务配置
- 微服务远程调用
- 声明式服务调用 Feign
- 熔断机制 Sentinel
- sentinel流控
- 简介
- 微服务配置
- 配置nacos对接
- APM监控&链路追踪
- 简介
- 安装
- 微服务接入
- SpringBootAdmin监控
- ELK分布式日志追踪系统
- ELK简介
- ELK一键部署
- 微服务日志对接ELK
- JPower-Chat
- 配置说明
- 生产部署
- docker部署
- docker安装
- docker-compose安装
- harbor安装
- 部署步骤
- 版本升级
- 1.0.1升级到2.0.0
- 2.0.0升级到2.0.2
- 2.0.2升级2.1.0
- 2.1.0升级到2.1.1
- 2.1.1升级到2.1.2
- 2.1.2升级到2.1.4