봄: 프로필에서 AND를 수행하는 방법?
스프링 종단 주석을 사용하여 종단을 선택할 수 있습니다.그러나 설명서를 읽는 경우 OR 작업을 통해 둘 이상의 프로파일만 선택할 수 있습니다.@Profile("A", "B")를 지정하면 프로파일 A 또는 프로파일 B가 활성화되면 빈이 작동합니다.
사용 사례가 다릅니다. 여러 구성의 TEST 및 PROD 버전을 지원하고자 합니다.따라서 간혹 TEST 및 CONFIG1 프로파일이 모두 활성화된 경우에만 Bean을 자동 배선하려고 합니다.
스프링으로 할 수 있는 방법이 없을까요?가장 간단한 방법은 무엇입니까?
Spring 5.1(Spring Boot 2.1에 통합됨) 이후 프로파일 문자열 주석 내부에서 프로파일 식을 사용할 수 있습니다.그래서:
Spring 5.1(Spring Boot 2.1) 이상에서는 다음과 같이 쉽게 사용할 수 있습니다.
@Component
@Profile("TEST & CONFIG1")
public class MyComponent {}
스프링 4.x 및 5.0.x:
접근 1: @Mithun이 답변함, 그것은 당신이 스프링 빈에 그의 것으로도 주석을 달 때마다 당신의 프로필 주석에서 OR을 AND로 변환하는 당신의 사례를 완벽하게 다룹니다.
Condition
저는 하지 않은 .하지만 저는 아무도 제안하지 않았던 찬성과 반대의 의견을 가진 또 다른 접근법을 제안하고 싶습니다.그냥 하기 2: 사용하기
@Conditional
.Condition
필요한 조합으로서의 구현.조합만큼 많은 구현을 생성해야 한다는 단점이 있지만 조합이 많지 않다면 더 간결한 솔루션이며 더 많은 유연성과 더 복잡한 논리적 해결책을 구현할 수 있는 기회를 제공한다고 생각합니다.
접근법 2의 구현은 다음과 같습니다.
당신의 봄 콩:
@Component
@Conditional(value = { TestAndConfig1Profiles.class })
public class MyComponent {}
TestAndConfig1Profiles
구현:
public class TestAndConfig1Profiles implements Condition {
@Override
public boolean matches(final ConditionContext context, final AnnotatedTypeMetadata metadata) {
return context.getEnvironment().acceptsProfiles("TEST")
&& context.getEnvironment().acceptsProfiles("CONFIG1");
}
}
이 접근 방식을 사용하면 다음과 같은 보다 복잡한 논리적 상황을 쉽게 처리할 수 있습니다.
(TEST & CONFIG1) | (TEST & CONFIG3)
질문에 대한 최신 답변을 제공하고 다른 답변을 보완하고자 합니다.
스프링은 AND 기능을 즉시 제공하지 않기 때문입니다.저는 다음과 같은 전략을 참조하십시오.
현의재@Profile
주석이 .@Conditional(ProfileCondition.class)
ProfileCondition.class
프로파일을 반복하고 프로파일이 활성화되었는지 확인합니다.마찬가지로 자신만의 조건부 구현을 만들고 콩 등록을 제한할 수 있습니다.
public class MyProfileCondition implements Condition {
@Override
public boolean matches(final ConditionContext context,
final AnnotatedTypeMetadata metadata) {
if (context.getEnvironment() != null) {
final MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
if (attrs != null) {
for (final Object value : attrs.get("value")) {
final String activeProfiles = context.getEnvironment().getProperty("spring.profiles.active");
for (final String profile : (String[]) value) {
if (!activeProfiles.contains(profile)) {
return false;
}
}
}
return true;
}
}
return true;
}
}
강의실:
@Component
@Profile("dev")
@Conditional(value = { MyProfileCondition.class })
public class DevDatasourceConfig
참고: 모든 코너 케이스(null, 길이 확인 등)를 확인하지 않았습니다.하지만, 이 방향이 도움이 될 수 있습니다.
@Mithun의 약간 개선된 버전은 다음과 같습니다.
public class AndProfilesCondition implements Condition {
public static final String VALUE = "value";
public static final String DEFAULT_PROFILE = "default";
@Override
public boolean matches(final ConditionContext context, final AnnotatedTypeMetadata metadata) {
if (context.getEnvironment() == null) {
return true;
}
MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
if (attrs == null) {
return true;
}
String[] activeProfiles = context.getEnvironment().getActiveProfiles();
String[] definedProfiles = (String[]) attrs.getFirst(VALUE);
Set<String> allowedProfiles = new HashSet<>(1);
Set<String> restrictedProfiles = new HashSet<>(1);
for (String nextDefinedProfile : definedProfiles) {
if (!nextDefinedProfile.isEmpty() && nextDefinedProfile.charAt(0) == '!') {
restrictedProfiles.add(nextDefinedProfile.substring(1, nextDefinedProfile.length()));
continue;
}
allowedProfiles.add(nextDefinedProfile);
}
int activeAllowedCount = 0;
for (String nextActiveProfile : activeProfiles) {
// quick exit when default profile is active and allowed profiles is empty
if (DEFAULT_PROFILE.equals(nextActiveProfile) && allowedProfiles.isEmpty()) {
continue;
}
// quick exit when one of active profiles is restricted
if (restrictedProfiles.contains(nextActiveProfile)) {
return false;
}
// just go ahead when there is no allowed profiles (just need to check that there is no active restricted profiles)
if (allowedProfiles.isEmpty()) {
continue;
}
if (allowedProfiles.contains(nextActiveProfile)) {
activeAllowedCount++;
}
}
return activeAllowedCount == allowedProfiles.size();
}
}
댓글에 올리지 못했습니다.
그러나 다른 옵션은 클래스/메소드 레벨에서 재생할 수 있습니다.@Profile
주석구현만큼 유연하지 않음MyProfileCondition
당신의 경우에 적합하다면 신속하고 깨끗합니다.
예를 들어 FAST와 DEV가 모두 활성화된 경우에는 시작되지 않지만 DEV가 다음과 같은 경우에만 시작됩니다.
@Configuration
@Profile("!" + SPRING_PROFILE_FAST)
public class TomcatLogbackAccessConfiguration {
@Bean
@Profile({SPRING_PROFILE_DEVELOPMENT, SPRING_PROFILE_STAGING})
public EmbeddedServletContainerCustomizer containerCustomizer() {
다른 종류의 트릭이지만 많은 시나리오에서 작동할 수 있는 것은 @Configuration에 @Profile 주석을 배치하고 다른 @Bean에 @Profile 주석을 배치하는 것입니다. 이는 Java 기반 스프링 구성에서 두 프로파일 사이에 논리적 AND를 생성합니다.
@Configuration
@Profile("Profile1")
public class TomcatLogbackAccessConfiguration {
@Bean
@Profile("Profile2")
public EmbeddedServletContainerCustomizer containerCustomizer() {
@Profile 주석을 사용하여 구성 클래스 또는 been 메서드를 이미 표시한 경우에는 다음을 사용하여 추가 프로파일(예: AND 조건)을 쉽게 확인할 수 있습니다.Environment.acceptsProfiles()
@Autowired Environment env;
@Profile("profile1")
@Bean
public MyBean myBean() {
if( env.acceptsProfiles("profile2") ) {
return new MyBean();
}
else {
return null;
}
}
저는 @rozhoc의 답변이 @Profile을 사용할 때 어떤 프로파일도 'default'에 해당하지 않는다는 사실을 설명하지 않았기 때문에 @rozhoc의 답변을 개선했습니다.또한 제가 원했던 조건은!default && !a
@rozhoc의 코드가 제대로 처리되지 않았습니다.마침내 나는 몇몇 Java8을 사용했고 오직 그것만을 보여주었습니다.matches
간결한 방법
@Override
public boolean matches(final ConditionContext context, final AnnotatedTypeMetadata metadata) {
if (context.getEnvironment() == null) {
return true;
}
MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
if (attrs == null) {
return true;
}
Set<String> activeProfilesSet = Arrays.stream(context.getEnvironment().getActiveProfiles()).collect(Collectors.toSet());
String[] definedProfiles = (String[]) attrs.getFirst(VALUE);
Set<String> allowedProfiles = new HashSet<>(1);
Set<String> restrictedProfiles = new HashSet<>(1);
if (activeProfilesSet.size() == 0) {
activeProfilesSet.add(DEFAULT_PROFILE); // no profile is equivalent in @Profile terms to "default"
}
for (String nextDefinedProfile : definedProfiles) {
if (!nextDefinedProfile.isEmpty() && nextDefinedProfile.charAt(0) == '!') {
restrictedProfiles.add(nextDefinedProfile.substring(1, nextDefinedProfile.length()));
continue;
}
allowedProfiles.add(nextDefinedProfile);
}
boolean allowed = true;
for (String allowedProfile : allowedProfiles) {
allowed = allowed && activeProfilesSet.contains(allowedProfile);
}
boolean restricted = true;
for (String restrictedProfile : restrictedProfiles) {
restricted = restricted && !activeProfilesSet.contains(restrictedProfile);
}
return allowed && restricted;
}
혼란스러운 경우를 대비하여 실제로 사용하는 방법은 다음과 같습니다.
@Profile({"!default", "!a"})
@Conditional(value={AndProfilesCondition.class})
언급URL : https://stackoverflow.com/questions/27055072/spring-how-to-do-and-in-profiles
'programing' 카테고리의 다른 글
PowerShell에서 배너 메시지를 제거하는 방법 (0) | 2023.09.02 |
---|---|
매일 특정 시간에 MySQL 이벤트 스케줄러 (0) | 2023.09.02 |
MongoDB가 _id 배열의 위치를 선택하시겠습니까? (0) | 2023.03.26 |
파일 API - BLOB에서 JSON으로 (0) | 2023.03.26 |
전달할 헤더 매개 변수가 있는 Img src 경로 (0) | 2023.03.26 |