INT-3365: Add SmartLifecycle for Annotations
JIRA: https://jira.spring.io/browse/INT-3365 INT-3365 Polishing
This commit is contained in:
committed by
Gary Russell
parent
55c4e26619
commit
3f40c40641
@@ -65,6 +65,14 @@ public @interface Aggregator {
|
||||
*/
|
||||
boolean sendPartialResultsOnExpiry() default false;
|
||||
|
||||
/*
|
||||
{@code SmartLifecycle} options.
|
||||
Can be specified as 'property placeholder', e.g. {@code ${foo.autoStartup}}.
|
||||
*/
|
||||
String autoStartup() default "true";
|
||||
|
||||
String phase() default "0";
|
||||
|
||||
/**
|
||||
* @return the {@link Poller} options for a polled endpoint
|
||||
* ({@link org.springframework.integration.scheduling.PollerMetadata}).
|
||||
|
||||
@@ -52,6 +52,14 @@ public @interface Filter {
|
||||
|
||||
boolean discardWithinAdvice() default true;
|
||||
|
||||
/*
|
||||
{@code SmartLifecycle} options.
|
||||
Can be specified as 'property placeholder', e.g. {@code ${foo.autoStartup}}.
|
||||
*/
|
||||
String autoStartup() default "true";
|
||||
|
||||
String phase() default "0";
|
||||
|
||||
/**
|
||||
* @return the {@link Poller} options for a polled endpoint
|
||||
* ({@link org.springframework.integration.scheduling.PollerMetadata}).
|
||||
|
||||
@@ -56,6 +56,14 @@ public @interface InboundChannelAdapter {
|
||||
*/
|
||||
String value();
|
||||
|
||||
/*
|
||||
{@code SmartLifecycle} options.
|
||||
Can be specified as 'property placeholder', e.g. {@code ${foo.autoStartup}}.
|
||||
*/
|
||||
String autoStartup() default "true";
|
||||
|
||||
String phase() default "0";
|
||||
|
||||
/**
|
||||
* @return the {@link org.springframework.integration.annotation.Poller} options for a polled endpoint
|
||||
* ({@link org.springframework.integration.scheduling.PollerMetadata}).
|
||||
|
||||
@@ -53,6 +53,14 @@ public @interface Router {
|
||||
|
||||
String defaultOutputChannel() default "";
|
||||
|
||||
/*
|
||||
{@code SmartLifecycle} options.
|
||||
Can be specified as 'property placeholder', e.g. {@code ${foo.autoStartup}}.
|
||||
*/
|
||||
String autoStartup() default "true";
|
||||
|
||||
String phase() default "0";
|
||||
|
||||
/**
|
||||
* @return the {@link Poller} options for a polled endpoint
|
||||
* ({@link org.springframework.integration.scheduling.PollerMetadata}).
|
||||
|
||||
@@ -53,6 +53,14 @@ public @interface ServiceActivator {
|
||||
|
||||
String[] adviceChain() default {};
|
||||
|
||||
/*
|
||||
{@code SmartLifecycle} options.
|
||||
Can be specified as 'property placeholder', e.g. {@code ${foo.autoStartup}}.
|
||||
*/
|
||||
String autoStartup() default "true";
|
||||
|
||||
String phase() default "0";
|
||||
|
||||
/**
|
||||
* @return the {@link Poller} options for a polled endpoint
|
||||
* ({@link org.springframework.integration.scheduling.PollerMetadata}).
|
||||
|
||||
@@ -52,6 +52,14 @@ public @interface Splitter {
|
||||
|
||||
String[] adviceChain() default {};
|
||||
|
||||
/*
|
||||
{@code SmartLifecycle} options.
|
||||
Can be specified as 'property placeholder', e.g. {@code ${foo.autoStartup}}.
|
||||
*/
|
||||
String autoStartup() default "true";
|
||||
|
||||
String phase() default "0";
|
||||
|
||||
/**
|
||||
* @return the {@link Poller} options for a polled endpoint
|
||||
* ({@link org.springframework.integration.scheduling.PollerMetadata}).
|
||||
|
||||
@@ -43,6 +43,14 @@ public @interface Transformer {
|
||||
|
||||
String[] adviceChain() default {};
|
||||
|
||||
/*
|
||||
{@code SmartLifecycle} options.
|
||||
Can be specified as 'property placeholder', e.g. {@code ${foo.autoStartup}}.
|
||||
*/
|
||||
String autoStartup() default "true";
|
||||
|
||||
String phase() default "0";
|
||||
|
||||
/**
|
||||
* @return the {@link Poller} options for a polled endpoint
|
||||
* ({@link org.springframework.integration.scheduling.PollerMetadata}).
|
||||
|
||||
@@ -84,6 +84,7 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
|
||||
private volatile boolean running = true;
|
||||
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
Assert.isAssignable(ConfigurableListableBeanFactory.class, beanFactory.getClass(),
|
||||
"a ConfigurableListableBeanFactory is required");
|
||||
@@ -95,6 +96,7 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
Assert.notNull(this.beanFactory, "BeanFactory must not be null");
|
||||
postProcessors.put(Filter.class, new FilterAnnotationPostProcessor(this.beanFactory, this.environment));
|
||||
@@ -106,10 +108,12 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
|
||||
postProcessors.put(InboundChannelAdapter.class, new InboundChannelAdapterAnnotationPostProcessor(this.beanFactory, this.environment));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
|
||||
Assert.notNull(this.beanFactory, "BeanFactory must not be null");
|
||||
final Class<?> beanClass = this.getBeanClass(bean);
|
||||
@@ -118,6 +122,7 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
|
||||
return bean;
|
||||
}
|
||||
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
Annotation[] annotations = AnnotationUtils.getAnnotations(method);
|
||||
@@ -127,6 +132,26 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
|
||||
Object result = postProcessor.postProcess(bean, beanName, method, annotation);
|
||||
if (result != null && result instanceof AbstractEndpoint) {
|
||||
AbstractEndpoint endpoint = (AbstractEndpoint) result;
|
||||
String autoStartup = (String) AnnotationUtils.getValue(annotation, "autoStartup");
|
||||
if (StringUtils.hasText(autoStartup)) {
|
||||
if (environment != null) {
|
||||
autoStartup = environment.resolvePlaceholders(autoStartup);
|
||||
}
|
||||
if (StringUtils.hasText(autoStartup)) {
|
||||
endpoint.setAutoStartup(Boolean.parseBoolean(autoStartup));
|
||||
}
|
||||
}
|
||||
|
||||
String phase = (String) AnnotationUtils.getValue(annotation, "phase");
|
||||
if (StringUtils.hasText(phase)) {
|
||||
if (environment != null) {
|
||||
phase = environment.resolvePlaceholders(phase);
|
||||
}
|
||||
if (StringUtils.hasText(phase)) {
|
||||
endpoint.setPhase(Integer.parseInt(phase));
|
||||
}
|
||||
}
|
||||
|
||||
String endpointBeanName = generateBeanName(beanName, method, annotation.annotationType());
|
||||
endpoint.setBeanName(endpointBeanName);
|
||||
beanFactory.registerSingleton(endpointBeanName, endpoint);
|
||||
@@ -192,6 +217,7 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
for (ApplicationListener<ApplicationEvent> listener : listeners) {
|
||||
try {
|
||||
@@ -208,10 +234,12 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
|
||||
|
||||
// Lifecycle implementation
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return this.running;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
for (Lifecycle lifecycle : this.lifecycles) {
|
||||
if (!lifecycle.isRunning()) {
|
||||
@@ -221,6 +249,7 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
|
||||
this.running = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
for (Lifecycle lifecycle : this.lifecycles) {
|
||||
if (lifecycle.isRunning()) {
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.config.AbstractFactoryBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
@@ -222,7 +223,8 @@ public class EnableIntegrationTests {
|
||||
assertNotNull(messageHistory);
|
||||
String messageHistoryString = messageHistory.toString();
|
||||
assertThat(messageHistoryString, Matchers.containsString("input"));
|
||||
assertThat(messageHistoryString, Matchers.containsString("AnnotationTestService.handle.serviceActivator.handler"));
|
||||
assertThat(messageHistoryString,
|
||||
Matchers.containsString("AnnotationTestService.handle.serviceActivator.handler"));
|
||||
assertThat(messageHistoryString, Matchers.not(Matchers.containsString("output")));
|
||||
|
||||
receive = this.publishedChannel.receive(1000);
|
||||
@@ -240,10 +242,20 @@ public class EnableIntegrationTests {
|
||||
assertThat(this.testChannelInterceptor.getInvoked(), Matchers.greaterThan(0));
|
||||
assertThat(this.fbInterceptorCounter.get(), Matchers.greaterThan(0));
|
||||
|
||||
assertTrue(this.context.containsBean("enableIntegrationTests.AnnotationTestService.count.inboundChannelAdapter.source"));
|
||||
Object messageSource = this.context.getBean("enableIntegrationTests.AnnotationTestService.count.inboundChannelAdapter.source");
|
||||
assertTrue(this.context
|
||||
.containsBean("enableIntegrationTests.AnnotationTestService.count.inboundChannelAdapter.source"));
|
||||
Object messageSource = this.context
|
||||
.getBean("enableIntegrationTests.AnnotationTestService.count.inboundChannelAdapter.source");
|
||||
assertThat(messageSource, Matchers.instanceOf(MethodInvokingMessageSource.class));
|
||||
|
||||
assertNull(this.counterChannel.receive(10));
|
||||
|
||||
SmartLifecycle countSA = this.context.getBean("enableIntegrationTests.AnnotationTestService.count.inboundChannelAdapter",
|
||||
SmartLifecycle.class);
|
||||
assertFalse(countSA.isAutoStartup());
|
||||
assertEquals(23, countSA.getPhase());
|
||||
countSA.start();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Message<?> message = this.counterChannel.receive(1000);
|
||||
assertNotNull(message);
|
||||
@@ -266,14 +278,14 @@ public class EnableIntegrationTests {
|
||||
@DirtiesContext
|
||||
public void testChangePatterns() {
|
||||
try {
|
||||
this.configurer.setComponentNamePatterns(new String[]{"*"});
|
||||
this.configurer.setComponentNamePatterns(new String[] {"*"});
|
||||
fail("ExpectedException");
|
||||
}
|
||||
catch (IllegalStateException e) {
|
||||
assertThat(e.getMessage(), containsString("cannot be changed"));
|
||||
}
|
||||
this.configurer.stop();
|
||||
this.configurer.setComponentNamePatterns(new String[]{"*"});
|
||||
this.configurer.setComponentNamePatterns(new String[] {"*"});
|
||||
assertEquals("*", TestUtils.getPropertyValue(this.configurer, "componentNamePatterns", String[].class)[0]);
|
||||
}
|
||||
|
||||
@@ -548,7 +560,7 @@ public class EnableIntegrationTests {
|
||||
@MessageEndpoint
|
||||
public static class AnnotationTestService {
|
||||
|
||||
private AtomicInteger counter = new AtomicInteger();
|
||||
private final AtomicInteger counter = new AtomicInteger();
|
||||
|
||||
@ServiceActivator(inputChannel = "input", outputChannel = "output",
|
||||
poller = @Poller(maxMessagesPerPoll = "${poller.maxMessagesPerPoll}", fixedDelay = "${poller.interval}"))
|
||||
@@ -608,7 +620,8 @@ public class EnableIntegrationTests {
|
||||
return this.handle(message.getPayload());
|
||||
}
|
||||
|
||||
@InboundChannelAdapter("counterChannel")
|
||||
@InboundChannelAdapter(value = "counterChannel", autoStartup = "false",
|
||||
phase = "23")
|
||||
public Integer count() {
|
||||
return this.counter.incrementAndGet();
|
||||
}
|
||||
@@ -618,7 +631,8 @@ public class EnableIntegrationTests {
|
||||
return "foo";
|
||||
}
|
||||
|
||||
@InboundChannelAdapter(value = "messageChannel", poller = @Poller(fixedDelay = "${poller.interval}", maxMessagesPerPoll = "1"))
|
||||
@InboundChannelAdapter(value = "messageChannel", poller = @Poller(fixedDelay = "${poller.interval}",
|
||||
maxMessagesPerPoll = "1"))
|
||||
public Message<?> message() {
|
||||
return MessageBuilder.withPayload("bar").setHeader("foo", "FOO").build();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user