CDI bean configuration - spring

I'm totally new to CDI.
I'm used at configuring beans in XML (Spring). In CDI, should I configure them in classes directly? I have tens of beans with the same implementation but different configuration.

CDI uses a mixture of annotations and xml configuration to configure which beans are active in the deployment. It's a big topic but I'll attempt to summarise:
On your bean implementations you can use the following standard annotations:
#Default
#Alterative
#Vetoed
#Specializes
#Default is assumed unless no other annotations are present
#Alternative beans are not active unless specified so in your META-INF/beans.xml
#Vetoed beans are never considered active
#Specializes beans will always take precedence over their superclasses.
In addition to those you can create your own qualifiers to more accurately select which bean you want for what purpose.
You would create a qualifier as an annotation like this:
#Qualifier
#Retention(RUNTIME)
#Target({ TYPE, FIELD, PARAMETER, METHOD })
public #interface MyQualifier {
}
Note the #Qualifier and #Retention(RUNTIME) annotations.
You can also add parameters to your customer qualifier.
I would recommend giving the Weld documentation a read, it's comprehensive and quite well written:
Weld manual

Yes, configuration happens within the code. There have been several attempts at doing XML based configuration, look for Seam Config.
For your tens of beans, you would typically use producer methods to create the individual implementations with their own configuration. CDI uses qualifiers, rather than bean ids to identify beans.

Related

What Default order of beans creating in Spring Boot?

What Default order of beans creating in Spring Boot if we don't use #DependsOn and #Order?
I searched for documentation and found only "How to control the order of creating"
From this Spring doc (scroll down a bit):
...Your target beans can implement the
org.springframework.core.Ordered interface or use the #Order or
standard #Priority annotation if you want items in the array or list
to be sorted in a specific order. Otherwise, their order follows the
registration order of the corresponding target bean definitions in the
container.
You can declare the #Order annotation at the target class level and on
#Bean methods, potentially for individual bean definitions (in case of
multiple definitions that use the same bean class). #Order values may
influence priorities at injection points, but be aware that they do
not influence singleton startup order, which is an orthogonal concern
determined by dependency relationships and #DependsOn declarations.

Spring - register Beans before everything else

I need to register a series of BeanDefinition(s) before every other Bean gets created. That's because those registered Bean(s) are needed for autowiring and ApplicationContext#getBean calls.
I cannot use #DependsOn, obviously.
Example:
final var beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(...);
beanDefinition.setLazyInit(true);
beanDefinition.setAbstract(false);
beanDefinition.setAutowireCandidate(true);
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
registry.registerBeanDefinition("...", beanDefinition);
Which point/interface/lister can I use to obtain this? Keep in mind I need an instance of BeanDefinitionRegistry.
Adding explanation as required.
Those definitions are created from a list of Classes gathered by scanning the classpath. Those classes are not Spring Bean(s) natively, so I need to integrate them into my ApplicationContext. Those classes, however, accepts constructor arguments which are Spring Beans.
That's why I'm setting
beanDefinition.setAutowireCandidate(true);
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
Those new registered Beans are there used by other Bean(s) (native Beans).
You are trying to make the solution too complex. If your only goal is to have non #Component annotated classes be detected by component scanning and have them used as Spring Beans simply define a custom includeFilter for the #COmponentScan.
You can use a filter of type ASPECTJ or REGEX to match a package or type.
#ComponentScan(includeFilter = #Filter(type=REGEX, expression="com.foo.bar.*))
Something like that will automatically detect your beans (assuming they are in a packaged being scanned) and create spring beans out of them. If they have a single constructor that will automatically be used to create an instance.
Register a new BeanFactoryPostProcessor or BeanDefinitionRegistryPostProcessor bean in your context. This bean will get invoked after bean definitions are scanned but before actual beans are constructed:
Extension to the standard BeanFactoryPostProcessor SPI, allowing for the registration of further bean definitions before regular BeanFactoryPostProcessor detection kicks in. In particular, BeanDefinitionRegistryPostProcessor may register further bean definitions which in turn define BeanFactoryPostProcessor instances.

Custom Annotations in spring

In my project we have set up something like below
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD,ElementType.ANNOTATION_TYPE, ElementType.PARAMETER})
#Inherited
#Documented
#Qualifier(“MessageConverterQualifier”)
public #interface MessageConverterRef {}
Above Is used at many places in CoreConfig files (annotation based loading)
#Bean
#MessageConverterRef
public DocumentToABCResponseMessageConverter
documentToABCResponseMessageConverter() {
return new DocumentToABCResponseMessageConverter();
}
#Bean
#MessageConverterRef
public StringToABCResponseMessageConverter stringToABCResponseMessageConverter(
StringToDomBasedMessageConverter stringToDomBasedMessageConverter) {
return new StringToABCResponseMessageConverter(stringToDomBasedMessageConverter);
}
I am not able to understand what is the need of MessageConvertoerRef custom annotation here.
This custom annotation is used at now of places while initializing the beans using #Bean.
Request you to let me know what does it mean and what difference is it making .
This is an elegant solution to ensure compile-time safety for autowiring a set of beans by using the same qualifier. If you look at your custom annotation #MessageConverterRef you will see that the only truly meaningful annotation it is decorated with is:
#Qualifier(“MessageConverterQualifier”))
Use case: you happen to have a set of beans serving the same purpose (like having converters for different types, like you do) it would be really convinient to annotate all of them with the same Spring Qualifier (in your case MessageConverterQualifier), so that they can be all autowired into a list.
The next step is to recognize that having a set of beans scattered across your project that should be annotated with the same qualifier name is not enterily safe, neither the most elegant solution. Defining your own annotation (#MessageConverterRef) once, and reuse it everywhere it is needed reduces the chance of of error (typos) and at the same time increases readability and provides a cleaner code.
For more info on the topic I suggest reading the corresponding Spring doc, especially this part:
Qualifiers also apply to typed collections (as discussed above): e.g. to Set. In such a case, all matching beans according to the declared qualifiers are going to be injected as a collection. This implies that qualifiers do not have to be unique; they rather simply constitute filtering criteria. For example, there could be multiple MovieCatalog beans defined with the same qualifier value "action"; all of which would be injected into a Set annotated with #Qualifier("action").

Inconvenient of #Value Annotation in Spring 3.0

I'm wondering if I add a #Value annotation on a property, the class who contains this property cannot be used by another one with a different value, Example :
MyClassUtil.java had
#Value("${some.value}")
private int _myProperty;
And of course there is one module.properties who contain :
some.value=10
Another class ClassA.java wants to use this class with value 10. Ok, no problem.
But another class ClassB.java wants to use this class but with another value : 20. I cannot do this if I'm not mistaken.
Because before #Value era, I could declare two beans in the moduleContext.xml without any problem.
So, is #Value pushes you to do some strong coupling ?
You are right that the annotation configuration can not be instance specific. It is important to understand the concept of bean definitions in bean factory.
Manual bean definition:
Single <bean> element in your XML config leads to a single bean definition. Multiple <bean> mean multiple definitions (regardless of a bean type).
Single #Bean method within #Configuration class leads to a single bean definition. Multiple #Bean methods mean multiple definitions (regardless of a bean type).
However when using component scan, classes annotated with #Component-like annotations are auto-registered as a single bean definition. There is no way you can register bean multiple times via component scan.
Similarly, annotation configurations (#Value, #Autowired, etc.) are type-wide. Your bean instances are always augmented and processed with the same effect (e.g. injecting the same value). There is no way you can alter annotation processing behaviour from instance to instance.
Is this tight coupling? It is not in its general understanding - bean factory (Spring) is still free to inject whatever it thinks is suitable. However it is more of a service lookup pattern. This simplifies your life when working with domain specific singletons. And most beans in an application context tend to be singletons, many of them domain specific (controllers, services, DAOs). Framework singletons (non-project specific reusable classes) should never use annotation based configuration - in this scope, it is an unwanted tight coupling.
If you need different bean instances, you should not use annotation configuration and define your beans manually.

Spring configurable bean injection

Is there any way to inject bean dependencies make configurable except from factory pattern?
I have 3 class implement same interface and have 3 bean definition. I want to change that beans using in other class? For excample is it possile to read bean name form conf file and use it as varible?
Yes, you can go with #Qualifier annotation. As you have 3 classes which implement same interface, name those classes with different names and use #Qualifier annotation.
Spring documentation says : autowiring by type may lead to multiple candidates, it is often necessary to have more control over the selection process. One way to accomplish this is with Spring's #Qualifier annotation.

Resources