SpringBoot项目打包成jar包供第三方调用方式

本文参考:

JAVA SpringBoot 项目打成jar包供第三方引用自动配置(Spring发现)解决方案 - 蒋具宏 - 博客园 (cnblogs.com)

自己实现一个jar包(starter组件)_自己写的jar包-CSDN博客

1.调用者手动配置 basePackages

1.1 第三方jar项目

新建一个 springboot maven 工程,要被使用者导入的核心 Bean 代码如下:

package com.jxz.thirdpartyjar1;

import org.springframework.stereotype.Component;

@Component // 别的项目 @ComponentScan(basePackages={}) 可以扫描得到
public class ThirdPartyJarBeanOne {
    public void test() {
        System.out.println("我是外部方法");
    }
}

然后用 maven LifeStyle 方法中的 install 方法进行打包,会看到控制台输出如下

[INFO] Installing /Users/gabriel/Desktop/CodingUper/ThirdPartyJar1/pom.xml to /Users/gabriel/Environment/apache-maven-3.6.3/maven_repo/com/jxz/ThirdPartyJar1/0.0.1-SNAPSHOT/ThirdPartyJar1-0.0.1-SNAPSHOT.pom
[INFO] Installing /Users/gabriel/Desktop/CodingUper/ThirdPartyJar1/target/ThirdPartyJar1-0.0.1-SNAPSHOT.jar to /Users/gabriel/Environment/apache-maven-3.6.3/maven_repo/com/jxz/ThirdPartyJar1/0.0.1-SNAPSHOT/ThirdPartyJar1-0.0.1-SNAPSHOT.jar

/Users/gabriel/Environment/apache-maven-3.6.3/maven_repo/ 是我本地 maven 仓库的地址(在公司里就需要打到公网的 maven 仓库里去,这样子别人才能看到),这个时候其实就可以去去看到在 0.0.1-SNAPSHOT 下面就打出了 ThirdPartyJar1-0.0.1-SNAPSHOT.jar 包,这个 jar 包后续还需要导入别的项目使用

Bug:

有可能会碰到 maven 打包问题(repackage failed: Unable to find main class),原因是第三方 jar 包可能缺少主类,需要在 maven-plugin 处进行修改,参考 maven 打包问题(repackage failed: Unable to find main class)-CSDN博客

直接修改maven插件,改用apache的maven插件,配置如下:

 <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
</plugin>

1.2 调用方项目

1.2.1 调用方配置

新建一个项目 Import3Party1 进行实验,先在 maven 中导入刚刚的 jar 包依赖

<dependency>
    <groupId>com.jxz</groupId>
    <artifactId>ThirdPartyJar1</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

为了便于测试,我这里再引入下 SpringBoot-web 的依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

1.2.2 项目测试

配置方式:在启动类或者能够被 Spring 发现的 Configuration 类上增加 @ComponentScan(basePackages = {xxx 第三方 jar 包路径}),确保第三方Bean能够被扫描到

在这里插入图片描述

调用方启动类:

package com.jxz.import3party1;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
// 启动类这里就需要带上第三方 jar bean 的路径 com.jxz.thirdpartyjar
@ComponentScan(basePackages = {"com.jxz.thirdpartyjar1","com.jxz.controller"})
public class Import3Party1Application {

    public static void main(String[] args) {
        SpringApplication.run(Import3Party1Application.class, args);
    }

}

调用方测试类:

package com.jxz.controller;

import com.jxz.thirdpartyjar1.ThirdPartyJarBeanOne;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2024/2/3
 */
@Controller
public class Import3Party1Controller {
    @Autowired
    ThirdPartyJarBeanOne thirdPartyJarBeanOne;

    @GetMapping(value = "/test1")
    @ResponseBody
    public String testApi(@RequestParam String accountId) {
        thirdPartyJarBeanOne.test();
        return accountId;
    }
}

经测试,输出正确

2.调用方通过注解的方式引入

其实就是把更多的工作交给 jar 包生成者去做了,通过注解的方式将 Bean 的导入进行了优化

2.1 第三方jar项目

在这里插入图片描述

要被使用者导入的核心 Bean 代码:

package com.jxz.thirdpartyjar2;

import org.springframework.stereotype.Component;

/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2024/2/3
 */
@Component
public class ThirdPartyJarBeanTwo {
    public void test() {
        System.out.println("我是外部方法");
    }
}

配置类:

package com.jxz.thirdpartyjar2.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2024/2/3
 */
@Configuration
@ComponentScan(basePackages = {"com.jxz.thirdpartyjar2"}) // 扫描注册 bean
public class ThirdPartyJarBeanTwoConfig {
}

第三方通过注解,自动注册配置类,重点在于 @Import(xxx.class):

package com.jxz.thirdpartyjar2.annotation;

import com.jxz.thirdpartyjar2.config.ThirdPartyJarBeanTwoConfig;
import org.springframework.context.annotation.Import;

import java.lang.annotation.*;

/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2024/2/3
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import({ThirdPartyJarBeanTwoConfig.class})
public @interface ThirdPartyJarBeanTwoAnnotation {
}

2.2 调用方项目

2.2.1 调用方配置

新建一个项目 Import3Party2 进行实验,先在 maven 中导入刚刚的 jar 包依赖

<dependency>
    <groupId>com.jxz</groupId>
    <artifactId>ThirdPartyJar2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

为了便于测试,我这里再引入下 SpringBoot-web 的依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2.2.2 项目测试

配置方式:只需要引入注解,注解上面都带上了自动导入的要素,会将原先使用者需要扫描的 Bean 自动扫描

在这里插入图片描述

调用方启动类:

package com.jxz.import3party2;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

@SpringBootApplication
// 启动类这里不需要带上第三方 jar bean 的路径,但是为了便于测试,引入 Controller 路径
@ComponentScan(basePackages = {"com.jxz.controller"})
public class Import3Party2Application {

    public static void main(String[] args) {
        SpringApplication.run(Import3Party2Application.class, args);
    }

}

测试类:

package com.jxz.controller;


import com.jxz.thirdpartyjar2.ThirdPartyJarBeanTwo;
import com.jxz.thirdpartyjar2.annotation.ThirdPartyJarBeanTwoAnnotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2024/2/3
 */
@Controller
// 这里就是第三方 jar 包中定义的注解
@ThirdPartyJarBeanTwoAnnotation
public class Import3Party2Controller {
    // 可以导入注入的 bean 使用
    @Autowired
    ThirdPartyJarBeanTwo thirdPartyJarBeanTwo;

    @GetMapping(value = "/test2")
    @ResponseBody
    public String testApi(@RequestParam String accountId) {
        thirdPartyJarBeanTwo.test();
        return accountId;
    }
}

经测试,输出正确

  • 上面的第三方 jar 项目 @ThirdPartyJarBeanTwoAnnotation 注解上是通过 @Import 一个配置文件,配置文件中再通过 @ComponentScan 将 Bean 扫描注册的,其实可以简化一点,直接在注解上 @Import 相关的类(复杂点还可以导入 ImportSelector 实现类或者 ImportBeanDefinitionRegistrar 实现类)。

第三方注解修改如下:

package com.jxz.thirdpartyjar2.annotation;

import com.jxz.thirdpartyjar2.ThirdPartyJarBeanTwo;
import org.springframework.context.annotation.Import;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2024/6/3
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import({ThirdPartyJarBeanTwo.class})
public @interface ThirdPartyJarBeanTwoAnnotation2 {
}

@Import 的 Bean 也可以去掉 @Component 注解了

package com.jxz.thirdpartyjar2;

import org.springframework.stereotype.Component;

/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2024/2/3
 */
public class ThirdPartyJarBeanTwo {
    public void test() {
        System.out.println("我是外部方法");
    }
}

调用方直接引入注解 @ThirdPartyJarBeanTwoAnnotation2 即可

package com.jxz.controller;

import com.jxz.thirdpartyjar2.ThirdPartyJarBeanTwo;
import com.jxz.thirdpartyjar2.annotation.ThirdPartyJarBeanTwoAnnotation2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2024/6/3
 */
@Controller
@ThirdPartyJarBeanTwoAnnotation2
public class Import3Party2Controller2 {
    @Autowired
    private ThirdPartyJarBeanTwo thirdPartyJarBeanTwo;

    @GetMapping(value = "/test2/version2")
    @ResponseBody
    public String testApi(@RequestParam String accountId) {
        thirdPartyJarBeanTwo.test();
        return accountId;
    }
}

3.SpringBoot Starter 方式

3.1 第三方jar项目

第三方 jar 项目仍然参考前面的配置类,只是配置类的引入方式从注解上的 @Import 变为了 SpringBoot Starter 自动装配.

此方法最关键的为 resources/META-INF/spring.factories 文件(特别注意:SpringBoot3更改了配置方式),当项目启动时,Spring会扫描所有jar包下面的 spring.factories 文件(SpringBoot3替换为了spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports *文件,参考下面说明*),进行相应的自动配置处理,其中写入类的全路径名

小于 SpringBoot 3 配置方法(resources/META-INF/spring.factories)

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.jxz.thirdpartyjar3.config.ThirdPartyJarBeanThreeConfig

其中 org.springframework.boot.autoconfigure.EnableAutoConfiguration 代表自动配置的 key,即代表需要自动配置哪些类,\ 可以理解为一个换行符,则该行下面的每行当做一个参数

第二行则为我们刚才看见的配置类的全路径,如果需要 Spring 自动配置多个类,我们依行写入它的全路径即可

大于等于SpringBoot3配置用法(resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports)

com.jxz.thirdpartyjar3.config.ThirdPartyJarBeanThreeConfig

在这里插入图片描述
当做完这一步,我们的组件就可以打包了,然后使用者只需要引入我们的jar包,Spring 就会在启动时对我们 spring.factories 中的所有配置类进行自动配置。
要被使用者导入的核心 Bean 代码:

package com.jxz.thirdpartyjar3;

import org.springframework.stereotype.Component;

/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2024/2/3
 */
@Component
public class ThirdPartyJarBeanThree {
    public void test() {
        System.out.println("我是外部方法");
    }
}

配置类:

同第二种配置方式

package com.jxz.thirdpartyjar3.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2024/2/3
 */
@Configuration
@ComponentScan(basePackages = {"com.jxz.thirdpartyjar3"}) // 扫描注册 bean
public class ThirdPartyJarBeanThreeConfig {
}

主要是自动扫描文件 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:

com.jxz.thirdpartyjar3.config.ThirdPartyJarBeanThreeConfig

3.2 调用方项目

3.2.1 调用方配置

新建一个项目 Import3Party3 进行实验,先在 maven 中导入刚刚的 jar 包依赖

<dependency>
    <groupId>com.jxz</groupId>
    <artifactId>ThirdPartyJar3</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

为了便于测试,我这里再引入下 SpringBoot-web 的依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

不需要额外的配置,只需要上面引入了 pom 就能够自动扫描

3.2.2 项目测试

启动类:

package com.jxz.import3party3;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = {"com.jxz.controller"}) // 还是需要能够扫描到 controller 的,默认扫描 com.jxz.import3party3
public class Import3Party3Application {

    public static void main(String[] args) {
        SpringApplication.run(Import3Party3Application.class, args);
    }

}

测试类:

package com.jxz.controller;

import com.jxz.thirdpartyjar3.ThirdPartyJarBeanThree;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2024/2/3
 */
@Controller
public class Import3Party3Controller {
    // 可以直接导入注入的 bean 使用
    @Autowired
    ThirdPartyJarBeanThree thirdPartyJarBeanThree;

    @GetMapping(value = "/test3")
    @ResponseBody
    public String testApi(@RequestParam String accountId) {
        thirdPartyJarBeanThree.test();
        return accountId;
    }
}

经测试,输出正确

  • 11
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

互联网民工蒋大钊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值