前言
在本系列博客中,我们将深入探讨 Spring Boot 项目结构的各个方面,并探讨如何利用这些结构来构建健壮、可扩展的应用程序。通过深入了解 Spring Boot 项目结构,我们可以更好地利用 Spring Boot 的优势,提高开发效率,降低维护成本,并构建出高质量的应用程序。
在本系列的第一部分中,我们将首先介绍 Spring Boot 项目结构的基本布局,包括主要的目录和文件,以及它们各自的作用。通过了解项目结构,我们可以更好地组织我们的代码,并充分利用 Spring Boot 提供的功能和特性。
一、新建项目,结构如下
1、项目依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><!-- 这个父模块是springboot的父级依赖,它提供了默认的Java版本、编码设置、插件管理、以及Maven依赖的版本号管理等功能,因此在项目中引入先关starter的时候就不在需要指定版本号--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.17</version><relativePath/> <!-- lookup parent from repository --></parent><!-- 当前项目的GAV坐标以及名称和描述 --><groupId>edu.nf</groupId><artifactId>ch01</artifactId><version>0.0.1-SNAPSHOT</version><name>ch01</name><description>ch01</description><!-- Java版本 --><properties><java.version>11</java.version></properties><!-- 依赖--><dependencies><!-- 这是springboot核心starter,也就是核心的启动器,它包含了起步所需要的依赖,自动化配置、日志、YAML配置功能,所以没有它springboot无法正常工作--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- springboot集成单元测试的环境 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><!-- 这个插件专门用于将springboot应用打包成jar或者war文件 --><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><image><builder>paketobuildpacks/builder-jammy-base:latest</builder></image><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>
这些依赖都不用我们自己加,在新建项目的时候选择。
这个 Maven POM 文件定义了一个基于 Spring Boot 的 Java 项目的配置和依赖。其中包括以下关键部分:
parent
元素指定了当前项目的父级依赖为spring-boot-starter-parent
,版本号为 2.7.17。这意味着该项目将继承 Spring Boot Starter Parent 提供的默认配置和依赖管理。
groupId
、artifactId
和version
元素定义了当前项目的坐标信息,分别表示项目的组织ID、项目ID和版本号。
properties
元素中定义了 Java 版本为 11。
dependencies
元素列出了当前项目所依赖的库,包括了spring-boot-starter
、lombok
和spring-boot-starter-test
等。
build
元素中配置了用于将 Spring Boot 应用打包成 JAR 或 WAR 文件的插件,这里使用了spring-boot-maven-plugin
插件,并设置了一些相关参数,如镜像构建器和排除某些依赖等。通过这些配置,你可以快速搭建一个基于 Spring Boot 的 Java 项目,而无需关注大量繁琐的配置和依赖管理。
二、Ch01Application 类
@SpringBootApplication
public class Ch01Application {/*** springboot 程序入口** SpringApplication 的 run 方法运行后会初始化一个 IOC 容器* 我们可以从这个容器中获取我们想要的 Bean* @param args*/public static void main(String[] args) {SpringApplication.run(Ch01Application.class, args);}}
这段代码是一个典型的 Spring Boot 应用程序的入口类。让我来解释一下:
@SpringBootApplication
注解标注在该类上,它是 Spring Boot 提供的一个组合注解,包括了@Configuration
、@EnableAutoConfiguration
和@ComponentScan
注解。通过这个注解,Spring Boot 将自动扫描当前类所在包以及子包中的组件,并对它们进行自动配置。
Ch01Application
类中的main
方法是程序的入口点。在这个方法中,调用了SpringApplication.run
方法,传入了当前类和命令行参数args
。这将启动 Spring 应用程序,并初始化一个 IOC 容器,其中包含了所有被@Component
、@Service
、@Repository
等注解标识的 Bean。通过初始化 IOC 容器,我们可以从中获取我们想要的 Bean,并开始执行我们的业务逻辑。
总的来说,这段代码是一个标准的 Spring B
oot 应用程序的入口类,负责启动 Spring 应用程序并初始化相关的组件和 Bean。
那我们就是实现一个简单的dao和service的调用,不使用 mybatis.
三、dao层
1、UserDao
public interface UserDao {void save();}
2、UserDaoImpl
@Repository
@Slf4j
public class UserDaoImpl implements UserDao {@Overridepublic void save() {log.info("insert into user_info.... ");}
}
这段代码定义了一个
UserDaoImpl
类,它实现了一个UserDao
接口,并使用了@Repository
注解进行标识。@Repository
注解是 Spring 框架提供的一种组件扫描注解,用于标识一个 DAO(数据访问对象)组件。该类中只实现了一个
save()
方法,方法体内部打印了一条日志,记录了插入用户信息的操作。在实际应用中,我们通常会在这个方法中编写对数据库的增、删、改、查等操作。使用
@Slf4j
注解可以自动生成日志记录器,无需手动创建。@Slf4j
注解是 Lombok 提供的一种简化代码的注解,它可以自动为类生成一个日志记录器变量log
,并且自动引入org.slf4j.LoggerFactory
类作为日志框架的实现。通过以上代码,我们可以看到 Spring Boot 在整合其他框架时的便利性,如使用
@Repository
注解来标识 DAO 组件,使用 Lombok 的@Slf4j
注解来简化日志记录器的创建,让我们能够更加专注于业务逻辑的实现。
四、service层
1、UserService
public interface UserService {void add();}
2、UserServiceImpl
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {private final UserDao userDao;@Overridepublic void add() {userDao.save();}}
五、在 Ch01Application 调用 service 的方法
前面我们讲到SpringApplication 的 run 方法运行后会初始化一个 IOC 容器 我们可以从这个容器中获取我们想要的 Bean。我们在 dao 和 service中都是用了装配注解,那我们现在就来从容器中拿出来使用。
@SpringBootApplicationpublic class Ch01Application {/*** springboot 程序入口** SpringApplication 的 run 方法运行后会初始化一个 IOC 容器* 我们可以从这个容器中获取我们想要的 Bean* @param args*/public static void main(String[] args) {ApplicationContext context = SpringApplication.run(Ch01Application.class, args);UserService service = context.getBean(UserService.class);service.add();}}
运行效果:
成功的调用到了 service 中 add() 方法,大家有没有发现我们现在使用 springboot ,我们并没有写任何的配置类,也没有使用任何的扫描注解?那为什么还能够调用到 dao 和 service 的方法呢?
六、详解 Ch01Application 类
@SpringBootApplication// 指定默认的扫描包路径
//@SpringBootApplication(scanBasePackageClasses = "xxx.xxxx.aa")
public class Ch01Application {/*** springboot 程序入口** SpringApplication 的 run 方法运行后会初始化一个 IOC 容器* 我们可以从这个容器中获取我们想要的 Bean* @param args*/public static void main(String[] args) {ApplicationContext context = SpringApplication.run(Ch01Application.class, args);UserService service = context.getBean(UserService.class);service.add();}}
这是 springboot 的核心启动类(同时也是一个配置类),运行整个 springboot 项目,在这个类上面有一个很重要的注解为 @SpringBootApplication 它其实是一个复合注解,包含了 @Configuration、@ComponentScan
@EnableAutoConfiguration(自动配置注解)
在启动这个类的时候他会有一个默认的扫描机制,是从当前启动类所在的包, 以及所有的子包进行扫描来专配所有带有注解的Bean,因此这个启动类通常放在最外层的父级包目录下。当然也可以改变这个默认扫描的机制,通过 scanBasePackages 属性来指定即可。在
Ch01Application
类中,我们使用了@SpringBootApplication
注解来标记这个类是一个 Spring Boot 应用程序的入口点。此外,我们还定义了一个main
方法,用于运行应用程序并初始化 IOC 容器。在
main
方法中,我们使用SpringApplication.run()
方法来运行应用程序,并将Ch01Application.class
作为参数传递给它。这个方法会自动扫描并加载应用程序中所有的 Spring 组件,并启动内嵌的 Tomcat 服务器。同时,它也会根据类路径下的配置文件来自动配置应用程序,包括数据库连接、日志记录、缓存等常见功能。在
main
方法中,我们还通过ApplicationContext
接口获取了一个 IOC 容器的实例,并从容器中获取了一个UserService
的 Bean 实例。这个 Bean 实例可以直接用于业务逻辑的处理,而无需手动创建对象或进行依赖注入。总之,
Ch01Application
类是 Spring Boot 应用程序的入口点,它提供了main
方法用于启动应用程序、初始化 IOC 容器,以及从容器中获取 Spring Bean 实例,方便开发者编写业务逻辑代码。
还有一个非常重要的地方要注意!!!!
Ch01Application必须是在ch01包下,不能够放在dao或者service里面,如果是放在里面的话@SpringBootApplication注解就没有没放扫描到所有的装配注解,如果是放在 dao 里,那它只能扫描到 dao 里面的装配注解,就没有办法扫描到 service 的。这样在获取 service bean 的时候就会报错。
如果想把 Ch01Application 放在其他的包下也可以,也可以使用@SpringBootApplication注解指定 Ch01Application 的包路径的。
// 指定默认的扫描包路径 @SpringBootApplication(scanBasePackageClasses = "xxx.xxxx.aa")
七、测试类
@SpringBootTest
class Ch01ApplicationTests {@Autowiredprivate UserService userService;@Testvoid contextLoads() {userService.add();}}
这段代码是一个典型的 Spring Boot 单元测试类,让我来逐一解释每一部分:
@SpringBootTest
注解标注在类上,它是 Spring Boot 提供的一个组合注解,用于加载整个 Spring 应用程序的上下文。它会自动初始化 Spring 应用程序的 IOC 容器,并加载所有的 Bean,使得在测试中可以使用依赖注入等功能。
Ch01ApplicationTests
类是一个测试类,用于测试Ch01Application
类中的业务逻辑。在这个测试类中,我们将测试UserService
的add()
方法。
@Autowired
注解用于自动装配UserService
类型的 Bean,由于在测试中我们需要使用userService
实例,因此使用@Autowired
注解将其注入到测试类中。
@Test
注解标注在contextLoads
方法上,表示这是一个测试方法。在这个方法中,调用了userService
的add()
方法,以测试添加用户的业务逻辑是否正常工作。通过以上代码,我们可以看到 Spring Boot 在测试方面的便利性,如使用
@SpringBootTest
注解来加载整个应用程序上下文,使用@Autowired
注解来自动装配需要测试的 Bean,使得我们能够方便地编写和执行单元测试。
运行结果:
八、总结
Spring Boot 项目通常具有以下标准结构:
src/main/java: 主要的 Java 代码目录,包含了项目的 Java 源代码文件。
src/main/resources: 存放主要的配置文件和资源文件,如 application.properties 或 application.yml 等配置文件,以及静态资源文件、模板文件等。
src/test/java: 测试代码目录,包含了项目的单元测试和集成测试等相关的 Java 源代码文件。
src/test/resources: 存放测试相关的配置文件和资源文件。
pom.xml (如果是 Maven 项目) 或 build.gradle (如果是 Gradle 项目): 项目的构建配置文件,包含了项目的依赖管理、插件配置等。
target (如果是 Maven 项目) 或 build (如果是 Gradle 项目): 编译输出目录,包含了编译后的类文件、打包后的可执行文件等。
其他自定义的目录结构,如存放实体类的目录、存放控制器的目录、存放服务类的目录等。
在 Spring Boot 项目中,通常会遵循约定大于配置的原则,因此可以快速地搭建和开发项目,同时也可以根据需要进行自定义的配置和扩展。