web-gelistirme-sc.com

Dış eklenmiş değerin Bahar ek açıklamasına enjekte edilmesi

Derleme zamanında ek açıklama değerlerini değerlendiren Java özelliğini düşünüyorum ve ek açıklama değerlerini gerçekten dışsallaştırmanın zorlaştığı görülüyor.

Ancak, aslında imkansız olup olmadığından emin değilim, bu yüzden bu konuda herhangi bir öneri veya kesin cevaplar için teşekkür ederiz.

Dahası, Spring’de programlanmış yöntem çağrıları arasındaki gecikmeleri kontrol eden bir ek açıklama değeri dışlamaya çalışıyorum, örn .:

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 öğesinin sınıf yolunda olduğunu ve karşılık gelen uzun değeri ile birlikte delayValue özellik anahtarını içerdiğini varsayalım.

Şimdi, bu kod, final değişkenine bir değer atamaya çalıştığımızdan açıkça derleme hataları içeriyor, ancak bu zorunlu, çünkü değişken, static final olmadıkça açıklama değerine atayamıyoruz.

Bunu aşmanın bir yolu var mı? Spring'in özel ek açıklamalarını düşünüyordum, ancak temel sorun hala - ek açıklama için dışsal değer nasıl atanır?

Herhangi bir fikir açığız.

EDIT: Küçük bir güncelleme - Quartz entegrasyonu bu örnekte geçersizdir. Sadece dakika altı çözünürlükte periyodik bir yürütmeye ihtiyacımız var ve hepsi bu.

23
quantum

Spring v3.2.2'deki @Scheduled notu, bunu işlemek için orijinal 3 uzun parametreye String parametreleri ekledi. fixedDelayString, fixedRateString ve initialDelayString şimdi de mevcuttur:

 @Scheduled(fixedDelayString = "${my.delay.property}")
 public void someMethod(){
        // perform something
 }
63
Mark-A

Bunu yapmanın daha iyi bir yolu, görev adı alanını kullanarak zamanlamayı xml olarak tanımlamaktır.

<context:property-placeholder location="scheduling.properties"/>
<task:scheduled ref="someBean" method="someMethod" fixed-delay="${delayValue}"/>

Bir nedenden dolayı ek açıklama yapmak istiyorsanız, özellik adını veya daha iyi bir özellik yer tutucu ifadesini veya Spel ifadesini belirtebileceğiniz başka bir isteğe bağlı niteliğe sahip bir ek açıklama oluşturmanız gerekir.

@MyScheduled(fixedDelayString="${delay}")
3
gkamal

Cevaplarınız için ikinize de teşekkür ederim, beni bu çözüme götüren değerli bilgiler verdiniz, bu yüzden her iki cevabı da yükselttim.

Özel bir fasulye sonrası işlemci ve özel @Scheduled ek açıklama yapmayı seçtim.

Kod basittir (temelde mevcut Spring kodunun önemsiz bir uyarlamasıdır) ve gerçekten neden baştan beri böyle yapmadıklarını merak ediyorum. BeanPostProcessor 'ın kod sayımı, eski ek açıklamaları ve yenilerini kullanmayı seçtiğim için etkin bir şekilde ikiye katlandı.

Bu kodu nasıl geliştireceğinize dair herhangi bir öneriniz varsa, duyduğuma memnun olurum.

CustomScheduled class (açıklama)

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomScheduled {

    String cron() default "";

    String fixedDelay() default "";

    String fixedRate() default "";
}

CustomScheduledAnnotationBeanPostProcessor class

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 config dosyası

<beans...>
    <!-- Enables the use of a @CustomScheduled annotation-->
    <bean class="org.package.CustomScheduledAnnotationBeanPostProcessor" />
</beans>
3
quantum

Bazı bahar ek açıklamaları SpEL'i desteklemektedir.

İlk:

<context:property-placeholder
    location="file:${external.config.location}/application.properties" />

Ve sonra, örneğin:

@Value("${delayValue}")
private int delayValue;

@Scheduled'ın SPeL'i destekleyip desteklemediğinden emin değilim, ancak genel olarak bu yaklaşım.

Programlamaya ilişkin olarak, bu yazı benim ve bu ilgili soruyu kontrol edin

2
Bozho

Bunu xml yapılandırması yerine fasulye eklemesiyle yapmak isterseniz, aşağıdaki ek açıklamaları kullanabilirsiniz: @Component, @ PropertySourcesPlaceholderConfigurer Bean'in kendisiyle, şöyle:

@Component
@PropertySource({ "classpath:scheduling.properties" })
public class SomeClass {

    @Scheduled(fixedDelay = "${delay}")
    public void someMethod(){
        // perform something
    }

    @Bean
    public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }   
}
0
selins sofa