Spring Boot auto configuration - Override an auto configured bean - java

I'm attempting to override a bean definition from a library auto configuration and it isn't working. I'm overriding the definition to return a bean of the interface type - my own implementation, whereas the library auto configuration bean returns a concrete implementation.
Spring is finding my bean at startup, then overriding it with the library bean. I've tried using #AutoConfigureAfter(LibraryConfig.class) and making my bean #Lazy but nothing seems to work.
I've spent many a year staying clear of 'magical' code and this type of thing is a good case in point.

Your question is indeed not clear, probably an example could help here.
Anyway, when an infrastructure-level bean is defined, the easiest way in spring boot to override it is just to provide your own configuration that will return the same interface (the bean with the given name)
for example, let's say, in some spring boot source/thirdparty there is the following code:
interface SomeInterface {...}
public class ThirdpartyInternalImplementation implementsSomeInterface {...}
#Configuration
public class ThirdPartyConfiguration {
#Bean
public SomeInterface someInterface () {
return new ThirdpartyInternalImplementation();
}
}
So now, let's assume, that in your source code you've provided another implementation of SomeInterface and you want to return it instead. So you should do something like this:
class MyCustomImplementation implements SomeInterface {}
..........................
#Configuration
public class MyOwnConfiguration {
#Bean
public SomeInterface someInterface() {
return MyCustomImplementation();
}
}
This should be enough to register your custom implementation of SomeInterface.

Related

Create bean only if property file/xml file exists [duplicate]

Lets say i have two beans:
class MyBean implements BeanInterface(){}
class MyBean2 implements BeanInterface(){}
And if specific property exists, i want to create MyBean, otherwise I want to create MyBean2(). How can i do this?
#Bean
#ConditionalOnProperty(name = "property.validation")
public BeanInterface beanInterface() {
return new MyBean();
}
works if I want to create MyBean if property exists, but how do I create MyBean2 if it doesn't?
#Bean
#ConditionalOnMissingBean(MyBean.class)
public BeanInterface beanInterface() {
return new MyBean2();
}
complains that method with same name exists, and if i understand it correctly, the methods name need to be camelCase name of the bean.
How do i do this?
Thanks
//edit i tried:
#Bean
#ConditionalOnProperty(name = "property.validation")
#Order(1)
public BeanInterface beanInterface() {
return new MyBean();
}
#Bean("beanInterface")
#ConditionalOnMissingBean(MyBean.class)
#Order(2)
public BeanInterface beanInterface() {
return new MyBean2();
}
but it didnt work, second bean is not getting created when property is missing.
You can specify bean name #Bean("beanInterface") then method name can be anything.
You have Java configuration at your hands, so use that to your advantage. Not everything needs annotations to be fixed.
#Bean
public BeanInterface myBean(Environment env) {
String validation = env.getProperty("property.validation", String.class);
return validation != null ? new MyBean(validation) : new MyBean2();
}
The name of the method doesn't matter it can be anything you like.
Spring and Spring boot provide a a following solution: If you need to choose one implementation of the interface at runtime, than you inject all implementations and choose appropriate one at runtime. Assuming that you have an interface DataSource with multiple implementations here is how you inject them all:
#Autowired
private List<DataSource> dataSources;
You can read about this solution here.
This is a standard solution, but I really don't like it as it is waistful to inject all implementations. So, I wrote a feature that is available as part of MgntUtils open-source library. That feature allows you to create a static factory per each interface, and once you add any implementation of that interface declared as a Bean, that implementation will be added automatically at start up into a relevant factory. So, instead of injecting all implementations in your class you at runtime take from the factory needed implementation. I think it is much more elegant solution, and it has been battle-tested and it works well. Here is Javadoc that explains the concept and has a detailed example on how to use it: Lifecycle management. Also here is the article that describes this feature in detail: Non-intrusive access to "Orphaned" Beans in Spring framework. The library is available as Maven artifact at Maven central ad also on Github including javadoc and source code. In the source code there is a working example on how to use this feature

Spring profile annotation multiple beans

Let's say I have a library (I cannot change it). There is a class Consumer that uses a spring component of class A.
#Component
public class Consumer{
#Autowired
private A a;
}
In my configuration class I want to define two beans of same class A depending on the profile.
#Configuration
public class Config {
#Bean
#Profile("!dev")
A a1(){
return new A();
}
#Bean
#Profile("dev")
A a2(){
return new A();
}
}
But when I start the app, I get next exception
Parameter 1 of constructor in sample.Consumer required a single bean, but 2 were found:
I can't get how to fix that. I've tried to create 2 separate configs for that with profile annotation and single bean there, but it also did not work.
Marking one bean #Primary also does not help.
Do you guys know how to fix that? Thanks!
UPD.
Let me make it more specific. That class is a part of dynamodb spring starter. Consumer - DynamoDBMapperFactory. My bean - DynamoDBMapperConfig. So I want to have 2 versions of DynamoDBMapperConfig in my app.
You need to stop scanning package where Consumer declared.
#Profile behaves differently if it's applied to the #Bean annotated method.
From Profile doc.:
Use distinct Java method names pointing to the same bean name if you'd like to define alternative beans with different profile conditions
This means, you should do:
#Configuration
public class Config {
#Bean("a")
#Profile("!dev")
A a1(){
return new A();
}
#Bean("a")
#Profile("dev")
A a2(){
return new A();
}
}
Note the same bean names.

How can I disable creating bean with #Component annotation in Spring?

I have some common interface for refactoring logic in my project. It looks about like this:
public interface RefactorAwareEntryPoint {
default boolean doRefactor() {
if (EventLogService.wasEvent(getEventType())) {
return true;
}
boolean result = doRefactorInternal();
if (result) {
EventLogService.registerEvent(eventType);
}
return result;
}
String getEventType();
boolean doRefactorInternal();
}
And than, when I need to write some refactoring - I implement this interface with methods, mark class like #Component, and Spring in loop evaluate each interface implementation and register it in database.
But we have a lot of refactors (every year - 200-300 new). It's hard to disable old implementations manualy, and we have a lot of beans in our spring-context.
Can we do something, for example, use some annotation - which will disable component creation by some condition?
For example:
#Component
#Enabled(YEAR.2020)
public class CustomRefactor implements RefactorAwareEntryPoint {
// Code implementation
}
And this annotation will work like this (a pseudocode):
if (YEAR.2020) {
create bean -> new CustomRefactor()
}
And when it will be YEAR.2021 - we will have no beans from YEAR.2020 in spring-context.
Use the annotation #Profile that makes application configuration and beans available in certain environments.
You can find more at Spring Boot 2.4.0 reference documentation: 3. Profiles
Spring Profiles provide a way to segregate parts of your application configuration and make it be available only in certain environments. Any #Component, #Configuration or #ConfigurationProperties can be marked with #Profile to limit when it is loaded
Consider each year as a separate environment.
#Component
#Profile("2020")
public class CustomRefactor2020 implements RefactorAwareEntryPoint {
// Code implementation
}
#Component
#Profile("2021")
public class CustomRefactor2021 implements RefactorAwareEntryPoint {
// Code implementation
}
In addition to the answers provided by our colleagues, consider the feature of spring called "Stereotype annotations". This is how well-known annotations like #Service are defined in spring.
In general, the fact that you mark your class with #Component annotation allows you to load the class as a spring bean because the annotated class becomes a subject to a process called "component scanning" - a process happens when you start the application context.
Since spring 4 there is a conditional interface that basically makes possible implementing a logic similar to what you refer to as #Enabled(YEAR.2020).
You might use a built-in "#ConditionalOnProperty" to map the 2020 year to property or even implement a custom conditional logic. I'll assume that you've implemented a custom conditional as #ConditionalOnYear
Now, what's interesting (and this is a "stereotype" feature that I've mentioned at the beginning of the post) is that you may create your own "component" annotation with a custom "conditional" logic and use it "as if" its a regular bean:
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#ConditionalOnYear(2020)
#Component
public #interface Year2020OnlyComponent {
#AliasFor(annotation = Component.class)
String value() default "";
}
#Year2020OnlyComponent
public class CustomRefactor implements RefactorAwareEntryPoint {
// Code implementation
}
You can also improve that by clever usage of #AliasFor annotation to be something like:
#SinceYearComponent(2020)
public class CustomRefactor implements RefactorAwareEntryPoint {
// Code implementation
}
But this is kind of out of scope for this question - so I just mention a direction here.
Of course, it's possible to merely use two annotations as you've suggested even without this "Stereotype" annotation feature:
#Component
#SinceYear(2020) // a custom conditional
public class CustomRefactor implements RefactorAwareEntryPoint {
// Code implementation
}
Check out the BeanFactoryPostprocessor interface. Probably you can remove a bean before it‘s creation.
Else you might implement your own BeanFactory and create the ApplicationContext with your implementation.
You can use excludeFilter annotations provided by spring boot .
As mentioned by others you can always use #Profile annotation to
enable/disable profiles.
Another option is excludeFilter

Spring DI - Non-managed-object custom resolution

I have the following bean / constructor definitions:
#Configuration
class Configuration {
#Bean
public List<Something> getSomethings(MyFancyStuff stuff, #Autowired Bar bar) {
//...
}
}
#Component
class SomeOtherThing {
public SomeOtherThing(MyFancyStuff stuff, #Autowired Bar bar) {
//...
}
}
Is it possible to extends dependency resolution to provide a custom resolver when a specific class or annotation is found for a given parameter? I looked at PropertyPlaceholderConfigurer and InstantiationAwareBeanPostProcessor but nothing seemed to help me write my own value provider.
As a context: I implemented a custom scope which creates many instances of a given bean for each configuration object it has. I want to pass this configuration object to the bean-creation-process of said scope without adding it to the application context. I don't want to add it to the application context because it is an object which no other object should be able to obtain through dependency injection. I need to extend the DI-process of spring because I want to support field injection, constructor injection and bean factory-methods like the shown getSomethings
note: this is not about automatic value conversion of SpringMVC request parameters.
You can use #Conditional Annotation
#Bean(name="dataSource")
#Conditional(value=DevCondition.class)
public Util getSource1() {
return new DevUtil();
}
#Bean(name="dataSource")
#Conditional(ProdCondition.class)
public Util getSource2() {
return new ProdUtil();
}
you can also create bean based on property value using #Profile

How to declare a Spring bean autowire-candidate="false" when using annotations?

I am using #ComponentScan and #Component to define my spring beans. What I would like is to declare one of these beans to be autowire-candidate=false.
This could be done with this attribute in xml. Isn't there the equivalent in annotations?
The reason I want this is because I have 2 implementations of the same interface and I don't want to use #Qualifier.
EDIT: Using #Primary is a valid work-around, but autowire-candidate seems to me like a useful feature with its own semantics.
Thanks
Looks like Spring refused autowire-candidate=false concept and it no longer supported. There is no analogue with annotations, so #Primary is the best work-around as you noticed.
Another way is to use custom org.springframework.beans.factory.support.AutowireCandidateResolver, which is used in DefaultListableBeanFactory, with logic that exclude undesirable beans from autowire candidates. In such case, the technology will be similar to that used for autowire-candidate=false in SimpleAutowireCandidateResolver.
Since Spring 5.1 , you can configure autowire-candidate in #Bean through autowireCandidate attribute:
#Bean(autowireCandidate = false)
public FooBean foo() {
return newFooBean();
}
You can also use the bean accessor to tune it's visibiltiy.
see Bean visibility
#Configuration
public abstract class VisibilityConfiguration {
#Bean
public Bean publicBean() {
Bean bean = new Bean();
bean.setDependency(hiddenBean());
return bean;
}
#Bean
protected Bean hiddenBean() {
return new Bean("protected bean");
}
}
You can then #Autowire the Bean class and it will autowire the public bean (without complaining about multiple matching beans)
As a class' definition (unless embedded) does not allow private / protected accessor the work around would be to use an #Configuration class that would instantiate all the beans an publish the public beans while hiding the private/protected (instead of directly annotating the classes #Component \ #Service)
Also package-protected accessor may worth a try to hide #Component annotated classes. I don't know if that may work.
We can do this by using the #Qualifier annotations with name mentioned in the #Component annotations
Bean classes -
#Component("fooFormatter")
public class FooFormatter implements Formatter {
public String format() {
return "foo";
}
}
#Component("barFormatter")
public class BarFormatter implements Formatter {
public String format() {
return "bar";
}
}
Injecting bean in service class -
public class FooService {
#Autowired
#Qualifier("fooFormatter")
private Formatter formatter;
}
For more details please refer - https://www.baeldung.com/spring-autowire#disambiguation. Above example taken from this link.

Categories

Resources