0

This is a simplification of the real scenario to reproduce the problem. The configuration process may look odd but it's because I have put all of the configuration classes in the same project, but actually they are separated among the application and some libraries.

This is my Spring Boot application main class:

@SpringBootApplication(scanBasePackageClasses={ SomeConfig.class})
public class MySpringBootApplication {

    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class, args);
    }
... 

SomeConfig.java:

@Configuration
@ImportResource("classpath:library.mail-executor.xml")
public class SomeConfig{}

library.mail-executor.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/util
           http://www.springframework.org/schema/util/spring-util.xsd ">

    <bean class=xxx.MyAsyncExecutorConfig"/>

</beans>

MyAsyncExecutorConfig.java:

@Configuration
@ImportResource("classpath:library.jobs-executor.xml")
public class MyAsyncExecutorConfig {}

}

library.jobs-executor.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:task="http://www.springframework.org/schema/task"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/task 
           http://www.springframework.org/schema/task/spring-task.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">

    <task:annotation-driven executor="mainWorkExecutor"/>

    <bean id="mainWorkExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <property name="corePoolSize" value="${jobs.corePoolSize:5}" />
        <property name="maxPoolSize" value="${jobs.maxPoolSize:10}" />
        <property name="queueCapacity" value="${jobs.queueCapacity:25}" />
    </bean>

</beans>

To sum up, SomeConfig imports library.mail-executor.xml which imports MyAsyncExecutorConfig whis imports library.jobs-executor.xml.

This is the exception: Configuration problem: Only one ScheduledAnnotationBeanPostProcessor may exist within the context:

2016-09-01T13:02:56.935 ( -  -  -  -  - ) o.s.b.SpringApplication ERROR - Application startup failed
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Only one ScheduledAnnotationBeanPostProcessor may exist within the context.
Offending resource: class path resource [es/mma/architecture/spring/library.jobs-executor.xml]
    at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:70) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:72) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.scheduling.config.AnnotationDrivenBeanDefinitionParser.parse(AnnotationDrivenBeanDefinitionParser.java:90) ~[spring-context-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:74) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1411) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1401) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:168) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:138) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:94) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:508) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:392) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:336) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:181) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:217) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromImportedResources(ConfigurationClassBeanDefinitionReader.java:346) ~[spring-context-4.2.5.RELEASE.jar:4.2.5.RELEASE]

FACTS:

I don't have @EnableScheduling anywhere.

Something VERY strange, if I get rid of MyAsyncExecutorConfig and import directly library.jobs-executor.xml on SomeConfig, it works OK. !!!??? For instance:

SomeConfig.java:

@Configuration
@ImportResource("classpath:library.jobs-executor.xml")
public class SomeConfig{}

If I import library.jobs-executor.xml directly on library.mail-executor.xml it also works. !!!??? For instance:

SomeConfig.java:

@Configuration
@ImportResource("classpath:library.mail-executor.xml")
public class SomeConfig{}

library.mail-executor.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/util
           http://www.springframework.org/schema/util/spring-util.xsd ">

    <import resource="classpath:library.jobs-executor.xml"/>
</beans>

So the problem only arises when the library.jobs-executor.xml is imported in the last @Configuration class.

Notice that I can't modify this flow. How come that postprocessor seems to be registered twice????

codependent
  • 23,193
  • 31
  • 166
  • 308
  • 2
    Because your `MyAsyncExecutorConfig` is loaded twice. Once through XML and once detected by the component scanning of spring boot. – M. Deinum Sep 01 '16 at 12:17
  • I shoud've put the packages... actually MyAsyncExecutorConfig isn't scanned, its package is not covered by the scanning. – codependent Sep 01 '16 at 12:31
  • There must be something loading your configuration, as you aren't showing actual code it is hard to tell. The fact that you only specify a base package doesn't mean there isn't another configuration class (or class) with a `@ComponentScan` or something alike that it gets picked up. I also don't really get why you are using `@Configuration` class to load xml... why not directly load the xml. Seems you are making things overly complex. – M. Deinum Sep 01 '16 at 13:52
  • https://stackoverflow.com/a/61258683/715269 – Gangnus Apr 16 '20 at 20:46

1 Answers1

0

The problem was in the actuator. It includes a metrics exporter that uses @EnableScheduler and created the conflicting post processor.

You can either disable it with spring.metrics.export.enabled: false or add a @Condition in order not to import the library.jobs-executor.xml if it exists:

public class InternalScheduledAnnotationProcessorDoesntExistCondition implements ConfigurationCondition{

    @Override
    public ConfigurationPhase getConfigurationPhase() {
        return ConfigurationPhase.PARSE_CONFIGURATION;
    }

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        try{
            context.getRegistry().getBeanDefinition("org.springframework.context.annotation.internalScheduledAnnotationProcessor");
            return false;
        }catch(NoSuchBeanDefinitionException nsde){
            return true;
        }
    }

}

MyAsyncExecutorConfig.java:

@Configuration
@Conditional(InternalScheduledAnnotationProcessorDoesntExistCondition.class)
@ImportResource("classpath:library.jobs-executor.xml")
public class MyAsyncExecutorConfig {}
codependent
  • 23,193
  • 31
  • 166
  • 308