Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bean overriding for 'taskExecutor' alias is not detected #25430

Closed
rgampa opened this issue Aug 9, 2019 · 8 comments
Closed

Bean overriding for 'taskExecutor' alias is not detected #25430

rgampa opened this issue Aug 9, 2019 · 8 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: bug A general bug
Milestone

Comments

@rgampa
Copy link

rgampa commented Aug 9, 2019

Earlier I was using 2.0.9.RELEASE, i have simply upgraded to 2.1.7.RELEASE. One of the bean couldn't be found or scanned by ComponentScan.

***************************
APPLICATION FAILED TO START
***************************
Description:
Field taskExecutor in com.helper.Helper required a bean of type 'com.task.TaskExecutor' that could not be found.
The injection point has the following annotations:
	- @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.task.TaskExecutor' in your configuration.

In main class @ComponentScan is present and TaskExecutor is annotated with @Component.

I have tried moving up the main class, but didn't help still.

@rgampa
Copy link
Author

rgampa commented Aug 10, 2019

UPDATE

Looks the problem is with the class name, by changing it to TaskExecutorImpl it worked.

Works

@Component("taskExecutorImpl")
public class TaskExecutorImpl

@Autowired
    private TaskExecutorImpl taskExecutorImpl;

Doesn't work

@Component("taskExecutot")
public class TaskExecutor

@Autowired
    private TaskExecutor taskExecutor;

@snicoll
Copy link
Member

snicoll commented Aug 11, 2019

@rgampa there is now a taskExecutor bean that is provided by auto-configuration which probably overrides yours.

Earlier I was using 2.0.9.RELEASE, i have simply upgraded to 2.1.7.RELEASE

I don't think that is possible as we do fail if something is trying to override a bean by name the way I think this is happening here. If you have set this property yourself, it is more than a simple upgrade as you described it. Getting this failure and taking appropriate action is what you should do on upgrade.

If you haven't set spring.main.allow-bean-definition-overriding then please share a sample that we can use to reproduce this behaviour.

@rgampa
Copy link
Author

rgampa commented Aug 12, 2019

@snicoll Thanks for your reply. I would have checked existing bean before posting here, but error was confusing. I haven't set spring.main.allow-bean-definition-overriding. However by changing bean name to taskExecutorImpl it works fine. This can be closed.

@rgampa rgampa closed this as completed Aug 12, 2019
@Pinocchio2018
Copy link

@snicoll Hi. I update a project to reproduce this problem. here 's the link : https://github.com/Pinocchio2018/TaskExecutorBeanProblem
A personal Java Bean named 'TaskExecutor' will cause Spring boot start problem
This problem confuse me a lot. Please help me if you know the problem reason. Thank you.

@snicoll
Copy link
Member

snicoll commented Jul 20, 2020

Thank you for sharing a sample.

This problem confuse me a lot. Please help me if you know the problem reason.

The problem is described here already. Your user-bean has the same name as a (new) well-known component in Spring Boot. The auto-configuration for task execution will unfortunately create a bean with id taskExecutor that is going to override yours. You also have a bean named taskExecutor. It isn't created at all and when you try to inject it, it does not exist.

In the meantime you can change the name of your bean, for instance:

@Service("myTaskExecutor")
public class TaskExecutor {

That said, I would expect your project to fail differently with a nicer exception message as we've disabled bean overriding by default. But it doesn't and I can't see why that is.

@snicoll snicoll reopened this Jul 20, 2020
@snicoll snicoll changed the title After upgrading to 2.1.7.RELEASE one of the bean can't be autowired Bean overriding for 'taskExcutor' is not detected Jul 20, 2020
@wilkinsona
Copy link
Member

wilkinsona commented Jul 20, 2020

This looks like a Framework bug to me. Here's a minimal sample that reproduces some behaviour that I would not expect:

package com.example;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

public class TaskExecutorBeanProblemApplication {
	
    public static void main(String[] args) {
    	try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
	    	DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)context.getBeanFactory();
			beanFactory.setAllowBeanDefinitionOverriding(false);
	    	context.register(FirstConfiguration.class, SecondConfiguration.class);
	    	context.refresh();
	    	System.out.println(context.getBean("taskExecutor"));
	    	System.out.println(beanFactory.getBeanDefinition("taskExecutor"));
    	}
    }
    
    @Configuration
    static class FirstConfiguration {
    	
    	@Bean
    	TaskExecutor taskExecutor() {
    		return new TaskExecutor();
    	}
    	
    }
    
    @Configuration
    static class SecondConfiguration {
    	
	    @Bean(name = { "applicationTaskExecutor", "taskExecutor" })
	    ThreadPoolTaskExecutor threadPoolTaskExecutor() {
	    	return new ThreadPoolTaskExecutor();
	    }
	    
    }
    
    static class TaskExecutor {
    	
    }

}

The getBean("taskExecutor") call returns the following:

org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor@3d121db3

While the beanFactory.getBeanDefinition("taskExecutor") returns a definition for a different bean:

Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=taskExecutorBeanProblemApplication.FirstConfiguration; factoryMethodName=taskExecutor; initMethodName=null; destroyMethodName=(inferred); defined in com.example.TaskExecutorBeanProblemApplication$FirstConfiguration

I would guess that this mismatched view of the state is why the override isn't detected and prevented.

@bclozel bclozel transferred this issue from spring-projects/spring-boot Jul 20, 2020
@bclozel bclozel added the status: waiting-for-triage An issue we've not yet triaged or decided on label Jul 20, 2020
@saltyx
Copy link

saltyx commented Jul 21, 2020

I think this may be a bug. I check the ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod method.

// Consider name and any aliases
List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
String beanName = (!names.isEmpty() ? names.remove(0) : methodName);

// Register aliases even when overridden
for (String alias : names) {
  this.registry.registerAlias(beanName, alias);
}

// Has this effectively been overridden before (e.g. via XML)?
if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
  ......
}

It uses the first item in the name array as the beanName, therefore, when checking whether the existing bean definition can be overridden, it is actually not checked whether the alias exists

In order to verify, I changed the name of the custom bean from TaskExecutor to ApplicationTaskExecutor. After executing it again, it reminded me that the name has been used. This is different from the previous bean not found error

When verifying whether the bean can be overridden, I think both beanName and its alias should be checked

@sbrannen sbrannen added the in: core Issues in core modules (aop, beans, core, context, expression) label Jul 22, 2020
@jhoeller jhoeller changed the title Bean overriding for 'taskExcutor' is not detected Bean overriding for 'taskExecutor' alias is not detected Jul 22, 2020
@jhoeller jhoeller self-assigned this Jul 22, 2020
@jhoeller jhoeller added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Jul 22, 2020
@jhoeller jhoeller added this to the 5.3 M2 milestone Jul 22, 2020
@jhoeller
Copy link
Contributor

This seems to be caused by a missing check for an alias overriding a bean definition of the same name in DefaultListableBeanFactory. Adding such a check makes the scenario fail with an IllegalStateException for me here, in case of allowBeanDefinitionOverriding=false.

I'll make sure to get this into 5.3 M2. Backporting is tough here since some applications may rely on an accidental override.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: bug A general bug
Projects
None yet
Development

No branches or pull requests

8 participants