Spring default bean candidate - java

I'm writing a library that uses spring, for others to use. In my library, I have class A that has an interface B as a field (with #Autowired).
I have a default implementation of that field, but the user can implement a custom implementation by himself. What I want to happen is the following:
If the user implemented B, I want that bean to be injected to A, otherwise I want my default implementation to be injected.
Something like the opposite of #Primary
I know that the user can add the #Primary annotation in order for that to happen, but I don't want him to add any other annotation besides #Component (because it is not clear for the user why he must add the #Primary annotation)
Is there a way to achieve this behavior? I've also tried #Order and #Priority, but no luck - the user must add another annotation.
Thanks!

You should create your own auto configuration. Auto configuration classes are always processed last so user's own configuration is processed first and when using #Conditional... annotations user's beans will take precedence.
Your auto configuration class should look like this:
#Configuration
public class MyAutoConfiguration {
#ConditionalOnMissingBean(B.class)
#Bean
public B defaultImplementation() { return A(); }
#Bean
public UsesB classThatUsesB(B b) { return UsesB(b); }
}
In this case if the user of your library defines a bean of type B it will always be used first and if they don't the bean created by the defaultImplementation method will be used.

I don't believe so. Spring's #Autowired is rather specific. Making it perform differently without any configuration changes (either to XML or the Spring configuration class) is pretty much impossible.

Related

Custom `RelyingPartyRegistrationRepository` implementation

It looks like Spring always uses InMemoryRelyingPartyRegistrationRepository to return a RelyingPartyRegistrationRepository typed bean, refer to https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyRegistrationConfiguration.java.
Question: how can I inject (autowire) my own implementation of RelyingPartyRegistrationRepository? Say I would like to allow the auto wired relying party repository auto reload from database once I have SAML configuration for a certain customer updated. Is this doable?
You can provide your own bean and spring boot auto configuration will back off.
#Configuration
#EnableConfigurationProperties(Saml2RelyingPartyProperties.class)
public class SamlConfig{
#Bean
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository(Saml2RelyingPartyProperties properties) {
-- Provide custom repository implementation
}
}
You may need other changes after you create your own bean based on what you need.

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

Order of Configuration in SpringBoot

I am trying to understand how beans that we make using #Configuration tends to override the beans that are generated by SpringBoot by default. I have been working on a project where in many cases we create beans for things like ZuulConfigs and the assumption is, whatever we are making shall take precedence over the default generated bean. I have been trying to figure this out but can't. Basically,
Is Spring achieving this via some custom class loader
If not how is this precedence working. Can I give some precedence in similar manner to my beans
Can I generate similar hierarchy in my project,if so how
The help is highly appreciated
Spring AutoConfiguration is used to provide a basic configuration if certain classes are in the classpath or not.
If you want to configure the order in which beans are instantiated by spring you can use
#DependsOn("A")
public class B {
...
}
This would create bean "A", then "B". Hence you can order the configuration depending upon the beans need first to be done. Anyways Spring automatically detects the dependencies by analyzing the bean classes.
for more help check this question
Spring Boot AutoConfiguration Order
Alternative :
There is also "#AutoConfigureOrder" annotation(where you can prioritise the configuration), you can have a look in the code for deeper understanding.
Documentation of AutoConfiguration is here
First of all, class loading and bean creation are two different things. We don't need to create a bean to load a class, however, a class has to be loaded in order to create a bean.
Now, coming back to Spring's example, Spring looks into all the packages configured by #componentScan and creates beans of all the classes annotated with #Bean, #Configuration and/or #Component. Spring's container keeps track of all the beans created and hence, when it encounters user defined bean with same name and class type as default bean, it replaces the original definition with user defined one (e.g. we can create our custom #ObjectMapper to override Spring boot's own instance). You can also use #Primary annotation to make you bean take precedence if another definition with same class exists (documentation here).
Below are the answers for your questions:
Spring uses reflection to load the classes and create instances. Although you can load the classes with your custom class loader (more on that here), you don't need to worry about it for #Configuration.
Yes, you can use #Primary annotation to give your bean a precedence. You can also use #Order(here) to define the creation order for your beans.
With #Primary, #Order and #Qualifier annotation you can define your own hierarchy for bean creation.
Can I give some precedence in similar manner to my beans
Yes.
A) To define a specific order your Configuration classes will be handled (by the way, a Configuration class does not have to be annotated with #Configuration (so-called full definition), but it's enough to be annotated with #Component, #ComponentScan, #Import, #ImportResource or just have a method annotated with #Bean - so-called lite definition), you should
1) add your Configuration Candidates to your SpringApplication's primarySource, for example, in your main method like that
SpringApplication.run(
new Class[]{YourSpringBootApplication.class, Config1.class, Config2.class, ...},
args);
2) and annotate each of your Configuration Candidates with #Order annotation, any other ordering means like Ordered interface, #DependsOn etc will be ignored by ConfigurationClassPostProcessor, the order in the primarySource array will also be ignored.
Then ConfigurationClassPostProcessor will sort your Configuration Candidates and handle them according the #Order annotation value you specified.
B) The precedence can also be achieved by defining your own AutoConfiguration classes. Although both Configuration and AutoConfiguration are handled by the same ConfigurationClassPostProcessor, they are essentially distinctive machineries. To do so
1) define in your classpath /META-INF/spring.factories file and put in the EnableAutoConfiguration section of it your AutoConfiguration classes like that
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
your.package.AutoConfig1,your.package.AutoConfig2
2) and annotate your AutoConfiguration classes with #AutoConfigureOrder, #AutoConfigureAfter, or #AutoConfigureAfter annotations, any other ordering means again will be ignored.
Like #Strelok pointed out, AutoConfiguration classes, your own and provided e.g. by spring-boot-autoconfigure library alike, will be added to the end of the list of Configuration Candidates.
Remember, however, that the order the Configuration Candidates will be handled by ConfigurationClassPostProcessor does not necessarily coincide with the order the beans defined by the Configuration classes will be created. For example, you might define your Configuration class that overrides TomcatServletWebServerFactory to make your own customization of Tomcat web server like
#Configuration
public class EmbeddedTomcatConfig {
#Bean
public TomcatServletWebServerFactory containerFactory() {
...
return customizedTomcatWebServerFactory;
}
but this method will be called right at the moment when your Spring Boot application decides to create a Web server, regardless of how you defined the precedence for your EmbeddedTomcatConfig Configuration class.
Is Spring achieving this via some custom class loader
There is no need to. Although you could, as always with Spring, define your own ClassLoader for BeanFactory, standard ClassLoader is good enough if everything you need for Configuration in your application is available in the classpath. Please notice, that at first phase ConfigurationClassPostProcessor does not load (i.e. does not resolve) the Configuration candidates classes (otherwise, most of the classes in spring-boot-autoconfigure library will fail to load). Instead it analyzes their annotations with bytecode analyzer, ASM by default. For that purpose, it is just enough to get a binary form, a byte array, of a class to feed it to bytecode analyzer.
Just know this: Spring Boot (specifically) auto configuration classes are always configured last. After all user beans have been created. Spring Boot auto configuration classes almost always use the #ConditionalXXXX annotations to make sure that any beans of the same type/name and other conditions that are configured in your application will take precedence over the Spring Boot auto-configured beans.
If you want your #Component to take precedence over other #Component while scanning all the components by spring, use #Order(Ordered.LOWEST_PRECEDENCE) i.e. the max value to load your component over other.
#Primary is used to give your bean a default preference, we can override the default preference using #Qualifier

How to create a bean by type in Spring?

In my ApplicationContext I have several Beans being created the same style. So I have a lot of dublicated code writing a FactoryBean for each of this beans. Those beans have a common ground, implementing all one special interface.
I would like to move all that bean creation to one factory. That one would have to provide a methode like this
<T extends CommonInterface> T createInstance(Class<T> clazz);
There I could implement all the instantiation necessary to create one of my special beans.
My implementation would be called by spring for
#Autowired
private MyCommonInterfaceImplementation impl;
in that way
createInstance(MyCommonInterfaceImplementation.class)
So far I looked at BeanFactory and FactoryBean, both seem not to be I'm searching for.
Any suggestions?
why not use #bean
#Bean
public MyCommonInterfaceImplementation getMyCommonInterfaceImplementation(){
return MyBeanFactory.createInstance(MyCommonInterfaceImplementation.class);
}
//should autowire here
#Autowired
private MyCommonInterfaceImplementation impl;
Basically you need the #Bean annotation on a "factory" only if you need some special handling during the creation of a bean.
If everything can be #Autowired, either by setters, fields, or one constructor, and nothing else needs to be done on a bean during initialization, you can simply declare the annotation #Component on each implementation of your interface. This works as long as you have component scanning active inside your application. The result will be that for each component spring will create a bean which you can use.
I'm writing this on a mobile so showing code is not the best. Just follow some tutorial on #ComponentScan, or if you need, let me know and I can augment this answer with an example.
As of Spring 4.3 you no longer have to annotate your bean classes and you can let them be instantiated via a componentscan.
#Configuration
#ComponentScan(
value = "some.package.path",
includeFilters = {
#Filter(type = ASSIGNABLE_TYPE, value = {
MyClass1.class,
MyClass2.class,
MyClass3.class
})
})
This actually creates beans for the three classes listed there. The example should work without filters as well (everything in the package becomes a bean). This works as long as the classes have a single constructor that can be used for autowiring. I don't think it is possible to filter for all implementations of a particular interface and then register a bean.
To do that, you might do something with a ContextListener and e.g. use reflection to find out what classes to instantiate and then use context.autowire(..) to inject any dependencies from your context. A bit hacky but it might work.
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext();
MyClass bean
= context
.getAutowireCapableBeanFactory()
.autowire(MyClass.class, Autowire.BY_NAME.value(), true);
...
}
That still leaves the problem of how to get the bean registered in the context of course.
You might also be able to adapt the answer to this SO question on how to add beans programmatically.
Finally the best approach I've found is using a ConfigurationClassPostProcessor. As example I've used https://github.com/rinoto/spring-auto-mock
But, since it is quite complicated and "too much magic" to create beans from nothing, we decided to explicitly create those beans via #Bean.
Thanks for your answers.

Less verbose #Bean

We use #Configuration classes with lots of #Bean annotated methods that essentially read like this:
#Bean
public TeamContactIndexer teamContactIndexer(GroupService groupService, ContactCrudService contactCrudService, ContactRetrieveService contactRetrieveService) {
return new TeamContactIndexer(groupService, contactCrudService, contactRetrieveService);
}
So this returns a new bean and injects other spring declared things via method arguments into the constructor by name.
The only way I know to reduce verbosity is to annotate the beans with #Component and constructor with #Autowired.
For many this is perfectly acceptable but I prefer to not litter my code with Spring annotations just to facilitate plumbing and keep a clean separation between completely spring free business logic and plumbing code in #Configuration annotated classes. I treat them as a more type safe, less verbose replacement for what we used to do in xml.
However, wouldn't it be nice if I could just go ...
#Bean
public TeamContactIndexer teamContactIndexer;
... and have spring figure out that it needs to autowire the constructor of that class (100% spring free) to produce the bean. This is not currently supported in Spring as far as I can see even though it should be quite easy to do as far as I can see. Am I missing something or is there really no way around me micromanaging constructor calls in my #Configuration classes (other than littering my code with annotations)? The vast majority of my #Bean methods should be easily replaced like this.
UPDATE
#bezmax has provided a workable approach here which is to use a component scan annotation.
#Configuration
#ComponentScan(
basePackages={"com.github.jsonj.tools"},
includeFilters = { #Filter(type = FilterType.ASSIGNABLE_TYPE, value = {JsonParser.class})})
public class JsonParserConfig {
}
I've used the above to provide a bean definition for a bean without annotations in a library that I use. This replaces the #Bean annotated factory method I had earlier. It's still somewhat verbose but at least you can put in a comma separated list of classes. The default for type is wrong for this usecase so you must specify it; likewise the package defintion is required even though it could be deduced from the class on the filter.
IMHO there is room for an obvious improvement in Spring, which is to provide an annotation that simply takes a comma separated list of classes. So, instead of scanning a package, simply list the bean classes you want initialized. There are probably still a few hairy issues with autowiring via the constructor.
This feature is implemented in Spring 4.3 (not yet released).
You can read more about that in the changelog (see 6.1)
Added:
As about registering your unannotated classes automatically, there seems to be a flexible way to achieve this using #ComponentScan annotation. This annotation allows you to specify a set of include filters, which, when matched on classes, are automatically registered as beans. I had not actually tried using more complex rules with this filter, and it seems that you have several options there (check out the documentation on #ComponentScan) but the easiest one would be something like this:
#Configuration
#ComponentScan(
value = "some.package.path",
includeFilters = {
#Filter(type = ASSIGNABLE_TYPE, value = {
MyClass1.class,
MyClass2.class,
MyClass3.class
})
})
public class WebConfig extends WebMvcConfigurerAdapter {
...

Categories

Resources