为了方便框架主版本的升级和系统的解耦抽象,现基于SpringBrick进行插件化开发。

# 准备工作

  1. 确认主框架JeecgBoot框架版本,目前3.7.0版本经测试可以正常运行,推测SpringBoot2.X的版本均可支持。
  2. SpringBrick使用版本为3.1.2
  3. JDK版本为1.8

# 确定主程序及主包

按照JeecgBoot的代码架构设计,以单体为例,主程序定为jeecg-module-system下的jeecg-system-start。故,主包即为org.jeecg。因此,插件包名应为其他名称,或者为org.jeecg.xxx

# jeecg-system-startpom.xml添加spring-brick依赖。

<dependency>
    <groupId>com.gitee.starblues</groupId>
    <artifactId>spring-brick</artifactId>
    <version>${spring-brick.version}</version>
</dependency>

<build>
    <plugins>
        <plugin>
            <groupId>com.gitee.starblues</groupId>
            <artifactId>spring-brick-maven-packager</artifactId>
            <configuration>
                <mode>main</mode>
                <mainConfig>
                    <mainClass>org.jeecg.JeecgSystemApplication</mainClass>
                    <packageType>jar</packageType>
                </mainConfig>
                <includeSystemScope>false</includeSystemScope>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

# jeecg-system-startapplication.yaml添加spring-brick配置项。

plugin:
  runMode: dev
  # 主包路径,和上面的对应
  mainPackage: org.jeecg
  pluginPath:
    # 示例插件路径
    - ~/jeecg-plugins

# 修改jeecg-system-startJeecgSystemApplication.java启动文件。

// 原代码

package org.jeecg;

import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
* 单体启动类
* 报错提醒: 未集成mongo报错,可以打开启动类上面的注释 exclude={MongoAutoConfiguration.class}
*/
@Slf4j
@SpringBootApplication
public class JeecgSystemApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(JeecgSystemApplication.class);
    }

    public static void main(String[] args) throws UnknownHostException {
        ConfigurableApplicationContext application = SpringApplication.run(JeecgSystemApplication.class, args);
        Environment env = application.getEnvironment();
        String ip = InetAddress.getLocalHost().getHostAddress();
        String port = env.getProperty("server.port");
        String path = oConvertUtils.getString(env.getProperty("server.servlet.context-path"));
        log.info("\n----------------------------------------------------------\n\t" +
                "Application Jeecg-Boot is running! Access URLs:\n\t" +
                "Local: \t\thttp://localhost:" + port + path + "/\n\t" +
                "External: \thttp://" + ip + ":" + port + path + "/\n\t" +
                "Swagger文档: \thttp://" + ip + ":" + port + path + "/doc.html\n" +
                "----------------------------------------------------------");
    }

}

// 修改后
package org.jeecg;

import com.gitee.starblues.loader.launcher.SpringBootstrap;
import com.gitee.starblues.loader.launcher.SpringMainBootstrap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.net.UnknownHostException;

/**
 * 单体启动类
 * 报错提醒: 未集成mongo报错,可以打开启动类上面的注释 exclude={MongoAutoConfiguration.class}
 */
@Slf4j
@SpringBootApplication
public class JeecgSystemApplication implements SpringBootstrap {

    public static void main(String[] args) throws UnknownHostException {
        SpringMainBootstrap.launch(JeecgSystemApplication.class, args);
        log.info("Application Jeecg-Boot is running!");
    }

    @Override
    public void run(String[] args) {
        SpringApplication.run(JeecgSystemApplication.class, args);
    }
}

修改说明:

  1. 取消了对SpringBootServletInitializer的继承,并删除configure方法,否则在maven package时会报错。
  2. 添加了对SpringBootstrap的实现。
  3. main方法通过SpringMainBootstrap.launch进行启动。
  4. 重写了run方法。

# 主程序其他配置

  • 鉴权处理,根据测试结果来看,插件中是不支持@IgnoreAuth注解的。所以插件中需要放权的请求要在ShiroConfig.java进行处理。但是,如果每个插件需要放权都要在主程序配置,并重启一次,则失去了插件部分意义,故推荐添加配置filterChainDefinitionMap.put("/plugins/**/ignoreAuth/**", "anon");。插件中,把需要放权的请求统一放在ignoreAuth接口下。这样,就可以不再需要调整主程序的鉴权配置了。

# 插件开发

目录结构设计推荐(插件建立一个父模块进行管理,根据上面的配置,我们的父模块就是jeecg-plugins):

-example
    - example-main
        - pom.xml
    - plugins
        - example-plugin1
            - pom.xml
        - example-plugin2
            - pom.xml
        - pom.xml
    - pom.xml

插件父模块的pom.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>jeecg-boot-parent</artifactId>
        <groupId>org.jeecgframework.boot</groupId>
        <version>3.7.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>jeecg-plugins</artifactId>

    <packaging>pom</packaging>

    <!-- 两个子插件 -->
    <modules>
        <module>plugins-example-1</module>
        <module>plugins-example-2</module>
    </modules>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- 插件统一SpringBoot依赖版本 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.7.18</version>
        </dependency>

        <!-- 加入对主程序的依赖,注意是provided范围 -->
        <dependency>
            <groupId>org.jeecgframework.boot</groupId>
            <artifactId>jeecg-system-start</artifactId>
            <version>${project.version}</version>
            <scope>provided</scope>
        </dependency>

        <!-- 添加SpringBrick依赖,注意插件依赖的是spring-brick-bootstrap,和主程序的不一样 -->
        <dependency>
            <groupId>com.gitee.starblues</groupId>
            <artifactId>spring-brick-bootstrap</artifactId>
            <version>${spring-brick.version}</version>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>com.gitee.starblues</groupId>
                    <artifactId>spring-brick-maven-packager</artifactId>
                    <version>${spring-brick.version}</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

插件子模块的pom.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.jeecgframework.boot</groupId>
        <artifactId>jeecg-plugins</artifactId>
        <version>3.7.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>plugins-example-1</artifactId>

    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>com.gitee.starblues</groupId>
                <artifactId>spring-brick-maven-packager</artifactId>
                <configuration>
                    <!-- 可选项dev, prod -->
                    <mode>${plugin.build.mode}</mode>
                    <pluginInfo>
                        <id>plugins-example-1</id>
                        <!-- 启动文件完整包路径 -->
                        <bootstrapClass>org.jeecg.plugin.ExampleOneApplication</bootstrapClass>
                        <version>1.0.0</version>
                        <provider>Zoneber</provider>
                        <description>示例插件</description>
                        <!-- 配置文件,默认目录resource -->
                        <configFileName>example-config.yaml</configFileName>
                    </pluginInfo>
                    <prodConfig>
                        <packageType>jar</packageType>
                    </prodConfig>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

插件子模块启动文件内容:

package org.jeecg.plugin;

import com.gitee.starblues.bootstrap.SpringPluginBootstrap;
import com.gitee.starblues.bootstrap.annotation.OneselfConfig;
import org.jeecg.JeecgSystemApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@SpringBootApplication
@OneselfConfig(mainConfigFileName = {"application.yml", "application-dev.yml"})
@EnableConfigurationProperties
public class ExampleOneApplication extends SpringPluginBootstrap {

    public static void main(String[] args) {
        // 注意这里加载了主程序的启动类
        new ExampleOneApplication().run(JeecgSystemApplication.class, args);
    }

}

之后对子模块进行mvn clean packagepackage可能会报找不到符号。这时需要对主模块进行build(对主模块右键点击后选择build处理,如果还是报错,则进行rebuild处理)。提示成功后启动主模块,提示插件[xxx@1.0.0]加载成功,即说明插件加载成功。

# 部署

生产环境推荐结构:

-main.jar
-application.yml
-plugins
  -plugin1.jar
  -plugin2.zip
  -plugin3

生产环境application.yml配置:

plugin:
  runMode: prod
  mainPackage: org.jeecg
  # 如果配置是 windows 下路径, mac、linux 自行修改
  pluginPath:
    - /plugins

maven选择prod环境,然后进行package。插件打包完成后,jar包名称默认为xxx-1.0.0-repackage.jar。之后将主程序和插件分别上传,启动主程序,提示插件[xxx@1.0.0]加载成功,即说明插件加载成功。部署全部完成!

# To Be Continued!😎

Last Updated: 8/28/2024, 4:25:42 PM