[SPRING] 외부화 된 값을 Spring annotation으로 주입
SPRING외부화 된 값을 Spring annotation으로 주입
필자는 컴파일 시간에 주석 값을 평가하는 자바 기능을 생각해 왔으며, 실제로 외 부화 애노테이션 값을 어렵게 만드는 것으로 보입니다.
그러나 실제로 불가능한 것인지 확신 할 수 없으므로 이에 대한 제안이나 답변을 주시면 감사하겠습니다.
더 중요한 것은 Spring에서 예약 된 메소드 호출 사이의 지연을 제어하는 주석 값을 외부화하려고 시도하고 있습니다 (예 :
public class SomeClass {
private Properties props;
private static final long delay = 0;
@PostConstruct
public void initializeBean() {
Resource resource = new ClassPathResource("scheduling.properties");
props = PropertiesLoaderUtils.loadProperties(resource);
delay = props.getProperties("delayValue");
}
@Scheduled(fixedDelay = delay)
public void someMethod(){
// perform something
}
}
scheduling.properties가 classpath에 있고 해당 long 값과 함께 속성 키 delayValue를 포함한다고 가정하십시오.
이제이 코드는 최종 변수에 값을 할당하려고하기 때문에 명백한 컴파일 오류가 있지만 고정 최종 변수가 아니라면 변수를 주석 값에 할당 할 수 없으므로 필수입니다.
이 문제를 해결할 방법이 있습니까? Spring 커스텀 애노테이션에 대해 생각해 왔지만 근본적인 문제는 남아 있습니다 - 외부화 된 값을 애노테이션에 할당하는 방법은 무엇입니까?
어떤 생각이라도 환영합니다.
편집 : 작은 업데이트 - 석영 통합이 예제에 대한 잔인한입니다. 서브 분 해상도로 주기적으로 실행하면됩니다.
해결법
-
==============================
1.Spring v3.2.2의 @Scheduled 주석은 이것을 처리하기 위해 String 매개 변수를 원래의 3 개의 긴 매개 변수에 추가했습니다. fixedDelayString, fixedRateString 및 initialDelayString을 사용할 수 있습니다.
Spring v3.2.2의 @Scheduled 주석은 이것을 처리하기 위해 String 매개 변수를 원래의 3 개의 긴 매개 변수에 추가했습니다. fixedDelayString, fixedRateString 및 initialDelayString을 사용할 수 있습니다.
@Scheduled(fixedDelayString = "${my.delay.property}") public void someMethod(){ // perform something }
-
==============================
2.이렇게하는 더 좋은 방법은 작업 이름 공간을 사용하여 xml로 일정을 정의하는 것입니다.
이렇게하는 더 좋은 방법은 작업 이름 공간을 사용하여 xml로 일정을 정의하는 것입니다.
<context:property-placeholder location="scheduling.properties"/> <task:scheduled ref="someBean" method="someMethod" fixed-delay="${delayValue}"/>
어떤 이유로 주석을 사용하여 작업하려는 경우 속성 이름을 지정하거나 더 나은 속성 자리 표시 자 식 또는 Spel 식을 지정할 수있는 다른 선택적 특성이있는 주석을 만들어야합니다.
@MyScheduled(fixedDelayString="${delay}")
-
==============================
3.두 가지 모두 해답을 주셔서 감사합니다. 귀사는이 솔루션으로 안내하는 귀중한 정보를 제공해 주셨습니다. 그래서 나는 두 답을 모두지지했습니다.
두 가지 모두 해답을 주셔서 감사합니다. 귀사는이 솔루션으로 안내하는 귀중한 정보를 제공해 주셨습니다. 그래서 나는 두 답을 모두지지했습니다.
나는 사용자 정의 bean post processor와 custom @Scheduled annotation을 만들기로 선택했다.
코드는 간단합니다 (본질적으로 기존 스프링 코드의 간단한 수정입니다). 그리고 나는 그들이 왜 이렇게하지 않았는지 궁금합니다. BeanPostProcessor의 코드 카운트는 이전 주석과 새로운 주석을 처리하기 때문에 두 배가됩니다.
이 코드를 개선하는 방법에 대한 제안 사항이 있으시면 언제든지 알려 주시기 바랍니다.
CustomScheduled 클래스 (주석)
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CustomScheduled { String cron() default ""; String fixedDelay() default ""; String fixedRate() default ""; }
Custom ScheduledAnnotationBeanPostProcessor 클래스
public class CustomScheduledAnnotationBeanPostProcessor implements BeanPostProcessor, Ordered, EmbeddedValueResolverAware, ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, DisposableBean { private static final Logger LOG = LoggerFactory.getLogger(CustomScheduledAnnotationBeanPostProcessor.class); // omitted code is the same as in ScheduledAnnotationBeanPostProcessor...... public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } // processes both @Scheduled and @CustomScheduled annotations public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException { final Class<?> targetClass = AopUtils.getTargetClass(bean); ReflectionUtils.doWithMethods(targetClass, new MethodCallback() { public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { Scheduled oldScheduledAnnotation = AnnotationUtils.getAnnotation(method, Scheduled.class); if (oldScheduledAnnotation != null) { LOG.info("@Scheduled found at method {}", method.getName()); Assert.isTrue(void.class.equals(method.getReturnType()), "Only void-returning methods may be annotated with @Scheduled."); Assert.isTrue(method.getParameterTypes().length == 0, "Only no-arg methods may be annotated with @Scheduled."); if (AopUtils.isJdkDynamicProxy(bean)) { try { // found a @Scheduled method on the target class for this JDK proxy -> is it // also present on the proxy itself? method = bean.getClass().getMethod(method.getName(), method.getParameterTypes()); } catch (SecurityException ex) { ReflectionUtils.handleReflectionException(ex); } catch (NoSuchMethodException ex) { throw new IllegalStateException(String.format( "@Scheduled method '%s' found on bean target class '%s', " + "but not found in any interface(s) for bean JDK proxy. Either " + "pull the method up to an interface or switch to subclass (CGLIB) " + "proxies by setting proxy-target-class/proxyTargetClass " + "attribute to 'true'", method.getName(), targetClass.getSimpleName())); } } Runnable runnable = new ScheduledMethodRunnable(bean, method); boolean processedSchedule = false; String errorMessage = "Exactly one of 'cron', 'fixedDelay', or 'fixedRate' is required."; String cron = oldScheduledAnnotation.cron(); if (!"".equals(cron)) { processedSchedule = true; if (embeddedValueResolver != null) { cron = embeddedValueResolver.resolveStringValue(cron); } cronTasks.put(runnable, cron); } long fixedDelay = oldScheduledAnnotation.fixedDelay(); if (fixedDelay >= 0) { Assert.isTrue(!processedSchedule, errorMessage); processedSchedule = true; fixedDelayTasks.put(runnable, fixedDelay); } long fixedRate = oldScheduledAnnotation.fixedRate(); if (fixedRate >= 0) { Assert.isTrue(!processedSchedule, errorMessage); processedSchedule = true; fixedRateTasks.put(runnable, fixedRate); } Assert.isTrue(processedSchedule, errorMessage); } CustomScheduled newScheduledAnnotation = AnnotationUtils.getAnnotation(method, CustomScheduled.class); if (newScheduledAnnotation != null) { LOG.info("@CustomScheduled found at method {}", method.getName()); Assert.isTrue(void.class.equals(method.getReturnType()), "Only void-returning methods may be annotated with @CustomScheduled."); Assert.isTrue(method.getParameterTypes().length == 0, "Only no-arg methods may be annotated with @CustomScheduled."); if (AopUtils.isJdkDynamicProxy(bean)) { try { // found a @CustomScheduled method on the target class for this JDK proxy -> is it // also present on the proxy itself? method = bean.getClass().getMethod(method.getName(), method.getParameterTypes()); } catch (SecurityException ex) { ReflectionUtils.handleReflectionException(ex); } catch (NoSuchMethodException ex) { throw new IllegalStateException(String.format("@CustomScheduled method '%s' found on bean target class '%s', " + "but not found in any interface(s) for bean JDK proxy. Either " + "pull the method up to an interface or switch to subclass (CGLIB) " + "proxies by setting proxy-target-class/proxyTargetClass " + "attribute to 'true'", method.getName(), targetClass.getSimpleName())); } } Runnable runnable = new ScheduledMethodRunnable(bean, method); boolean processedSchedule = false; String errorMessage = "Exactly one of 'cron', 'fixedDelay', or 'fixedRate' is required."; boolean numberFormatException = false; String numberFormatErrorMessage = "Delay value is not a number!"; String cron = newScheduledAnnotation.cron(); if (!"".equals(cron)) { processedSchedule = true; if (embeddedValueResolver != null) { cron = embeddedValueResolver.resolveStringValue(cron); } cronTasks.put(runnable, cron); LOG.info("Put cron in tasks map with value {}", cron); } // fixedDelay value resolving Long fixedDelay = null; String resolverDelayCandidate = newScheduledAnnotation.fixedDelay(); if (!"".equals(resolverDelayCandidate)) { try { if (embeddedValueResolver != null) { resolverDelayCandidate = embeddedValueResolver.resolveStringValue(resolverDelayCandidate); fixedDelay = Long.valueOf(resolverDelayCandidate); } else { fixedDelay = Long.valueOf(newScheduledAnnotation.fixedDelay()); } } catch (NumberFormatException e) { numberFormatException = true; } } Assert.isTrue(!numberFormatException, numberFormatErrorMessage); if (fixedDelay != null && fixedDelay >= 0) { Assert.isTrue(!processedSchedule, errorMessage); processedSchedule = true; fixedDelayTasks.put(runnable, fixedDelay); LOG.info("Put fixedDelay in tasks map with value {}", fixedDelay); } // fixedRate value resolving Long fixedRate = null; String resolverRateCandidate = newScheduledAnnotation.fixedRate(); if (!"".equals(resolverRateCandidate)) { try { if (embeddedValueResolver != null) { fixedRate = Long.valueOf(embeddedValueResolver.resolveStringValue(resolverRateCandidate)); } else { fixedRate = Long.valueOf(newScheduledAnnotation.fixedRate()); } } catch (NumberFormatException e) { numberFormatException = true; } } Assert.isTrue(!numberFormatException, numberFormatErrorMessage); if (fixedRate != null && fixedRate >= 0) { Assert.isTrue(!processedSchedule, errorMessage); processedSchedule = true; fixedRateTasks.put(runnable, fixedRate); LOG.info("Put fixedRate in tasks map with value {}", fixedRate); } Assert.isTrue(processedSchedule, errorMessage); } } }); return bean; } }
spring-context.xml 설정 파일
<beans...> <!-- Enables the use of a @CustomScheduled annotation--> <bean class="org.package.CustomScheduledAnnotationBeanPostProcessor" /> </beans>
-
==============================
4.일부 스프링 주석은 SpEL을 지원합니다.
일부 스프링 주석은 SpEL을 지원합니다.
먼저:
<context:property-placeholder location="file:${external.config.location}/application.properties" />
그리고 나서, 예를 들면 :
@Value("${delayValue}") private int delayValue;
@Scheduled가 SPeL을 지원하는지 잘 모르겠지만, 일반적으로 접근 방법입니다.
일정 계획과 관련하여이 게시물과이 관련 질문을 확인하십시오.
-
==============================
5.bean 구성 xml이 아닌 주석으로이 작업을 수행하려면 @Component, PropertySourcesPlaceholderConfigurer Bean과 함께 @PropertySource와 같이 다음과 같은 주석을 사용할 수 있습니다.
bean 구성 xml이 아닌 주석으로이 작업을 수행하려면 @Component, PropertySourcesPlaceholderConfigurer Bean과 함께 @PropertySource와 같이 다음과 같은 주석을 사용할 수 있습니다.
@Component @PropertySource({ "classpath:scheduling.properties" }) public class SomeClass { @Scheduled(fixedDelay = "${delay}") public void someMethod(){ // perform something } @Bean public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } }
from https://stackoverflow.com/questions/11608531/injecting-externalized-value-into-spring-annotation by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Spring Boot RestController에서 요청 URL을 얻는 방법 (0) | 2019.03.18 |
---|---|
[SPRING] Spring 3.2와 Cache Abstraction에서 EhCache 구현이 누락되었습니다. (0) | 2019.03.18 |
[SPRING] Maven : Spring 4 + Spring 보안 (0) | 2019.03.18 |
[SPRING] 스프링 부트가없는 스프링 데이터 JPA (0) | 2019.03.18 |
[SPRING] IntelliJ IDEA에서 Spring 패싯을 구성하는 방법 (0) | 2019.03.18 |