# 13 个编写 Spring 配置文件的最佳实践

> 原文： [https://howtodoinjava.com/best-practices/13-best-practices-for-writing-spring-configuration-files/](https://howtodoinjava.com/best-practices/13-best-practices-for-writing-spring-configuration-files/)

Spring 是一个功能强大的框架，它使用多种配置选项。 它的最佳功能是为称为 bean 的旧式 Java 对象（PlainOld​​JavaObject）提供企业服务。 Spring 使用[依赖项注入（DI）](//howtodoinjava.com/spring/spring-core/inversion-of-control-ioc-and-dependency-injection-di-patterns-in-spring-framework-and-related-interview-questions/ "Inversion of control (IoC) and dependency injection (DI) patterns in spring framework and related interview questions")来简化并提高[可测试性](//howtodoinjava.com/best-practices/unit-testing-best-practices-junit-reference-guide/ "Unit testing best practices : JUnit Reference guide")。

Spring Bean，依赖项和 Bean 所需的服务在 xml 配置文件或注释中指定。 但是，XML 配置文件是冗长且更干净的。 如果未正确计划和编写，在大型项目中将变得非常难以管理。

在本文中，我将向您展示 13 个[最佳实践](//howtodoinjava.com/java-best-practices/ "Best practices")，用于编写 spring XML 配置。 其中一些似乎是最佳实践而不是最佳实践，但我将它们包含在此处是因为它们与该主题高度相关。

> 注意：其他一些因素（例如应用设计）可能会影响 XML 配置决策，但是我主要关注 XML 配置的可读性和可维护性。

```java
Table of Contents

1) Add a header comment to each configuration file
2) Use consistent naming conventions
3) No version numbers in schema references
4) Prefer setter injection over constructor injection
5) Prefer type over index for constructor argument matching
6) Use shortcut forms over expanded forms
7) Reuse bean definitions as much as possible
8) Always use ids as bean identifiers
9) Try to avoid autowiring
10) Always use classpath prefix
11) Always externalize properties
12) Use dependency-check at the development phase
13) Do not abuse/overuse dependency injection
```

让我们详细讨论上面的每一个，以使其更有意义。

## 1）在每个配置文件中添加标题注释

我总是更加强调代码注释。 配置文件也是如此。 添加配置文件标头总是非常有帮助的，该标头总结了配置文件中定义的 bean /属性。

在 Spring 配置中，您可以像添加 XML 注释一样添加注释，也可以使用`description`元素。 例如：

```java
<beans>
	<description>
		This configuration file will have all beans 
		which may be used for controlling transactions.
	</description>
	...
</beans>

```

使用`description`标签的一个可能的优点是，某些工具可能会从此元素中获取描述，以在其他地方为您提供帮助。

## 2）使用一致的命名约定

在所有配置文件中使用相同的命名是非常重要的。 在整个项目中使用清晰，描述性和一致的名称约定，可以提高配置文件的可读性，并使其他开发人员可以轻松避免一些偶然的错误。

例如，对于 bean ID，可以遵循 Java 类字段名称约定。 `EmployeeUpdateDAO`实例的 bean ID 将是`employeeUpdateDAO`。 对于大型项目，可以将包名称添加为 Bean ID 的前缀。 例如 `finance.employeeUpdateDAO`。

## 3）模式引用中没有版本号

我在之前的文章中也指出了此功能。 我再次将其包括在内，因为从长远来看，它对于改善可维护性至关重要且有益。 要刷新您的内存，根本不需要在 bean 配置文件中为引用的模式指定版本号，您可以忽略它。 如果确实如此，您应该一直忽略它。

Spring 自动从项目依赖项（jar）中选择可用的最高版本。 另外，随着项目的发展和 Spring 版本的更新，我们不必维护所有 XML 配置文件即可看到新功能。

> 阅读更多： [Spring 无版本的架构引用](//howtodoinjava.com/spring/spring-core/do-not-specify-version-numbers-in-spring-schema-references/ "Do not specify version numbers in Spring schema references")

一个示例示例将如下所示：

```java
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context/
  http://www.springframework.org/schema/context/spring-context.xsd">

  <!-- Other bean definitions-->

</beans>

```

## 4）优先使用设置器注入而不是构造方法注入

Spring 提供了三种类型的依赖项注入：构造器注入，设置器注入和方法注入。 通常，我们都只使用前两种类型。

```java
<!-- Constructor injection -->
<bean id="employeeDAO"	class="com.howtodoinjava.dao.EmployeeDAO">
	<constructor-arg ref="datasource"/>
</bean>

<!-- Setter injection -->
<bean id="employeeDAO" class="com.howtodoinjava.dao.EmployeeDAO">
	<property name="datasource"	ref="datasource">
</bean>

```

构造器注入可以提供最便宜的线程安全，即[不可变对象](//howtodoinjava.com/java/related-concepts/how-to-make-a-java-class-immutable/ "How to make a java class immutable")。 此外，它还可以确保没有完成初始化就不会将对象移交给其他 bean。

设置器注入提供了许多理想的功能，即灵活性或可维护性。 如果在 bean 中要设置多个属性，那么为构造器创建一长串参数不是一个好主意。 同样，如果可能的话，某些属性可能是可选的。

更偏向灵活性。 为了保持不变或线程安全，请遵循其他编程规则。

> 阅读更多：[如何使 Java 类不可变](//howtodoinjava.com/java/related-concepts/how-to-make-a-java-class-immutable/ "How to make a java class immutable")

## 5）在构造器注入中将类型优先于索引以进行构造器参数匹配

最好避免使用构造器注入，而更偏向使用设置器注入进行依赖项注入。 但是，如果绝对需要使用构造器注入，则**总是更偏向基于类型而不是索引**的参数匹配。

```java
<!-- Index based constructor injection -->
<bean id="employeeDAO" class="com.howtodoinjava.EmployeeDAO">
	<constructor-arg index="0" value="rest"/>
	<constructor-arg index="1" value="8080"/>
</bean>

<!-- Type based constructor injection -->
<bean id="employeeDAO" class="com.howtodoinjava.EmployeeDAO">
	<constructor-arg type="java.lang.String" value="rest"/>
	<constructor-arg type="int" value="8080"/>
</bean>

```

如您所见，基于类型的参数传递更具可读性，并且不易出错。 但是，只要基于类型的参数传递有任何歧义，就可以毫不犹豫地转到基于索引的参数传递。

## 6）在扩展形式上使用快捷方式形式

Spring bean 配置语义允许两种形式来指定属性值和其他 bean 引用。 一种是扩展形式，另一种是较短形式。 最好使用较短的版本。

```java
<!-- Expanded version -->
<bean id="employeeDAO" class="com.howtodoinjava.dao.EmployeeDAO">
	<property name="datasource">
		<ref bean="datasource"></ref>
		<value>datasource</value>
	 </property>
</bean>

<!-- Shorter/shortcut version -->
<bean id="employeeDAO" class="com.howtodoinjava.dao.EmployeeDAO">
	<property name="datasource"	ref="datasource" value="datasource">
</bean>

```

## 7）尽可能重用 bean 定义

Spring 提供了非常有用的功能，您应该在项目中广泛使用它，即 bean 定义可重用性。 在这里，我不是在谈论用于设置器注入的 bean 参考。 而是我指出了在构造其他 bean 时重用 bean 定义。

以数据源定义的示例为例：

```java
<bean id="abstractDataSource" class="org.apache.commons.dbcp.BasicDataSource" 
	destroy-method="close"
	p:driverClassName="${jdbc.driverClassName}"
	p:username="${jdbc.username}"
	p:password="${jdbc.password}" />

<bean id="concreteDataSourceOne"
	parent="abstractDataSource"
	p:url="${jdbc.databaseurlOne}"/>

<bean id="concreteDataSourceTwo"
	parent="abstractDataSource"
	p:url="${jdbc.databaseurlTwo}"/>

```

> 阅读更多： [Spring `AbstractRoutingDataSource`示例](//howtodoinjava.com/spring/spring-orm/spring-3-2-5-abstractroutingdatasource-example/ "Spring AbstractRoutingDataSource example")

## 8）始终使用“`id`”作为 bean 标识符

Spring 允许 bean 使用两种类型的标识符。 使用属性“`id`”或“`name`”。 您应该**始终选择属性 ID 而不是名称**。 通常，它既不会增加可读性，也不会增加任何性能。 这是行业标准的做法，所有其他开发人员都在全世界甚至在您的团队中遵循。

只是不要在这里是个奇怪的人。

## 9）尽量避免自动装配

如果可以长期管理，自动装配是一个很棒的功能。 通常，如果您的项目只有很少的 bean，并且几乎可以在内存中记住它们，那将是有益的。

一旦项目变大，自动装配就开始在确定要使用的正确依赖项方面造成麻烦。 我发现主要的缺点是无法将整个系统绑定在一起。 这是 spring 配置文件获胜的地方。 他们可以在几分钟之内将整个系统呈现给任何新手。

另外，当您开始调试一些复杂的问题时，所有在配置文件中的所有信息实际上都会有很大帮助。 自动装配使调试更加困难。

> 了解更多：[Spring 自动装配](//howtodoinjava.com/2013/05/08/spring-beans-autowiring-concepts/ "Spring beans autowiring concepts")

## 10）始终使用`classpath`前缀

导入资源，XML 配置，属性等时，请始终使用`classpath:`或`classpath*`：前缀。 这提供了资源位置的一致性和清晰度。 并非 Spring 的每个功能都具有相同的行为，**类路径保证一致性**。

类路径由构建工具和 IDE 确定。 对于 Java 代码，通常为`src/main/java`，对于非 Java 依赖项和测试通常为`src/main/resources`，对于 Java 代码为`src/test/java`，对于非 Java 资源为`src/test/resources`。

```java
<!-- Always use classpath: prefix-->
<import resource="classpath:/META-INF/spring/applicationContext-security.xml"/>

```

## 11）总是外部化属性

通常，存在与应用运行时间相关的多个配置参数。 它们被传递到 bean 配置上下文文件中的 bean 定义。 不要将它们硬编码在配置文件中。 而是将它们外部化到某些属性文件。

最好根据它们的用法或模块将它们分组在单独的文件中，即`jdbc.properties`文件中所有与 JDBC 数据源相关的属性。

```java
<bean id="abstractDataSource" class="org.apache.commons.dbcp.BasicDataSource" 
        destroy-method="close"
        p:driverClassName="${jdbc.driverClassName}"
        p:username="${jdbc.username}"
        p:password="${jdbc.password}" />

```

和属性文件是：

```java
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.username=root
jdbc.password=password

```

## 12）在开发阶段使用“依赖项检查”

您应该将 Bean 定义上的`dependency-check`属性设置为`simple`，`objects`或`all`（默认值为`none`，即不检查），以便容器可以为您执行显式依赖项验证。 当必须显式地或通过自动装配来设置 Bean 的所有属性（或某些类别的属性）时，这很有用。

```java
<bean id="abstractDataSource" class="org.apache.commons.dbcp.BasicDataSource" 
	destroy-method="close"
	p:driverClassName="${jdbc.driverClassName}"
	p:username="${jdbc.username}"
	p:password="${jdbc.password}" 
	dependency-check="all" />

```

在上面给出的示例中，容器将确保在应用初始化时间本身中设置数据源的所有属性/参数。

## 13）不要滥用/滥用依赖注入

最后，请不要滥用引入[依赖注入](//howtodoinjava.com/spring/spring-core/inversion-of-control-ioc-and-dependency-injection-di-patterns-in-spring-framework-and-related-interview-questions/ "Inversion of control (IoC) and dependency injection (DI) patterns in spring framework and related interview questions")的动机。

Java 提供“`new`”关键字来创建新对象。 在不需要 DI 的地方使用此精彩的关键字，例如 DTO 对象。 不要试图玩得更聪明。 只需遵循基础知识即可。

如果您对以上几点有异议，请给我评论。

学习愉快！