spring - how to set explicitly primary=false? - spring

I am building a jar dependency that will create a bean of a type that is likely to exist already in the apps that will use that dependency.
I want to create a configuration spring class in the dependency to mark that bean as "secondary".
How can we set explicitly a bean as secondary (or #Primary(value=false) ) in spring with annotations or with java config?
There is also the autoWireCandidate on the #Bean annotation. But that is available only from the very young spring versions.

Related

Resilience4J Retry not auto-configured in Spring boot 3

I'm in the process of migrating to Spring Boot 3. In Spring Boot 2 Resilience4J Retry was auto-configured and worked out of the box using the following setup:
application.yaml:
resilience4j.retry:
instances:
some-instance
# retry config here
Test class:
#SpringBootTest
public class TestClass {
#Autowired
private RetryRegistry retryRegistry;
#Test
void someTest() {
// perform test and evaluate retries using retryRegistry
}
}
However while updating to Spring Boot 3 using the following versions:
org.springframework.boot:spring-boot-starter:jar:3.0.0:compile
io.github.resilience4j:resilience4j-spring-boot2:jar:1.7.0:compile (derived from a Spring BoM)
The test in which the RetryRegistry was autowired failed with the following message:
Unsatisfied dependency expressed through field 'retryRegistry':
No qualifying bean of type 'io.github.resilience4j.retry.RetryRegistry' available:
expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I managed to fix the test by explicitly importing the Resilience4j Retry configuration in the test using:
#Import(io.github.resilience4j.retry.autoconfigure.RetryAutoConfiguration.class)
However, I'm wondering why the component scanning mechanism in Spring Boot 3 did not pick up the retry config in the first place. Would anyone know why Spring Boot 3 did not pick up the class during component scanning?
In the resilience4j project they changed the dependency for spring boot 3.
So you should go for io.github.resilience4j:resilience4j-spring-boot3:${resilience4jVersion}
like
org.springframework.boot:spring-boot-starter:jar:3.0.0:compile
io.github.resilience4j:resilience4j-spring-boot3:jar:2.0.0:compile
from the documentation
It seems that it is related to a new META-INF file being used instead of the old spring.factories file. From the documentation :
Spring Boot 2.7 introduced a new META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports file for registering auto-configurations, while maintaining backwards compatibility with registration in spring.factories. With this release, support for registering auto-configurations in spring.factories has been removed in favor of the imports file.
The Resilience4J dependency used in the spring-cloud-dependencies-parent BoM still uses a spring.factories file instead of the new file named org.springframework.boot.autoconfigure.AutoConfiguration.imports. The new file has recently been introduced in Resilience4J (source).
Overriding the version from the Spring BoM with version 2.0.2 for all the resilience dependencies fixed it for me. I will check in a few days whether the new Resilience4J version has been updated in the Spring BoM (or resilience4j-spring-boot3 has been introduced).
[edit]
As others have noticed,resilience4j-spring-boot3 is already available. I'll start using it.

CDI and Spring hand in hand

Is there any chance that CDI and spring dependency injection could co-exist. The problem started when I tried using JpaRepository interface.
I cannot remove beans.xml as it breaks a common jar implementation which uses CDI. I tried #Vetoed but it then fails to autowire my JpaRepository interface in a service class. Does it mean that #Vetoed prevents the bean from being managed by spring also?
I am looking for an idea so that i could use CDI to manage some beans and spring to manage the rest.

Spring Integration causes multiple beans error

I'm using Spring Boot and trying use Spring integration (because I want to use its SFTP client). But I got the following error:
Description:
Parameter 0 of constructor in com.example.demo.service.ServiceOne required a single bean, but 2 were found:
- applicationTaskExecutor: defined by method 'applicationTaskExecutor' in class path resource [org/springframework/boot/autoconfigure/task/TaskExecutionAutoConfiguration.class]
- taskScheduler: defined in null
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 consumed
I'm sure that the error happens after adding dependencies for spring-integration. I've tried to use #Qualifier("applicationTaskExecutor") and creating a bean with #Primary annotation but still unable to run the application. How to fix it?
As error stated there are two TaskExecutor beans in the application context.
One is auto-configured by the TaskExecutionAutoConfiguration and another by Spring Integration for its pollers features which is essentially a TaskScheduler.
What the error description suggest is to use a #Qualifier("applicationTaskExecutor") on the ServiceOne 's Parameter 0 of constructor. You don't need to have #Primary bean because the story is about beans created outside of your code.

The bean 'methodSecurityInterceptor', defined in class path resource and overriding bean is disabled

I am using spring boot 2.1.6.RELEASE and using some third party framework to perform security specific activities. This third party library using spring security 4.2.3.RELEASE.
When I ran the application, I got below error.
The bean 'methodSecurityInterceptor', defined in class path resource [org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [com/thirdparty/configSecurityConfig.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
I know, I can solve the problem by setting below configuration.
spring:
main:
allow-bean-definition-overriding: true
But is there any way to specify my application to use the spring security (4.2.3.RELEASE) of third party library not from spring boot 2.1.6.RELEASE.

Spring Boot Scanning Classes from jars issue

In my sample spring boot application, i have added a dependency of a custom jar. My sample application has a support for web and jpa.
The jar which i've created contains a Spring MVC controller. Below is the sample code
#Controller
public class StartStopDefaultMessageListenerContainerController {
#Autowired(required=false)
private Map<String, DefaultMessageListenerContainer> messageListeners;
I haven't manually created a bean instance of this controller anywhere in my code.
Problem - When i start my spring boot application by running the main class, i get an error in console that prob while autowiring DefaultMessageListenerContainer.
My question here is, even though this class StartStopDefaultMessageListenerContainerController is just present in the classpath, it's bean shouldn't be created and autowiring should not happen. But spring boot is scanning the class automatically and then it tries to autowire the fields.
Is this the normal behavior of spring and is there anyway i can avoid this?
If the StartStopDefaultMessageListenerContainerController class is part of component scanning by spring container, Yes spring tries to instantiate and resolve all dependencies.
Here your problem is #Autowired on collection. Spring docs says,
Beans that are themselves defined as a collection or map type cannot be injected through #Autowired, because type matching is not properly applicable to them. Use #Resource for such beans, referring to the specific collection or map bean by unique name.
And also Refer inject-empty-map-via-spring

Resources