feat(测试跟踪): 平台插件跨服务加载和卸载
This commit is contained in:
parent
7b05cf730b
commit
c0acc104de
|
@ -12,5 +12,9 @@ public interface KafkaTopicConstants {
|
||||||
String TEST_PLAN_REPORT_TOPIC = "TEST_PLAN_REPORT_TOPIC";
|
String TEST_PLAN_REPORT_TOPIC = "TEST_PLAN_REPORT_TOPIC";
|
||||||
// 保存当前站点时检查MOCK环境
|
// 保存当前站点时检查MOCK环境
|
||||||
String CHECK_MOCK_ENV_TOPIC = "CHECK_MOCK_ENV_TOPIC";
|
String CHECK_MOCK_ENV_TOPIC = "CHECK_MOCK_ENV_TOPIC";
|
||||||
|
// 上传插件后,通知各服务从 minio 加载插件
|
||||||
|
String PLATFORM_PLUGIN_ADD = "PLATFORM_PLUGIN_ADD";
|
||||||
|
// 删除插件后卸载插件
|
||||||
|
String PLATFORM_PLUGIN_DELETED = "PLATFORM_PLUGIN_DELETED";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,14 @@ package io.metersphere.service;
|
||||||
import io.metersphere.base.domain.PluginExample;
|
import io.metersphere.base.domain.PluginExample;
|
||||||
import io.metersphere.base.domain.PluginWithBLOBs;
|
import io.metersphere.base.domain.PluginWithBLOBs;
|
||||||
import io.metersphere.base.mapper.PluginMapper;
|
import io.metersphere.base.mapper.PluginMapper;
|
||||||
|
import io.metersphere.commons.constants.StorageConstants;
|
||||||
|
import io.metersphere.metadata.service.FileManagerService;
|
||||||
|
import io.metersphere.metadata.vo.FileRequest;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@ -14,10 +18,26 @@ import java.util.List;
|
||||||
public class BasePluginService {
|
public class BasePluginService {
|
||||||
@Resource
|
@Resource
|
||||||
private PluginMapper pluginMapper;
|
private PluginMapper pluginMapper;
|
||||||
|
@Resource
|
||||||
|
FileManagerService fileManagerService;
|
||||||
|
public static final String DIR_PATH = "system/plugin";
|
||||||
|
|
||||||
public List<PluginWithBLOBs> getPlugins(String scenario) {
|
public List<PluginWithBLOBs> getPlugins(String scenario) {
|
||||||
PluginExample example = new PluginExample();
|
PluginExample example = new PluginExample();
|
||||||
example.createCriteria().andScenarioEqualTo(scenario);
|
example.createCriteria().andScenarioEqualTo(scenario);
|
||||||
return pluginMapper.selectByExampleWithBLOBs(example);
|
return pluginMapper.selectByExampleWithBLOBs(example);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public InputStream getPluginResource(String pluginId, String resourceName) {
|
||||||
|
FileRequest request = new FileRequest();
|
||||||
|
request.setProjectId(DIR_PATH + "/" + pluginId);
|
||||||
|
request.setFileName(resourceName);
|
||||||
|
request.setStorage(StorageConstants.MINIO.name());
|
||||||
|
return fileManagerService.downloadFileAsStream(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getPluginJar(String pluginId) {
|
||||||
|
PluginWithBLOBs plugin = pluginMapper.selectByPrimaryKey(pluginId);
|
||||||
|
return getPluginResource(pluginId, plugin.getSourceName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package io.metersphere.remote.service;
|
package io.metersphere.remote.service;
|
||||||
|
|
||||||
import io.metersphere.commons.constants.StorageConstants;
|
|
||||||
import io.metersphere.commons.utils.LogUtil;
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
import io.metersphere.metadata.service.FileManagerService;
|
import io.metersphere.service.BasePluginService;
|
||||||
import io.metersphere.metadata.vo.FileRequest;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
@ -14,19 +12,11 @@ import java.io.OutputStream;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class PlatformPluginService {
|
public class PlatformPluginService {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
FileManagerService fileManagerService;
|
BasePluginService basePluginService;
|
||||||
|
|
||||||
public static final String DIR_PATH = "system/plugin";
|
|
||||||
|
|
||||||
public void getPluginResource(String pluginId, String name, HttpServletResponse response) {
|
public void getPluginResource(String pluginId, String name, HttpServletResponse response) {
|
||||||
FileRequest request = new FileRequest();
|
getImage(basePluginService.getPluginResource(pluginId, name), response);
|
||||||
request.setProjectId(DIR_PATH + "/" + pluginId);
|
|
||||||
request.setFileName(name);
|
|
||||||
request.setStorage(StorageConstants.MINIO.name());
|
|
||||||
InputStream inputStream = fileManagerService.downloadFileAsStream(request);
|
|
||||||
getImage(inputStream, response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getImage(InputStream in, HttpServletResponse response) {
|
public void getImage(InputStream in, HttpServletResponse response) {
|
||||||
|
|
|
@ -39,4 +39,20 @@ public class KafkaTopicConfig {
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public NewTopic platformPluginAddTopic() {
|
||||||
|
return TopicBuilder.name(KafkaTopicConstants.PLATFORM_PLUGIN_ADD)
|
||||||
|
.partitions(partitions)
|
||||||
|
.replicas(replicas)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public NewTopic platformPluginDeleteTopic() {
|
||||||
|
return TopicBuilder.name(KafkaTopicConstants.PLATFORM_PLUGIN_DELETED)
|
||||||
|
.partitions(partitions)
|
||||||
|
.replicas(replicas)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ public class InitListener implements ApplicationRunner {
|
||||||
private PlatformPluginService platformPluginService;
|
private PlatformPluginService platformPluginService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(ApplicationArguments applicationArguments) throws Exception {
|
public void run(ApplicationArguments applicationArguments) {
|
||||||
platformPluginService.loadPlatFormPlugins();
|
platformPluginService.loadPlatFormPlugins();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package io.metersphere.listener;
|
||||||
|
|
||||||
|
|
||||||
|
import io.metersphere.commons.constants.KafkaTopicConstants;
|
||||||
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
|
import io.metersphere.service.PlatformPluginService;
|
||||||
|
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
||||||
|
import org.springframework.kafka.annotation.KafkaListener;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class PlatformPluginListener {
|
||||||
|
public static final String ADD_CONSUME_ID = "system_setting_platform_plugin_add";
|
||||||
|
public static final String DELETE_CONSUME_ID = "system_setting_platform_plugin_delete";
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PlatformPluginService platformPluginService;
|
||||||
|
|
||||||
|
@KafkaListener(id = ADD_CONSUME_ID, topics = KafkaTopicConstants.PLATFORM_PLUGIN_ADD, groupId = "${spring.application.name}")
|
||||||
|
public void handlePluginAdd(ConsumerRecord<?, String> record) {
|
||||||
|
String pluginId = record.value();
|
||||||
|
LogUtil.info("system setting service consume platform_plugin add message, plugin id: " + pluginId);
|
||||||
|
platformPluginService.loadPlugin(pluginId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@KafkaListener(id = DELETE_CONSUME_ID, topics = KafkaTopicConstants.PLATFORM_PLUGIN_DELETED, groupId = "${spring.application.name}")
|
||||||
|
public void handlePluginDelete(ConsumerRecord<?, String> record) {
|
||||||
|
String pluginId = record.value();
|
||||||
|
LogUtil.info("system setting consume platform_plugin delete message, plugin id: " + pluginId);
|
||||||
|
platformPluginService.unload(pluginId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import io.metersphere.api.PluginMetaInfo;
|
||||||
import io.metersphere.base.domain.PluginWithBLOBs;
|
import io.metersphere.base.domain.PluginWithBLOBs;
|
||||||
import io.metersphere.base.domain.ServiceIntegration;
|
import io.metersphere.base.domain.ServiceIntegration;
|
||||||
import io.metersphere.base.mapper.PluginMapper;
|
import io.metersphere.base.mapper.PluginMapper;
|
||||||
|
import io.metersphere.commons.constants.KafkaTopicConstants;
|
||||||
import io.metersphere.commons.constants.PluginScenario;
|
import io.metersphere.commons.constants.PluginScenario;
|
||||||
import io.metersphere.commons.utils.BeanUtils;
|
import io.metersphere.commons.utils.BeanUtils;
|
||||||
import io.metersphere.commons.utils.JSON;
|
import io.metersphere.commons.utils.JSON;
|
||||||
|
@ -18,6 +19,7 @@ import io.metersphere.loader.PlatformPluginManager;
|
||||||
import io.metersphere.request.IntegrationRequest;
|
import io.metersphere.request.IntegrationRequest;
|
||||||
import io.metersphere.utils.PluginManagerUtil;
|
import io.metersphere.utils.PluginManagerUtil;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.kafka.core.KafkaTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
@ -43,6 +45,8 @@ public class PlatformPluginService {
|
||||||
private PluginMapper pluginMapper;
|
private PluginMapper pluginMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private BaseIntegrationService baseIntegrationService;
|
private BaseIntegrationService baseIntegrationService;
|
||||||
|
@Resource
|
||||||
|
private KafkaTemplate<String, String> kafkaTemplate;
|
||||||
|
|
||||||
private PlatformPluginManager pluginManager;
|
private PlatformPluginManager pluginManager;
|
||||||
|
|
||||||
|
@ -52,6 +56,7 @@ public class PlatformPluginService {
|
||||||
}
|
}
|
||||||
String id = UUID.randomUUID().toString();
|
String id = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
PluginManagerUtil.uploadPlugin(id, file);
|
||||||
PluginManagerUtil.loadPlugin(id, pluginManager, file);
|
PluginManagerUtil.loadPlugin(id, pluginManager, file);
|
||||||
PluginMetaInfo pluginMetaInfo = pluginManager.getImplInstance(id, PluginMetaInfo.class);
|
PluginMetaInfo pluginMetaInfo = pluginManager.getImplInstance(id, PluginMetaInfo.class);
|
||||||
|
|
||||||
|
@ -74,6 +79,8 @@ public class PlatformPluginService {
|
||||||
plugin.setCreateUserId(SessionUtils.getUserId());
|
plugin.setCreateUserId(SessionUtils.getUserId());
|
||||||
plugin.setXpack(pluginMetaInfo.isXpack());
|
plugin.setXpack(pluginMetaInfo.isXpack());
|
||||||
plugin.setScenario(PluginScenario.platform.name());
|
plugin.setScenario(PluginScenario.platform.name());
|
||||||
|
// 初始化项目默认节点
|
||||||
|
kafkaTemplate.send(KafkaTopicConstants.PLATFORM_PLUGIN_ADD, id);
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,11 +178,13 @@ public class PlatformPluginService {
|
||||||
public void delete(String id) {
|
public void delete(String id) {
|
||||||
pluginMapper.deleteByPrimaryKey(id);
|
pluginMapper.deleteByPrimaryKey(id);
|
||||||
try {
|
try {
|
||||||
|
// 删除文件
|
||||||
pluginManager.getClassLoader(id).getStorageStrategy().delete();
|
pluginManager.getClassLoader(id).getStorageStrategy().delete();
|
||||||
pluginManager.deletePlugin(id);
|
kafkaTemplate.send(KafkaTopicConstants.PLATFORM_PLUGIN_DELETED, id);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LogUtil.error(e);
|
LogUtil.error(e);
|
||||||
}
|
}
|
||||||
|
this.unload(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Platform getPlatFormInstance(String pluginId, Map IntegrationConfig) {
|
public Platform getPlatFormInstance(String pluginId, Map IntegrationConfig) {
|
||||||
|
@ -237,4 +246,21 @@ public class PlatformPluginService {
|
||||||
.map(PluginMetaInfo::getKey)
|
.map(PluginMetaInfo::getKey)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void loadPlugin(String pluginId) {
|
||||||
|
if (pluginManager.getClassLoader(pluginId) == null) {
|
||||||
|
// 如果没有加载才加载
|
||||||
|
InputStream pluginJar = basePluginService.getPluginJar(pluginId);
|
||||||
|
PluginManagerUtil.loadPlugin(pluginId, pluginManager, pluginJar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 卸载插件
|
||||||
|
* @param pluginId
|
||||||
|
*/
|
||||||
|
public void unload(String pluginId) {
|
||||||
|
pluginManager.deletePlugin(pluginId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,24 +13,54 @@ import java.util.List;
|
||||||
|
|
||||||
public class PluginManagerUtil {
|
public class PluginManagerUtil {
|
||||||
|
|
||||||
public static void loadPlugin(String id, PluginManager pluginManager, MultipartFile file) {
|
/**
|
||||||
if (pluginManager == null) {
|
* 上传到 minio
|
||||||
pluginManager = new PluginManager();
|
* @param id
|
||||||
}
|
* @param file
|
||||||
|
*/
|
||||||
MinioStorageStrategy minioStorageStrategy = new MinioStorageStrategy(id);
|
public static void uploadPlugin(String id, MultipartFile file) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 上传到 sso
|
new MinioStorageStrategy(id).store(file.getOriginalFilename(), file.getInputStream());
|
||||||
minioStorageStrategy.store(file.getOriginalFilename(), file.getInputStream());
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LogUtil.error("上传 jar 包失败: ", e);
|
LogUtil.error("上传 jar 包失败: ", e);
|
||||||
MSException.throwException("上传 jar 包失败: " + e.getMessage());
|
MSException.throwException("上传 jar 包失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载 jar
|
||||||
|
* 并设置存储策略
|
||||||
|
* @param id
|
||||||
|
* @param pluginManager
|
||||||
|
* @param file
|
||||||
|
*/
|
||||||
|
public static void loadPlugin(String id, PluginManager pluginManager, MultipartFile file) {
|
||||||
|
if (pluginManager == null) {
|
||||||
|
pluginManager = new PluginManager();
|
||||||
|
}
|
||||||
// 加载 jar
|
// 加载 jar
|
||||||
try {
|
try {
|
||||||
pluginManager.loadJar(id, file.getInputStream(), minioStorageStrategy);
|
pluginManager.loadJar(id, file.getInputStream(), new MinioStorageStrategy(id));
|
||||||
|
} catch (IOException e) {
|
||||||
|
LogUtil.error("加载jar包失败: ", e);
|
||||||
|
MSException.throwException("加载jar包失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载 jar
|
||||||
|
* 并设置存储策略
|
||||||
|
* @param id
|
||||||
|
* @param pluginManager
|
||||||
|
*/
|
||||||
|
public static void loadPlugin(String id, PluginManager pluginManager, InputStream inputStream) {
|
||||||
|
if (pluginManager == null) {
|
||||||
|
pluginManager = new PluginManager();
|
||||||
|
}
|
||||||
|
// 加载 jar
|
||||||
|
try {
|
||||||
|
pluginManager.loadJar(id, inputStream, new MinioStorageStrategy(id));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LogUtil.error("加载jar包失败: ", e);
|
LogUtil.error("加载jar包失败: ", e);
|
||||||
MSException.throwException("加载jar包失败: " + e.getMessage());
|
MSException.throwException("加载jar包失败: " + e.getMessage());
|
||||||
|
|
|
@ -22,6 +22,11 @@
|
||||||
<artifactId>xpack-interface</artifactId>
|
<artifactId>xpack-interface</artifactId>
|
||||||
<version>${revision}</version>
|
<version>${revision}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<artifactId>metersphere-platform-plugin-sdk</artifactId>
|
||||||
|
<groupId>io.metersphere</groupId>
|
||||||
|
<version>${platform-plugin-sdk.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -23,10 +23,13 @@ public class InitListener implements ApplicationRunner {
|
||||||
private TestReviewTestCaseService testReviewTestCaseService;
|
private TestReviewTestCaseService testReviewTestCaseService;
|
||||||
@Resource
|
@Resource
|
||||||
private CustomFieldResourceCompatibleService customFieldResourceCompatibleService;
|
private CustomFieldResourceCompatibleService customFieldResourceCompatibleService;
|
||||||
|
@Resource
|
||||||
|
private PlatformPluginService platformPluginService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(ApplicationArguments applicationArguments) throws Exception {
|
public void run(ApplicationArguments applicationArguments) throws Exception {
|
||||||
this.initOnceOperate();
|
this.initOnceOperate();
|
||||||
|
platformPluginService.loadPlatFormPlugins();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package io.metersphere.listener;
|
||||||
|
|
||||||
|
import io.metersphere.commons.constants.KafkaTopicConstants;
|
||||||
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
|
import io.metersphere.service.PlatformPluginService;
|
||||||
|
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
||||||
|
import org.springframework.kafka.annotation.KafkaListener;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class PlatformPluginListener {
|
||||||
|
public static final String ADD_CONSUME_ID = "test_track_platform_plugin_add";
|
||||||
|
public static final String DELETE_CONSUME_ID = "test_track_platform_plugin_delete";
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PlatformPluginService platformPluginService;
|
||||||
|
|
||||||
|
@KafkaListener(id = ADD_CONSUME_ID, topics = KafkaTopicConstants.PLATFORM_PLUGIN_ADD, groupId = "${spring.application.name}")
|
||||||
|
public void handlePluginAdd(ConsumerRecord<?, String> record) {
|
||||||
|
String pluginId = record.value();
|
||||||
|
LogUtil.info("track service consume platform_plugin add message, plugin id: " + pluginId);
|
||||||
|
platformPluginService.loadPlugin(pluginId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@KafkaListener(id = DELETE_CONSUME_ID, topics = KafkaTopicConstants.PLATFORM_PLUGIN_DELETED, groupId = "${spring.application.name}")
|
||||||
|
public void handlePluginDelete(ConsumerRecord<?, String> record) {
|
||||||
|
String pluginId = record.value();
|
||||||
|
LogUtil.info("track service consume platform_plugin delete message, plugin id: " + pluginId);
|
||||||
|
platformPluginService.unloadPlugin(pluginId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package io.metersphere.service;
|
||||||
|
|
||||||
|
import io.metersphere.base.domain.PluginWithBLOBs;
|
||||||
|
import io.metersphere.commons.constants.PluginScenario;
|
||||||
|
import io.metersphere.loader.PlatformPluginManager;
|
||||||
|
import io.metersphere.utils.PluginManagerUtil;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public class PlatformPluginService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BasePluginService basePluginService;
|
||||||
|
@Resource
|
||||||
|
private BaseIntegrationService baseIntegrationService;
|
||||||
|
|
||||||
|
private PlatformPluginManager pluginManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有平台插件并加载
|
||||||
|
*/
|
||||||
|
public void loadPlatFormPlugins() {
|
||||||
|
pluginManager = new PlatformPluginManager();
|
||||||
|
List<PluginWithBLOBs> plugins = basePluginService.getPlugins(PluginScenario.platform.name());
|
||||||
|
PluginManagerUtil.loadPlugins(pluginManager, plugins);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadPlugin(String pluginId) {
|
||||||
|
if (pluginManager.getClassLoader(pluginId) == null) {
|
||||||
|
// 如果没有加载才加载
|
||||||
|
InputStream pluginJar = basePluginService.getPluginJar(pluginId);
|
||||||
|
PluginManagerUtil.loadPlugin(pluginId, pluginManager, pluginJar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 卸载插件
|
||||||
|
* @param pluginId
|
||||||
|
*/
|
||||||
|
public void unloadPlugin(String pluginId) {
|
||||||
|
pluginManager.deletePlugin(pluginId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
package io.metersphere.service.plugin;
|
||||||
|
|
||||||
|
import im.metersphere.storage.StorageStrategy;
|
||||||
|
import io.metersphere.commons.constants.StorageConstants;
|
||||||
|
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||||
|
import io.metersphere.metadata.service.FileManagerService;
|
||||||
|
import io.metersphere.metadata.vo.FileRequest;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* jar包静态资源存储策略,存储在 Minio
|
||||||
|
*/
|
||||||
|
public class MinioStorageStrategy implements StorageStrategy {
|
||||||
|
|
||||||
|
private FileManagerService fileManagerService;
|
||||||
|
private String pluginId;
|
||||||
|
|
||||||
|
public static final String DIR_PATH = "system/plugin";
|
||||||
|
|
||||||
|
public MinioStorageStrategy(String pluginId) {
|
||||||
|
this.pluginId = pluginId;
|
||||||
|
fileManagerService = CommonBeanFactory.getBean(FileManagerService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String store(String name, InputStream in) throws IOException {
|
||||||
|
FileRequest request = getFileRequest(name);
|
||||||
|
return fileManagerService.upload(in.readAllBytes(), request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream get(String name) {
|
||||||
|
FileRequest request = getFileRequest(name);
|
||||||
|
return fileManagerService.downloadFileAsStream(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete() throws IOException {
|
||||||
|
FileRequest request = new FileRequest();
|
||||||
|
request.setProjectId(DIR_PATH + "/" + this.pluginId + "/");
|
||||||
|
request.setStorage(StorageConstants.MINIO.name());
|
||||||
|
fileManagerService.delete(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FileRequest getFileRequest(String name) {
|
||||||
|
FileRequest request = new FileRequest();
|
||||||
|
request.setProjectId(DIR_PATH + "/" + this.pluginId);
|
||||||
|
request.setFileName(name);
|
||||||
|
request.setStorage(StorageConstants.MINIO.name());
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package io.metersphere.utils;
|
||||||
|
|
||||||
|
import im.metersphere.loader.PluginManager;
|
||||||
|
import io.metersphere.base.domain.PluginWithBLOBs;
|
||||||
|
import io.metersphere.commons.exception.MSException;
|
||||||
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
|
import io.metersphere.service.plugin.MinioStorageStrategy;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PluginManagerUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载 jar
|
||||||
|
* 并设置存储策略
|
||||||
|
* @param id
|
||||||
|
* @param pluginManager
|
||||||
|
* @param inputStream
|
||||||
|
*/
|
||||||
|
public static void loadPlugin(String id, PluginManager pluginManager, InputStream inputStream) {
|
||||||
|
if (pluginManager == null) {
|
||||||
|
pluginManager = new PluginManager();
|
||||||
|
}
|
||||||
|
// 加载 jar
|
||||||
|
try {
|
||||||
|
pluginManager.loadJar(id, inputStream, new MinioStorageStrategy(id));
|
||||||
|
} catch (IOException e) {
|
||||||
|
LogUtil.error("加载jar包失败: ", e);
|
||||||
|
MSException.throwException("加载jar包失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载插件
|
||||||
|
*/
|
||||||
|
public static void loadPlugins(PluginManager pluginManager, List<PluginWithBLOBs> plugins) {
|
||||||
|
plugins.forEach(plugin -> {
|
||||||
|
String id = plugin.getId();
|
||||||
|
MinioStorageStrategy minioStorageStrategy = new MinioStorageStrategy(id);
|
||||||
|
InputStream inputStream = minioStorageStrategy.get(plugin.getSourceName());
|
||||||
|
try {
|
||||||
|
pluginManager.loadJar(id, inputStream, minioStorageStrategy);
|
||||||
|
} catch (IOException e) {
|
||||||
|
LogUtil.error("初始化插件失败:", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue