불변 @Configuration Properties
Spring Boot에서 불변(최종) 필드를 사용할 수 있습니까?@ConfigurationProperties
주석?다음 예
@ConfigurationProperties(prefix = "example")
public final class MyProps {
private final String neededProperty;
public MyProps(String neededProperty) {
this.neededProperty = neededProperty;
}
public String getNeededProperty() { .. }
}
지금까지 해 본 접근법:
- 작성
@Bean
의MyProps
두 개의 컨스트럭터가 있는 클래스- 2개의 컨스트럭터 제공: 빈 컨스트럭터와
neededProperty
논쟁 - 콩은 다음과 같이 생성됩니다.
new MyProps()
- 결과는 다음과 같습니다.
null
- 2개의 컨스트럭터 제공: 빈 컨스트럭터와
- 사용.
@ComponentScan
그리고.@Component
제공하다MyProps
콩.- 결과:
BeanInstantiationException
->NoSuchMethodException: MyProps.<init>()
- 결과:
최종이 아닌 각 필드에 getter/setter를 제공하는 방법밖에 없습니다.
Spring Boot 2.2부터는 최종적으로 다음 명령어로 장식된 불변의 클래스를 정의할 수 있습니다.@ConfigurationProperties
.
문서에는 예가 나와 있습니다.
(세터 방식이 아닌) 바인딩할 필드를 사용하여 생성자를 선언하고 생성자 바인딩을 사용해야 함을 나타내는 주석을 클래스 수준에서 추가하면 됩니다.
따라서 세터 없이 실제 코드를 사용할 수 있습니다.
@ConstructorBinding
@ConfigurationProperties(prefix = "example")
public final class MyProps {
private final String neededProperty;
public MyProps(String neededProperty) {
this.neededProperty = neededProperty;
}
public String getNeededProperty() { .. }
}
저는 이 문제를 자주 해결해야 합니다.그리고 저는 조금 다른 접근방식을 사용합니다.그러면final
클래스 내의 변수입니다.
우선, 모든 설정을 1개의 장소(클래스)에 보관합니다.ApplicationProperties
그 반에는@ConfigurationProperties
특정 접두사를 가진 주석.에도 기재되어 있습니다.@EnableConfigurationProperties
구성 클래스(또는 기본 클래스)에 대한 주석입니다.
그리고 나서 나는 나의ApplicationProperties
컨스트럭터 인수로서, 그리고 에의 할당을 실행한다.final
컨스트럭터 내부의 필드.
예:
메인 클래스:
@SpringBootApplication
@EnableConfigurationProperties(ApplicationProperties.class)
public class Application {
public static void main(String... args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
ApplicationProperties
클래스
@ConfigurationProperties(prefix = "myapp")
public class ApplicationProperties {
private String someProperty;
// ... other properties and getters
public String getSomeProperty() {
return someProperty;
}
}
그리고 최종 속성을 가진 클래스는
@Service
public class SomeImplementation implements SomeInterface {
private final String someProperty;
@Autowired
public SomeImplementation(ApplicationProperties properties) {
this.someProperty = properties.getSomeProperty();
}
// ... other methods / properties
}
저는 여러 가지 이유로 이 방법을 선호합니다. 예를 들어 컨스트럭터에서 더 많은 속성을 설정해야 하는 경우, 컨스트럭터 인수 목록은 항상 하나의 인수를 가지고 있기 때문에 "거대"가 아닙니다.ApplicationProperties
내 경우); 추가가 필요한 경우final
properties, my constructor는 같은 상태(인수 1개만)입니다.이것에 의해서, 다른 장소의 변경의 수를 줄일 수 있습니다.
그게 도움이 됐으면 좋겠다.
https://stackoverflow.com/a/60442151/11770752의 접근방식과 유사한 접근방식을 사용한다.
하지만 대신AllArgsConstructor
를 사용할 수 있습니다.RequiredArgsConstructor
.
다음을 고려하다applications.properties
myprops.example.firstName=Peter
myprops.example.last-name=Pan
myprops.example.age=28
주의: 속성과 일관성을 유지하십시오.저는 단지 양쪽이 모두 맞았음을 보여주고 싶었습니다.fistName
그리고.last-name
).
Java 클래스에서 속성을 픽업
@Getter
@ConstructorBinding
@RequiredArgsConstructor
@ConfigurationProperties(prefix = "myprops.example")
public class StageConfig
{
private final String firstName;
private final Integer lastName;
private final Integer age;
// ...
}
또한 빌드 도구에 종속성을 추가해야 합니다.
build.gradle
annotationProcessor('org.springframework.boot:spring-boot-configuration-processor')
또는
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring.boot.version}</version>
</dependency>
상세하고 한 더 파일 .additional-spring-configuration-metadata.json
「」에서src/main/resources/META-INF
.
{
"properties": [
{
"name": "myprops.example.firstName",
"type": "java.lang.String",
"description": "First name of the product owner from this web-service."
},
{
"name": "myprops.example.lastName",
"type": "java.lang.String",
"description": "Last name of the product owner from this web-service."
},
{
"name": "myprops.example.age",
"type": "java.lang.Integer",
"description": "Current age of this web-service, since development started."
}
}
(깨끗하게 컴파일하여 유효하게 합니다)
에서는, 「IntelliJ」의 를 대면,application.propoerties
커스텀 속성을 명확하게 확인할 수 있습니다.하다
이것은 내가 봄과 함께 봉사할 때 사용하고 있는, 내 소유물의 멋지고 간결한 구조를 내게 주고 있다.
최종적으로 불변의 오브젝트를 원하는 경우 다음과 같은 세터를 "해킹"할 수도 있습니다.
@ConfigurationProperties(prefix = "myapp")
public class ApplicationProperties {
private String someProperty;
// ... other properties and getters
public String getSomeProperty() {
return someProperty;
}
public String setSomeProperty(String someProperty) {
if (someProperty == null) {
this.someProperty = someProperty;
}
}
}
분명히 그 속성이 단순한 스트링(String)이 아니라 가변 객체라면 상황은 더 복잡하지만 그것은 다른 이야기다.
구성 컨테이너를 생성할 수 있습니다.
@ConfigurationProperties(prefix = "myapp")
public class ApplicationProperties {
private final List<MyConfiguration> configurations = new ArrayList<>();
public List<MyConfiguration> getConfigurations() {
return configurations
}
}
여기서 Configuration은 clas 입니다.
public class MyConfiguration {
private String someProperty;
// ... other properties and getters
public String getSomeProperty() {
return someProperty;
}
public String setSomeProperty(String someProperty) {
if (this.someProperty == null) {
this.someProperty = someProperty;
}
}
}
및 application.yml as
myapp:
configurations:
- someProperty: one
- someProperty: two
- someProperty: other
내 생각에는 내부 클래스를 통해 속성 그룹을 캡슐화하고 getters와의 인터페이스만 노출하는 것입니다.
속성 파일:
myapp.security.token-duration=30m
myapp.security.expired-tokens-check-interval=5m
myapp.scheduler.pool-size=2
코드:
@Component
@ConfigurationProperties("myapp")
@Validated
public class ApplicationProperties
{
private final Security security = new Security();
private final Scheduler scheduler = new Scheduler();
public interface SecurityProperties
{
Duration getTokenDuration();
Duration getExpiredTokensCheckInterval();
}
public interface SchedulerProperties
{
int getPoolSize();
}
static private class Security implements SecurityProperties
{
@DurationUnit(ChronoUnit.MINUTES)
private Duration tokenDuration = Duration.ofMinutes(30);
@DurationUnit(ChronoUnit.MINUTES)
private Duration expiredTokensCheckInterval = Duration.ofMinutes(10);
@Override
public Duration getTokenDuration()
{
return tokenDuration;
}
@Override
public Duration getExpiredTokensCheckInterval()
{
return expiredTokensCheckInterval;
}
public void setTokenDuration(Duration duration)
{
this.tokenDuration = duration;
}
public void setExpiredTokensCheckInterval(Duration duration)
{
this.expiredTokensCheckInterval = duration;
}
@Override
public String toString()
{
final StringBuffer sb = new StringBuffer("{ ");
sb.append("tokenDuration=").append(tokenDuration);
sb.append(", expiredTokensCheckInterval=").append(expiredTokensCheckInterval);
sb.append(" }");
return sb.toString();
}
}
static private class Scheduler implements SchedulerProperties
{
@Min(1)
@Max(5)
private int poolSize = 1;
@Override
public int getPoolSize()
{
return poolSize;
}
public void setPoolSize(int poolSize)
{
this.poolSize = poolSize;
}
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder("{ ");
sb.append("poolSize=").append(poolSize);
sb.append(" }");
return sb.toString();
}
}
public SecurityProperties getSecurity() { return security; }
public SchedulerProperties getScheduler() { return scheduler; }
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder("{ ");
sb.append("security=").append(security);
sb.append(", scheduler=").append(scheduler);
sb.append(" }");
return sb.toString();
}
}
최신 Spring-Boot 버전에 대한 최신 지원 업데이트입니다.
버전 jdk > = 14를 사용할 수 .record
롬복 버전과 거의 같지만 롬복이 없는 유형입니다.
@ConfigurationProperties(prefix = "example")
public record MyProps(String neededProperty) {
}
, 도 사용하실 수 .MyProps
record를 클릭하여 중첩된 속성을 관리합니다.여기서 예를 볼 수 있습니다.
여기 또 다른 흥미로운 게시물이 있습니다.@ConstructorBinding
단 한 개의 생성자만 선언된 경우에도 주석은 더 이상 필요하지 않습니다.
Lombok 주석을 사용하면 코드는 다음과 같습니다.
@ConfigurationProperties(prefix = "example")
@AllArgsConstructor
@Getter
@ConstructorBinding
public final class MyProps {
private final String neededProperty;
}
이 를 사용하지 @Configuration
및 " " " 。@EnableConfigurationProperties
, , , , , , , , , , , , , , , , , , , .@ConfigurationPropertiesScan
주 응용 프로그램클래스에 주석을 붙입니다.@SpringBootApplication
.
다음 URL에서 관련 문서를 참조하십시오.https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-constructor-binding
은 하다를 통해 할 수 .@Value
수 .이것들은 필드에 직접 배치할 수 있으며 세터가 필요하지 않습니다.
@Component
public final class MyProps {
@Value("${example.neededProperty}")
private final String neededProperty;
public String getNeededProperty() { .. }
}
이 접근방식의 단점은 다음과 같습니다.
언급URL : https://stackoverflow.com/questions/26137932/immutable-configurationproperties
'programing' 카테고리의 다른 글
json_encode(): 인수의 UTF-8 시퀀스가 잘못되었습니다. (0) | 2023.02.20 |
---|---|
각도 - UI 라우터가 이전 상태를 가져옵니다. (0) | 2023.02.20 |
스프링 부트 유닛 테스트에서는 logging.level이 무시됩니다. (0) | 2023.02.20 |
wp mail smtp로 폼7에 문의해 주세요. (0) | 2023.02.20 |
.js 파일에 상대적인 Angular Directive templateUrl (0) | 2023.02.20 |