@SpringBootApplication(scanBasePackages = {"io.github.meta.ease.bpm"})@ComponentScan(basePackages ={"io.github.meta.ease.bpm"} )public class QuickstartApplication { public static void main(String[] args) { SpringApplication.run(QuickstartApplication.class, args); }}
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'springAsyncExecutor' defined in class path resource [org/activiti/spring/boot/ProcessEngineAutoConfiguration.class]: Unsatisfied dependency expressed through method 'springAsyncExecutor' parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.core.task.TaskExecutor' available: expected single matching bean but found 3: jobTaskScheduler,dataConvertTheadPool,threadPoolat org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:541)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1389)at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1309)at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)... 105 common frames omittedCaused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.core.task.TaskExecutor' available: expected single matching bean but found 3: jobTaskScheduler,dataConvertTheadPool,threadPoolat org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:220)at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1367)at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1309)at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)... 119 common frames omitted
无法创建 自动配置ProcessEngineAutoConfiguration 中的 bean springAsyncExecutor,由于所依赖的bean 类型 org.springframework.core.task.TaskExecutor无法找到唯一的bean实例。
@Bean产生一个bean并且交给Spring容器管理,如果即将要产生的Bean依赖另外一个Bean,使用Autowired的依赖策略。而@Autowired依赖原理如下:
1、@Autowired是Spring自带的注解,通过AutowiredAnnotationBeanPostProcessor 类实现的依赖注入
2、@Autowired可以作用在CONSTRUCTOR、METHOD、PARAMETER、FIELD、ANNOTATION_TYPE
3、@Autowired默认是根据类型(byType )进行自动装配的
4、如果有多个类型一样的Bean候选者,需要指定按照名称(byName )进行装配,则需要配合@Qualifier。指定名称后,如果Spring IOC容器中没有对应的组件bean抛出NoSuchBeanDefinitionException。也可以将@Autowired中required配置为false,如果配置为false之后,当没有找到相应bean的时候,系统不会抛异常
注意@ComponentScan(basePackages = {"io.github.meta.ease.bpm"})
package io.github.meta.ease.bpm;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.ComponentScan;@SpringBootApplication@ComponentScan(basePackages = {"io.github.meta.ease.bpm"})public class QuickstartApplication { public static void main(String[] args) { SpringApplication.run(QuickstartApplication.class, args); }}
package io.github.meta.ease.bpm;import org.springframework.beans.factory.InitializingBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;@Configuration(proxyBeanMethods = false)public class ScheduleJobAutoConfiguration implements InitializingBean { @Bean({"jobTaskScheduler"}) public ThreadPoolTaskScheduler jobTaskScheduler() { ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); taskScheduler.setThreadNamePrefix("job-scheduler-"); taskScheduler.setPoolSize(Runtime.getRuntime().availableProcessors()); taskScheduler.setDaemon(true); taskScheduler.setWaitForTasksToCompleteOnShutdown(true); return taskScheduler; } @Bean public ThreadPoolTaskExecutor dataConvertTheadPool() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.initialize(); return executor; } @Override public void afterPropertiesSet() throws Exception { }}
package io.activiti.spring.boot;import org.springframework.boot.autoconfigure.AutoConfigureAfter;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.task.TaskExecutor;@Configuration@AutoConfigureAfter(name = {"org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration", "org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration"})public class ProcessEngineAutoConfiguration { @Bean public SpringAsyncExecutor springAsyncExecutor(TaskExecutor applicationTaskExecutor) { return new SpringAsyncExecutor(applicationTaskExecutor); }}public class SpringAsyncExecutor { public SpringAsyncExecutor(TaskExecutor applicationTaskExecutor) { }}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ io.activiti.spring.boot.ProcessEngineAutoConfiguration,\ io.github.meta.ease.bpm.ScheduleJobAutoConfiguration
Parameter 0 of method springAsyncExecutor in io.activiti.spring.boot.ProcessEngineAutoConfiguration required a single bean, but 2 were found:- jobTaskScheduler: defined by method 'jobTaskScheduler' in class path resource [io/github/meta/ease/bpm/ScheduleJobAutoConfiguration.class]- dataConvertTheadPool: defined by method 'dataConvertTheadPool' in class path resource [io/github/meta/ease/bpm/ScheduleJobAutoConfiguration.class]Action:Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumedDisconnected from the target VM, address: '127.0.0.1:49825', transport: 'socket'Process finished with exit code 1
spring 注入Bean流程
@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");// Invoke factory processors registered as beans in the context. //开始注入Bean定义invokeBeanFactoryPostProcessors(beanFactory);
ConfigurationClassPostProcessor
@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {int registryId = System.identityHashCode(registry);if (this.registriesPostProcessed.contains(registryId)) {throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);}if (this.factoriesPostProcessed.contains(registryId)) {throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);}this.registriesPostProcessed.add(registryId); //processConfigBeanDefinitions(registry);}public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {List configCandidates = new ArrayList<>();String[] candidateNames = registry.getBeanDefinitionNames();for (String beanName : candidateNames) {BeanDefinition beanDef = registry.getBeanDefinition(beanName);if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {if (logger.isDebugEnabled()) {logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);}}else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));}} ...... // Parse each @Configuration class // 扫描基于@Config 配置的Bean,正由于是主启动类外部自己加载了ComponentScan注解,导致ComponentScan的扫描的优先级高于自动配置类ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment,this.resourceLoader, this.componentScanBeanNameGenerator, registry);Set candidates = new LinkedHashSet<>(configCandidates);Set alreadyParsed = new HashSet<>(configCandidates.size());do {StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse"); // 扫描基于@Config 配置的Bean,正由于是主启动类外部自己加载了ComponentScan注解,导致ComponentScan的扫描的优先级高于自动配置类 parser.parse(candidates);parser.validate();}
ConfigurationClassParser:重点逻辑(此处获取的componentScans 属性是Spring单独@ComponentScan配置,导致自定义扫描的jar包提前进入到Spring IOC容器内部)
Set componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {for (AnnotationAttributes componentScan : componentScans) {// The config class is annotated with @ComponentScan -> perform the scan immediatelySet scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());// Check the set of scanned definitions for any further config classes and parse recursively if neededfor (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand == null) {bdCand = holder.getBeanDefinition();}if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());}}}}
主启动类不配置 //@ComponentScan(basePackages ={"io.github.meta.ease.bpm"} )
主启动类单独配置@ComponentScan(basePackages ={"io.github.meta.ease.bpm"} )
从这两个图基本可以确定问题的原因。
继续Debug 后续流程 ComponentScanAnnotationParser、ClassPathBeanDefinitionScanner.doScan(String... basePackages)可以明确问题原因。
ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
AutoConfigurationExcludeFilter匹配注册的自动配置类的 TypeFilter 实现,排除了自动配置相关实现的Bean。
@Configuration@AutoConfigureAfter(name = {"org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration", "org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration"})public class ProcessEngineAutoConfiguration { @Bean public SpringAsyncExecutor springAsyncExecutor(@Qualifier("applicationTaskExecutor") TaskExecutor applicationTaskExecutor) { return new SpringAsyncExecutor(applicationTaskExecutor); }}
@SpringBootApplication(scanBasePackages = {"io.github.meta.ease.bpm"})//@ComponentScan(basePackages ={"io.github.meta.ease.bpm"} )public class QuickstartApplication { public static void main(String[] args) { SpringApplication.run(QuickstartApplication.class, args); }}
留言与评论(共有 0 条评论) “” |