我一直在思考编译时评估注释值的Java特性,它似乎真的很难外部化注释值。
但是,我不确定这是否真的是不可能的,所以我非常感谢对此的任何建议或明确的答案。
更重要的是,我试图将控制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
}
}
假设调度 .属性
位于类路径上,并且包含属性键延迟值
及其相应的长整型值。
现在,这段代码有明显的编译错误,因为我们试图将值赋给final
变量,但这是强制性的,因为我们不能将变量赋给注释值,除非它是static final
。
有没有办法解决这个问题?我一直在考虑Spring的自定义注释,但根本问题仍然存在 - 如何将外部化值分配给注释?
任何想法都是受欢迎的。
编辑:一个小的更新——石英集成对于这个例子来说是多余的。我们只需要一个亚分钟分辨率的定期执行,仅此而已。
一些Spring注释支持SpEL。
第一:
<context:property-placeholder
location="file:${external.config.location}/application.properties" />
然后,举个例子:
@Value("${delayValue}")
private int delayValue;
我不确定@Scheduled
是否支持SPeL,但总的来说,这就是方法。
关于日程安排,请查看我的这篇文章和这个相关问题
感谢你们两位的回答,你们提供了有价值的信息,引导我找到了这个解决方案,所以我投票支持这两个答案。
我选择了制作一个自定义bean后处理器和自定义@计划
注释。
代码很简单(本质上是对现有Spring代码的简单改编),我真的想知道他们为什么不从一开始就这样做。自从我选择处理旧注释和新注释以来,< code>BeanPostProcessor的代码数量实际上增加了一倍。
如果您对如何改进此代码有任何建议,我将很高兴听到。
自定义计划类(注释)
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomScheduled {
String cron() default "";
String fixedDelay() default "";
String fixedRate() default "";
}
CustomScheduledAnnotationBeanPostProcessor类
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>
Spring v3.2.2 中的@Scheduled
注释已将 String 参数添加到原始的 3 个 long 参数中来处理此问题。固定延迟字符串
,固定速率字符串
和初始延迟字符串
现在也可用:
@Scheduled(fixedDelayString = "${my.delay.property}")
public void someMethod(){
// perform something
}
我试图向自定义注释中注入一个值,但Spring似乎没有进行评估。
我有一个正在使用jar的项目a,比如(其中B是在项目a中用作依赖项的另一个项目),现在有一个(类似于缓存),它在映射中保存所需的所有数据。这个映射bean被project(在我的项目中作为包含)使用,即B来读取缓存属性,但我无法这样做,有什么帮助吗? 项目B的webapp-config.xml 上面的bean b2必须在外部项目B中使用(作为jar包含在我的项目A中)。 但我得到了 任何帮助都将不
基本上,我的项目是一场战争(MyProject),导入2罐,MyProject-Client和MyProjectJar-API 我的项目 MyProjectJar-API - 有一个接口 MyProject-Client -想要注入在MyProject上生成的ParametroService 我想知道是否可以将ParameterService(在MyProject上生成)注入MyProject客户
我们在产品中使用Spring引导微服务,我们有多达10个应用程序。为了记录,我们使用Log4j MDC来生成事务标识,并使用拦截器和过滤器将其传递给服务[超文本传输协议标头]。问题是我们必须在我们所有的应用程序(比如10个)中添加拦截器和过滤器来跟踪这个事务。有没有办法在我们的微服务应用程序中创建jar并注入。 我们能否在所有应用程序中使用最少的代码更改来实现这一点?
当我使用强化工具扫描时,我在“XML外部实体注入”下遇到了一些问题。 这是它显示错误的地方。根据fortify的建议,我给出了以下修复方法 但是问题仍然没有解决。如何解决这个问题?
imi 中有一类注解,他们支持将值动态注入到注解属性中,当调用获取注解属性时,才实时计算并返回。 注解说明 @ConstValue 从常量中读取值 属性名称 说明 name 常量名 default 常量不存在时,返回的默认值 @ConfigValue 从配置中读取值 属性名称 说明 name 配置名,支持@app、@currentServer等用法 default 配置名,支持@app、@curr