背景
假设我们有一个 service 模块,但是希望被 2 个不同的项目依赖。
这个 service 实现比较复杂,各种 spring bean 注入之类的。
又应该如何正常使用呢?
本文演示一下。
模块 springboot-invoke-service-noauto
说明
模拟一个普通的服务类
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">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>springboot-invoke-service-noauto</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.14</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
注入类
一个注入了其他类的 service 类
package org.example.springboot.invoke.noauto.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserDal userDal;
public void queryById() {
System.out.println("UserService#queryById");
userDal.selectById();
}
}
打包
mvn clean install
模块 springboot-invoke-app-noauto
模拟调用的地方
引入
引入刚才的依赖
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>springboot-invoke-service-noauto</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
Application#main
package org.example.springboot.invoke.app.noauto;
import org.example.springboot.invoke.noauto.service.UserService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
// 启动时直接调用
UserService userService = ctx.getBean(UserService.class);
userService.queryById();
}
}
效果
此时结果:
2025-09-16 19:28:36.039 INFO 24148 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2025-09-16 19:28:36.046 INFO 24148 --- [ main] o.e.s.invoke.app.noauto.Application : Started Application in 2.378 seconds (JVM running for 2.749)
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.example.springboot.invoke.noauto.service.UserService' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:351)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1175)
at org.example.springboot.invoke.app.noauto.Application.main(Application.java:15)
如何解决?
方式1-指定扫描包
我们指定一下 springboot 的扫描包,包含依赖的地方即可。
@SpringBootApplication(scanBasePackages = "org.example.springboot.invoke.noauto.service")
public class Application {
public static void main(String[] args) {
//...
}
}
效果:
2025-09-16 19:34:02.673 INFO 17536 --- [ main] o.e.s.invoke.app.noauto.Application : Started Application in 2.538 seconds (JVM running for 2.905)
UserService#queryById
UserDal#selectById
方式2-service 包指定为 starter
实现类
作为对比,我们在新建 auto 模块
- UserService.java 实现类似
package org.example.springboot.invoke.service.auto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserDal userDal;
public void queryById() {
System.out.println("UserService#queryById");
userDal.selectById();
}
}
自定义 starter
本 springboot 为 2.x
定义一个扫描的类
package org.example.springboot.invoke.service.auto;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* 自动配置类
* 当 starter 被引入时,会自动扫描指定包下的所有组件
*/
@Configuration
@ComponentScan(basePackages = "org.example.springboot.invoke.service.auto")
public class InvokeServiceAutoConfiguration {
}
指定 spring.factories
指定 springboot 的自动启动策略
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.example.springboot.invoke.service.auto.InvokeServiceAutoConfiguration
打包
当前的项目打包
mvn clean install
测试验证
引入
<dependency>
<groupId>org.example</groupId>
<artifactId>springboot-invoke-service-auto</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
启动
package org.example.springboot.invoke.app.auto;
import org.example.springboot.invoke.service.auto.UserService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
// 启动时直接调用
UserService userService = ctx.getBean(UserService.class);
userService.queryById();
}
}
日志:
2025-09-16 19:46:46.061 INFO 22280 --- [ main] o.e.s.invoke.app.auto.Application : Started Application in 2.528 seconds (JVM running for 2.963)
UserService#queryById
UserDal#selectById
直接正常加载启用。
小结
两种方式都可以。
可以结合自己的场景使用。