> For the complete documentation index, see [llms.txt](https://potoyang.gitbook.io/spring-in-action-v5/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://potoyang.gitbook.io/spring-in-action-v5/di-5-zhang-shi-yong-pei-zhi-shu-xing/5.2-chuang-jian-zi-ji-de-pei-zhi-shu-xing/5.2.1-ding-yi-pei-zhi-shu-xing-chi-you-zhe.md).

# 5.2.1 定义配置属性持有者

这里没有说 @ConfigurationProperties 必须设置在控制器或任何其他特定类型的 bean 上，@ConfigurationProperties 实际上经常放在 bean 上。在应用程序中，这些 bean 的惟一目的是作为配置数据的持有者，这使控制器和其他应用程序类不涉及特定于配置的细节，它还使得在几个可能使用该信息的 bean 之间共享公共配置属性变得很容易。

对于 OrderController 中的 pageSize 属性，可以将其提取到一个单独的类中。下面的程序清单以这种方式使用了 OrderProps 类。

{% code title="程序清单 5.2 提取 pageSize 到持有者类" %}

```java
package tacos.web;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import lombok.Data;
​
@Component
@ConfigurationProperties(prefix="taco.orders")
@Data
public class OrderProps {
    private int pageSize = 20;
}
```

{% endcode %}

正如在 OrderController 中所做的，pageSize 属性默认为 20，同时 OrderProps 使用 @ConfigurationProperties 进行注解，以具有 taco.orders 前缀。

它还带有 @Component 注解，因此 Spring 组件扫描时将自动发现它并在 Spring 应用程序上下文中将其创建为 bean。这很重要，因为下一步是将 OrderProps bean 注入到 OrderController 中。

关于配置属性持有者，没有什么特别的。它们是从 Spring 环境中注入属性的 bean。它们可以被注入到任何需要这些属性的其他 bean 中。对于 OrderController，这意味着从 OrderController 中删除 pageSize 属性，而不是注入并使用 OrderProps bean：

```java
@Controller
@RequestMapping("/orders")
@SessionAttributes("order")
public class OrderController {
    
    private OrderRepository orderRepo;
    
    private OrderProps props;
    
    public OrderController(OrderRepository orderRepo,
             OrderProps props) {
        this.orderRepo = orderRepo;
        this.props = props;
    }
    
    ...
    
    @GetMapping
    public String ordersForUser(
        @AuthenticationPrincipal User user, Model model) {
        Pageable pageable = PageRequest.of(0, props.getPageSize());
        model.addAttribute("orders",
            orderRepo.findByUserOrderByPlacedAtDesc(user, pageable));
        return "orderList";
    }
    
    ...
}
```

现在 OrderController 不再负责处理它自己的配置属性。这使得 OrderController 中的代码稍微整洁一些，并允许在任何其他需要它们的 bean 中重用 OrderProps 中的属性。此外，正在收集与一个地方的订单相关的配置属性：OrderProps 类。如果需要添加、删除、重命名或以其他方式更改其中的属性，只需要在 OrderProps 中应用这些更改。

例如，假设在其他几个 bean 中使用 pageSize 属性，这时最好对该属性应用一些验证，以将其值限制为不小于 5 和不大于 25。如果没有持有者 bean，将不得不对 OrderController、pageSize 属性以及使用该属性的所有其他类应用验证注解。但是因为已经将 pageSize 提取到 OrderProps 中，所以只需要更改 OrderProps：

```java
package tacos.web;
​
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import org.springframework.boot.context.properties.
ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import lombok.Data;
​
@Component
@ConfigurationProperties(prefix="taco.orders")
@Data
@Validated
public class OrderProps {
    @Min(value=5, message="must be between 5 and 25")
    @Max(value=25, message="must be between 5 and 25")
    private int pageSize = 20;
}
//end::validated[]
```

尽管可以很容易地将 @Validated、@Min 和 @Max 注解应用到 OrderController（以及可以注入 OrderProps 的任何其他 bean），但这只会使 OrderController 更加混乱。通过使用配置属性持有者 bean，就在在一个地方收集了配置属性的细节，使得需要这些属性的类相对干净。
