使用jarslink实现版本隔离

JarsLink (原名Titan) 是一个基于JAVA的模块化开发框架,它提供在运行时动态加载模块(一个JAR包)、卸载模块和模块间调用的API。也是阿里巴巴的开源项目之一 https://github.com/alibaba/jarslink,目前在微贷事业群广泛使用。

github例子地址:https://github.com/zhuquanwen/jarslink-demo

使用介绍参见:https://yq.aliyun.com/articles/555104

一、编写两个jar包版本
1、引入jarslink-api等依赖(这里用的gradle,maven的类似)

dependencies {
    compile ('com.alipay.jarslink:jarslink-api:1.5.0.20180213')
    testCompile group: 'junit', name: 'junit', version: '4.12'
    compile group: 'com.iscas', name: 'base', version: '2.0-RELEASE'
    compile ('org.springframework:spring-web:5.1.6.RELEASE')
    compile ('org.springframework:spring-context:5.1.6.RELEASE')
}

这里的base 就是一个接口而已,没什么特别的,只是个例子

2、resources下创建/META-INF/spring/xxx.xml文件




    


3、编写action

@Component
public class TTT implements Action, TTInterface {
    @Autowired
    private Use use;
    public TTT() {
        /*System.out.println("2.5");*/

    }
    @Override
    public void ttt() {
        use.t();
    }

    @Override
    public String execute(ModuleConfig actionRequest) {
        ttt();
        return "success";
    }

    @Override
    public String getActionName() {
        return "ttt";
    }
}
@Component
public class Use {
    public void t() {
        System.out.println("2.9-ttt");
    }
 }

TTInterface就是base内的一个接口
这里在测试方法中输出版本号,方便测试版本的隔离有没有成功

4、打两个jar包,更改一下版本号,和上一步的输出,我这里用的gradle的showJar插件,打包后传入了本地maven私服

group 'com.iscas'
version '2.9-RELEASE'

//上传至nexus
publishing {
    publications {
        maven(MavenPublication) {
            groupId project.group
            artifactId project.name
            version project.version
            //若是war包,就写components.web,若是jar包,就写components.java
//            from components.java
            artifact shadowJar
        }
    }
    repositories {
        maven {

            if (project.version.endsWith('-SNAPSHOT')) {
                url = "http://192.168.100.88:8081/repository/maven-snapshots/"
            } else {
                url = "http://192.168.100.88:8081/repository/maven-releases/"
            }

            credentials {
                username 'admin'
                password 'admin123'
            }
        }
    }
}

二、调用

1、构建一个springboot项目,将两个jar拷贝至resources下META-INF
2、注册ModuleConfig

public class ModuleRefreshSchedulerImpl extends AbstractModuleRefreshScheduler {
    @Override
    public List queryModuleConfigs() {
        return ImmutableList.of(buildModuleConfig()/*, buildModuleConfig2()*/);
    }

    public static ModuleConfig buildModuleConfig() {
        URL demoModule = Thread.currentThread().getContextClassLoader().getResource("META-INF/demo-2.8-RELEASE.jar");
        ModuleConfig moduleConfig = new ModuleConfig();
        //通过该方法构建的配置都是使用注解形式扫描bean的
//        String scanBase = "com.alipay.jarslink.main";
        moduleConfig.setOverridePackages(Arrays.asList("com.iscas.demo"));
        moduleConfig.setName("demo");
        moduleConfig.setEnabled(true);
        moduleConfig.setVersion("2.8");
//        moduleConfig.setProperties(ImmutableMap.of("lalala", new Object()));
        moduleConfig.setModuleUrl(ImmutableList.of(demoModule));
        return moduleConfig;
    }

    public static ModuleConfig buildModuleConfig2() {
        URL demoModule = Thread.currentThread().getContextClassLoader().getResource("META-INF/demo-2.9-RELEASE.jar");

        ModuleConfig moduleConfig = new ModuleConfig();
        moduleConfig.setName("demo");
        moduleConfig.setEnabled(true);
        moduleConfig.setVersion("2.9");
//        moduleConfig.setProperties(ImmutableMap.of("svnPath", new Object()));
        moduleConfig.setModuleUrl(ImmutableList.of(demoModule));
        return moduleConfig;
    }
}

3、注册bean

@Configuration
public class BeanConfig {

    @Bean
    public ModuleLoader moduleLoader() {
        return new ModuleLoaderImpl();
    }
    @Bean
    public ModuleManager moduleManager() {
        return new ModuleManagerImpl();
    }

    @Bean
    public ModuleRefreshSchedulerImpl moduleRefreshScheduler() {
        ModuleRefreshSchedulerImpl moduleRefreshScheduler = new ModuleRefreshSchedulerImpl();
        ModuleManager moduleManager = moduleManager();
        ModuleLoader moduleLoader = moduleLoader();
        moduleRefreshScheduler.setModuleLoader(moduleLoader);
        moduleRefreshScheduler.setModuleManager(moduleManager);
        return moduleRefreshScheduler;
    }
}

4、测试调用

@RestController
public class Controller {
    @Autowired
    private ModuleRefreshSchedulerImpl moduleRefreshScheduler;
    @Autowired
    private ModuleManager moduleManager;
    @Autowired
    private ModuleLoader moduleLoader;

    @GetMapping("/test/{version}")
    public String test(@PathVariable String version) {
        List moduleConfigs = moduleRefreshScheduler.queryModuleConfigs();
        Module runModule = moduleManager.find("demo");
        if (runModule == null || runModule.getActions().size() == 0 || !Objects.equals(version, runModule.getVersion())) {
            if (Objects.equals("2.8", version)) {
                runModule = moduleLoader.load(ModuleRefreshSchedulerImpl.buildModuleConfig());
                Module removedModule = moduleManager.register(runModule);
            } else if (Objects.equals("2.9", version)) {
                runModule = moduleLoader.load(ModuleRefreshSchedulerImpl.buildModuleConfig2());
                Module removedModule = moduleManager.register(runModule);
            } else {
                throw new RuntimeException("版本错误");
            }
        }
        String result = runModule.doAction("ttt", new ModuleConfig());
        return result;
    }
}

5、结果
http://localhost:8080/test/2.8
http://localhost:8080/test/2.9
使用jarslink实现版本隔离_第1张图片

你可能感兴趣的:(java)