A bean with that name has already been defined in class path resource [path] and overriding is disabled - spring-boot

I have the java configuration for the Spring Data Elaticsearch(using Transport Client) and ESTemplate.
Here some except:
#Configuration
#EnableElasticsearchRepositories(basePackages = "subpackage-in-this-project")
#PropertySource("file:path-to-file")
public class ESConfig {
#Bean
ElasticsearchTemplate elasticsearchTemplate(Client client) {
return new ElasticsearchTemplate(client);
}
#Bean
Client client() {
// configuration of the ES client
}
}
And I have a config that extends the one above in the different project.
#Configuration
#ComponentScan("package-prefix-that-matches-packages-in-both-projects")
#EnableElasticsearchRepositories(basePackages = "subpackage-in-this-project")
#PropertySource("file:same-path-to-file-as-in-the-config-above")
public class ExtendedESConfig extends ESConfig {
#Value("index-name")
private String indexName;
#Bean
public String indexName() {
return indexName;
}
}
Upon executing a third Spring Boot application, which uses the dependency on the project with ExtendedESConfig, I get this and I can't quite understand why does it happen, started to happen after upgrading to 2.2.9.RELEASE from 2.0.5.RELEASE Spring Boot version.
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'elasticsearchTemplate', defined in class path resource [my/package/ESConfig.class], could not be registered. A bean with that name has already been defined in class path resource [my/other/package/ExtendedESConfig.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
2020-08-30 16:49:46 ERROR [main] org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter:40 -
Important remark from my comment:
... sadly, I am not the one who wrote this ES config and built the whole infrastructure around it. ...
At the time of this question, I don't own ExtendedESConfig nor can change it.

Or you can add the next property to your application.properties :
spring.main.allow-bean-definition-overriding=true

The default behaviour of overriding bean has been disabled in Spring Boot 2.1. Spring Boot 2.1 Release Notes
Since you don't own / or don't want to modify both configuration classes. You can exclude parent configuration form your SpringBootApplication class using #ComponentScan
#SpringBootApplication
#ComponentScan(excludeFilters =
{#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = ESConfig.class)})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

I had a similar problem with my custom springSecurityFilterChain method, in my #Configuration class. The application told me it couldn't create a Bean named springSecurityFilterChain since it was defined elsewhere (in my case, in a Spring Security package, which, as is your case, I couldn't modify).
I found the solution here and it amounted to simply changing my custom method's name; I chose customFilterChain. So it went from
#Bean
public SecurityFilterChain springSecurityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf().disable()
// etc
}
to:
#Bean
public SecurityFilterChain customFilterChain(HttpSecurity http) throws Exception {
return http
.csrf().disable()
// etc
}
Amazingly it worked. Like the article says, Spring builds the bean using the method's name by default. Hope it helps.

find in your modul: resources/application.properties and write:
spring.main.allow-bean-definition-overriding=true
it help you, you need to enable the beans override mechanism.

Related

Error with using #ComponentScan on multiple packages in Spring Boot

Here's my issue--I have a service that relies on an external library. I was trying to autowire the service so I can use it but was not able to
import org.keycloak.admin.client.token.TokenService;
public class SimpleService {
#Autowired
private TokenService keycloakTokenSvc; // Could not autowire, no beans of type 'TokenService' found
public void execute() {
keyCloakTokenSvc.doSomething();
}
}
I then added this to my SpringBootApplication and got it working:
#SpringBootApplication
#ComponentScan({"org.keycloak.admin.client.token"})
public MyApp {}
Sweet -- all good now, right? Nope. It seems like this overrides some of my auto configuraitons like my security config, so I was no longer to make RESTful requests to my application while it was running. I then did this next:
#SpringBootApplication
#ComponentScan({"org.keycloak.admin.client.token", "com.project.pkg"})
public MyApp {}
Still nothing. I get the same error as before:
Field keycloakTokenSvc in com.mark43.jms.services.TokenRefreshService required a bean of type 'org.keycloak.admin.client.token.TokenService' 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 'org.keycloak.admin.client.token.TokenService' in your configuration.
I'm new to Spring Boot so not sure what to do here. Is there a way to use the TokenService without Autowiring? Is there a way to scan both packages?
It seems to me that you need to create a TokenService bean as follows:
#Configuration
public class TokenConfig {
#Bean
public TokenService tokenService() {
return new TokenService(); // Or whatever you need to instantiate it
}
}
This will register a TokenService object as a Spring-managed bean so that it can be autowired into SimpleService.

SpringBoot 2.1 spring.main.allow-bean-definition-overriding=true not working

We are upgrading to SpringBoot 2.1.x and Spring Security 5.1.x. We have our own SecurityConfig that overrides springSecurityFilterChain bean that is found in org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration. I have added that property to the applications.property file and set it to true but it is still not allowing overrides.
Our class:
#EnableWebSecurity
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public FilterChainProxy springSecurityFilterChain() throws Exception {
blahblahblah
}
}
And the Spring class:
package org.springframework.security.config.annotation.web.configuration;
#Configuration
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
#Bean(
name = {"springSecurityFilterChain"}
)
public Filter springSecurityFilterChain() throws Exception {
blahblah
}
}
The error:
org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'springSecurityFilterChain' defined in class path resource
Its not clear to me why setting the override property to true is not being picked up. I have also tried to annotate our bean as primary, the #autoconfigureBefore(WebSecurityConfiguration.class) and removing non-wanted bean from registry (but haven't figured out how to do that successfully). Is there something special about the bean I am trying to override that prevents it? Do I need to have the applications.property file loaded earlier somehow?
same issue here. what is the solution for this. I have
#Bean
#Primary
public ScheduledLockConfiguration taskScheduler(LockProvider lockProvider) {
}
But it doesn't seem to be invoked as another bean in third party library exists with same name.

#EnableAspectJAutoProxy deactivate my bean definition

I setting up a new Spring App(not spring boot) in IDEA,and manual download aspectjweaver,
writing the following code to practice aop.
A root configuration class is:
#Configuration
/*#EnableAspectJAutoProxy*/
#ComponentScan
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext();
ctx.register(Main.class);
ctx.refresh();
Performance performance=ctx.getBean(WoodStock.class);
//System.out.println(ctx.getBean(Audience.class));
performance.performance();
}
}
and the project layout is:
+com.dawn.www
-Main.java
+aspect
-Audience.java
+music
-Performance.java
-WoodStock.java
I want the Audience being the aspect of WoodStock(seeing it in spring in action)
#Aspect
#Component
public class Audience {
#Before("execution(* com.dawn.www.music.Performance.performance(..))")
public void silenceCellPhones(){
System.out.println("-----------Silencing cell phones");
}
}
Performance is a simple interface which implements by WoodStock
public interface Performance {
void performance();
}
#Component
public class WoodStock implements Performance{
#Override
public void performance() {
System.out.println("WoodStock Performance start,singer singing+++++");
}
}
#ComponentScan should find theWoodStockbean which is defined in application context,however when I run it:
No qualifying bean of type 'com.dawn.www.music.WoodStock' available
but when I comment out #EnableAspectJAutoProxy, WoodStock can be fetched from
application context?that's why?
When you are using #EnableAspecjAutoProxy, spring will automatically
create proxy for all the matching beans(i.e. WoodStock via Audience aspect).
Now, Since you haven't used 'proxyTargetClass=true' on
#EnableAspectJAutoProxy, it will fall back on JDK proxy instead of
CGLIB.
JDK proxy is interface based, hence your proxy is of type
'Performance'.
Thats the reason you are getting 'No qualifying bean of type
'com.dawn.www.music.WoodStock' available' when you try to find bean
using WoodStock type
Now, after commenting out #EnableAspectJAutoProxy, WoodStock becomes a
simple bean and is accessible via ctx.getBean(..)
with 'proxyTargetClass=true', CGLIB proxy is enabled and it creates
proxy of type WoodStock
Suggestions
Use 'proxyTargetClass=true' with ctx.getBean(WoodStock.class)
or
Use 'proxyTargetClass=false' with ctx.getBean(Performance.class)
Performance performance=ctx.getBean(Performance.class);
Spring Aop only support Interface-level proxy when not using CGLIB,so don't use class,use interface.

onStartup method of WebApplicationInitializer never gets called

I have a Grails application. I am trying to set an active Spring profile by using the onStartup method of WebApplicationInitializer.
I have annotated this Java class with #Configuration but onStartup method never gets invoked.
package my.package;
#Configuration
public class MyWebApplicationInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.setInitParameter("spring.profiles.active", "test");
}
}
In Config.groovy I have added,
grails.spring.bean.packages = ['my.package']
I also tried adding following code in resources.groovy
xmlns context: "http://www.springframework.org/schema/context"
context."component-scan" "base-package": "my.package"
But whatever code changes I try onStartup method never gets called.
In my case I used application.yml and it worked in dev environment but after packaging it into a war using prod profile, for some reason it stopped picking up my java config annotated with #Configuration.
The solution was to modify Application.groovy as recommended in another question:
#ComponentScan("my.package")
class Application extends GrailsAutoConfiguration {
...
}
Note: Overriding packageNames() in Application.groovy recommended in the docs also doesn't work.

Spring Boot - custom 404 page with standalone tomcat

I am running a Spring boot application inside a standalone tomcat instance, and I am trying to override the error pages. From my understanding, Spring provides a filter ErrorPageFilter that allows me to just setup error pages as normal for Springs EmbeddedServletContainerCustomizer to handle this case exactly.
So I have my standard auto configuration/servlet initializer in one class:
#Configuration
#ComponentScan
#EnableAutoConfiguration(exclude = [ GroovyTemplateAutoConfiguration, SecurityAutoConfiguration, ErrorMvcAutoConfiguration, JmxAutoConfiguration ] )
class Application extends SpringBootServletInitializer {
#Override protected SpringApplicationBuilder configure( SpringApplicationBuilder application ) {
application.sources( Application )
}
(I am using the same class for autoconfiguration and servlet init, which is why i just pass my Application class in the configure method)
Looking at the source code for SpringBootServletInitializer it looks like the ErrorPageFilter class is being added by just extending that class here. I have turned off the ErrorMvcAutoConfiguration - but again, looking at that source code it looks like that is just setting default error pages and not actually setting anything up with the ErrorPageFilter.
I then have my error config file:
#Configuration
class ErrorConfiguration implements EmbeddedServletContainerCustomizer {
#Override public void customize( ConfigurableEmbeddedServletContainer container ) {
container.addErrorPages(new ErrorPage( HttpStatus.NOT_FOUND, "/errors/404" ))
}
However, if I just visit an invalid URL, and I DispatcherServlet can't find a match then I just get tomcats /404.html - not my view linked to "/errors/404" (I have this path mapped to a thymeleaf view template, that works fine - if I navigate to /errors/404 it displays ok)
Any ideas why my custom error page is not working? tracing the logs, I get a line about the ErrorPageFilter being configured and setup ok on application startup, but then no mentions of the filter doing anything when a request comes in.
You can use following code for older versions of spring boot (0.5.x)
public class ServerCustomization extends ServerProperties {
#Override
public void customize(ConfigurableEmbeddedServletContainerFactory factory) {
super.customize(factory);
factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,
"/yourpath/error-not-found.jsp"));
factory.addErrorPages(new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR,
"/yourpath/error-internal.jsp"));
factory.addErrorPages(new ErrorPage("/yourpath/error-other.jsp"));
}
}
Newer spring boot versions (1.X.RELEASE) has some refactoring around ServerProperties. See below,
public class ServerCustomization extends ServerProperties {
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
super.customize(container);
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,
"/jsp/404.jsp"));
container.addErrorPages(new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR,
"/jsp/500.jsp"));
container.addErrorPages(new ErrorPage("/jsp/error.jsp"));
}
}
Then define a bean to inject ServerProperies.
#Bean
public ServerProperties getServerProperties() {
return new ServerCustomization();
}
Sample project posted in git
Very Important: If you are using maven to build, You must store all the resource files under src/main/resources folder. Otherwise maven will not add those files to final jar artifact.
You can either use Spring Boot's builtin error view by implementing a view named error, or switch it off by setting error.whitelabel.enabled=false property and implement your own. It's explained more in the docs.

Resources