I'm looking for a pattern to simplify bean creation for a team of developers.
For now, I've been trying to use abstract classes like this:
public abstract class BaseClass {
#Bean
public BeanA generateBeanA() {
...
return beanA;
}
#Bean
public BeanB generateBeanB() {
...
return beanB;
}
}
The idea behind: I provide the BaseClass and I'd like developers to extend it many times. For each extension, every beans should be generated. But this approach doesn't work : for each extension, developers have to redeclare beans for 2 reasons :
bean declaration is not inherited
to avoid name clashing, they have to name beans manually in each extension
Is there a better pattern that would allow the following?
centralized bean naming (ie: the developer declare a base name in the extension and every bean of the extension is renamed accordingly: ${baseName}${beanName} )
overriden beans would be declared (instead of parent version)
parent beans would be declared if not overriden
There are 3 ways to configure beans in Spring container:
Declare them using XML configuration.
Declare beans using the #Bean
annotation in a configuration class.
Mark the class with one of the
annotations from the org.springframework.stereotype package, and
leave the rest to component scanning.
So, the way you declare Spring bean is wrong.
IMHO, let the developers declare beans as they want, and they just #Autowired them or something.
Please continue by reading this
Related
I would like to inject a bean (lets call it clientStub) into my service bean.
There are two requirements for that:
In order to create the clientStub bean, I need to access the #Client annotation, that carries some important information that are used to lookup the relevant configuration in the properties.
It must support constructor based injection (and #Bean method parameter injection)
Expected usage:
#Autowired
public MyService(
#Client("invoice-manager") InvoiceManagerClientStub clientStub,
SomeOtherBean bean1, ...) {
or
#Bean
MyService myService(
#Client("invoice-manager") InvoiceManagerClientStub clientStub,
SomeOtherBean bean1, ...) {
So I would like to do the same as the #Value annotation e.g. derive the value from the annotation on the parameter (plus some internal lookups).
Unfortunately, the usual BeanFactorys don't seem to be aware of the target's annotations.
Alternatives considered
Using an BeanPostProcessor to inject the values into annotated fields. Well, this is what I'm currently doing, but it doesn't feel right to have an immutable class with a single setter for injection.
Injecting it to a field and then exposing it as a bean or manually invoking the constructor is even worse.
Creating a proxy instance of the injected class. This isn't possible since the injected classes are generated + final and not part of my library.
Derive the configuration from the bean name: Not sure how to implement this and how to explain the user what the configuration parameters should be named in their properties files. I also would like to avoid bean name conflicts.
Non-Goals
Overwriting any core beans. I would like to distribute the extension as a library (spring-boot based), so any excessive replacement of spring internal beans should be avoided.
TLDR
How do I tell spring to resolve the parameter using my annotation's value (resolver)?
I don't understand what problem #Primary resolves.
The documentation says:
[#Primary] Indicates that a bean should be given preference when multiple
candidates are qualified to autowire a single-valued dependency. If
exactly one 'primary' bean exists among the candidates, it will be the
autowired value.
Example code:
#Configuration
class Configuration {
#Bean
#Primary
MyType bean1() {
return new MyType(1);
}
#Bean
MyType bean2() {
return new MyType(2);
}
}
Example:
I have 2 beans, bean1 and bean2, both with the type MyType. bean1 has a #Primary annotation, so when I autowire an object of type MyType to some constructor, bean1 will be chosen.
Why is it useful to have two beans of the same type if the primary bean will always be chosen? When and how could I use bean2 which isn't annotated as primary? The example shows that bean2 is redundant and unused.
You can still always qualify which bean you actually want, meaning the primary one will not always be chosen.
#Component
class MyComponent
{
public MyComponent(#Qualifier("bean2") MyType foo) { /*...*/ }
}
#Primary just tells Spring which bean to give precedence to if there are two or more possible candidates. You can always be explicit.
Also, another constructor might take a list of all MyTypes. In which case, both beans would be autowired.
#Component
class AnotherComponent
{
public AnotherComponent(List<MyType> allFoos) { /*...*/ }
}
So why could I have two beans of the same type if primary bean will be injected?
Actually the primary bean will be only injected if you didn't specify which one of your beans you want to inject, and #Primary is used to specify which bean will be injected when the type is not specified.
And to answer your question, having two beans of the same type is a common way of giving different implementations, there are many cases when we want to use two beans of the same bean, the most common situation is when we want to specify two data sources for the same application.
And to specify which one of our beans we want to go with, we use the #Resource annotation like this:
#Resource(name="bean2")
MyType bean;
For futher details you can check the discussed differences between #Resource and #Autowired.
Say you have multiple instances of beans which have some differences among them. In many cases (say > 90% for example) you will need one of them, and you will rarely use the other ones. In this case it makes sense to annotate as #Primary the most used one and in this way it will be directly injected by the framework when no further specification is provided. In the other case you will specify the exact bean to use using the #Qualifier annotation.
An example can be initializing beans of RestTemplate, say you will define a global one which will have generic settings and will be used accross all application, and another one with some specific retry policy for a small set of use-cases.
One of possible usages of #Primary you can override your Bean in tests by set #Primary there. Still your secondary Bean is used when you run an application.
I have a collection of classes which I want to be injected into the Spring application context. However, these classes can only be guaranteed to be annotated with one of a group of annotations I have written - i.e. I can assume it will be annotated with #MyAnnotation, but not #Component.
However, #MyAnnotation forms part of an API for my project, and I don't want to state an explicit dependency of this API on Spring. Thus, I can't annotate #MyAnnotation with #Component in order to have it be transitively picked up by Spring.
Is there a way to tell Spring to additionally include #MyAnnotation in its classpath scanning without adding this dependency to my API?
Currently I'm manipulating the bean definition registry to 'manually' add each class annotated with #MyAnnotation, but I'd prefer to rely on Spring's inbuilt support.
Thanks in advance.
It's possible if you create your own BeanDefinitionRegistryPostProcessor to register your own beans. If you implement the postProcessBeanDefinitionRegistry method, you can add beans to the registry by yourself, for example:
#Component
public class FooFactoryBean implements BeanDefinitionRegistryPostProcessor {
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
registry.registerBeanDefinition(..);
}
}
To obtain these bean definitions, you can use the ClassPathScanningCandidateComponentProvider class, which will create BeanDefinition objects for all classes found for a specific filter. In this case, an AnnotationTypeFilter will work:
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(Foo.class));
Set<BeanDefinition> definitions = scanner.findCandidateComponents("com.example.my");
In this example, it will find all classes annotated with #Foo in the com.example.my package.
#Configuration classes and XML based configuration should work for you. Have a look at this tutorial: https://www.tutorialspoint.com/spring/spring_java_based_configuration.htm
But to get your #MyAnnotations picked up is more difficult (see #g00glen00b's answer), and I'm not sure it makes sense if the above mentioned solutions are available.
I would like to autowire a component (still using the #Autowired annotation), but not require it to have the #Component (or other similar annotations) on it. How would I do this?
public class A {
#Autowired
private class B b;
}
#Component
public class B {
}
This would be convenient in order to allow autowiring of class A without requiring the creation of A, unless we needed it (in otherwise on the fly by reflection using the class name).
Injection and autowiring do not require #Component. They require beans. #Component states that the annotated type should have a bean generated for it. You can define beans in other ways: with a <bean> declaration in an XML context configuration, with a #Bean method in a #Configuration class, etc.
Your last sentence doesn't make much sense. You can't process injection targets in a bean without creating a bean. You also can't inject a bean without creating it. (Applied to scopes, bean may refer to the target source/proxy and not the actual instance.) Perhaps you want #Lazy.
I don't sure, If I correctly understood to your question. But if you want inject bean B without marking bean A via some annotation, or xml definition, you can use SpringBeanAutowiringSupport
public class A {
#Autowired
private class B b;
public A{
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
}
Spring documentation defines #Component annotation in the following way: "Indicates that an annotated class is a "component". Such classes are considered as candidates for auto-detection when using annotation-based configuration and classpath scanning. "
This is concise, but it does not say a lot. I understand that #Component is used to indicate that a class lifecycle (creation/destruction) will be managed by Spring. The question I have: I need to use it only in classes that will be autowired somewhere (1) or do I also need to use it in classes that have autowired attributes (2)?
(1)
#Component
class B {
}
class A {
// #Autowired
B b;
}
(2)
#Component
class B {
}
#Component
class A {
// #Autowired
B b;
}
Well, strictly speaking you don't have to use anywhere, you can define beans in XML like in the old days. Also you can use #Service or #Repository like in the old days. But back to your question:
If your bean A is not annotated with #Component or otherwise known to the Spring context, it will never be created and managed by Spring. So you either have to use an annotation or define A in XML.
This is true for B as well. If you want it to be a subject for autowiring, it must be known to Spring - either by annotation scanning or by XML.
At the end of the day it doesn't really matter whether you use XML, annotation or Java configuration. It's important that both beans are known to application context.