How to use #Autowired with Java-based config? - java

I am using Java-based Spring configuration in my project, specifying bean construction in #Bean-annotated methods in #Configuration. Recently, Recently, I've started to think that maybe it would've been better to use #Autowired to remove all non-important beans from #Configuration, leaving only small "root" set of them (key services and technical beans like those of Spring MVC).
Unfortunately, it seems that Spring can notice implementations for #Autowired dependencies only if they are inside component-scanned package which I cannot do without resorting to some XML.
Is there any way to use #Autowired with Java-based configuration without explicitly specifying each bean?

If I understand you correctly, you're expecting Spring to auto-discover the DaoImpl class based on the autowired dependency on the Dao interface.
This isn't going to happen - you either need to use component scanning, or you need to explicitly declare the bean, either as <bean> or #Bean.
The reason for this is that Java provides no mechanism to discover classes which implement a given interface, the classloader just doesn't work that way.

If you are implementing the Idao via dao and you are looking to #Autowire that dependency into your reference var... you need to first:
define the bean so you (in Java Based Config) simply return the impl class to the interface. The bean name is that of your method name.
When you autowire this, it will search for a matching name between your reference variable you are looking to autowire and your declaration.
THEN you will be fine. Hope this helps.

Related

How can I inject dependency from a library in Spring Boot 2?

I have a library in which I defined a class let's say MyClass with #Component along with #Value but when I try to use this in my Spring Boot application and try to Autowire it, I get exception about Spring not being able to find this type and ask me to define a Bean. All other classes gets injected just fine that I have defined in the application it self.
How can I make the MyClass to be injected?
Without a complete information on about your library, how you are using it, we can't provide solution. Assuming everything on your library is correct, you can simply add #ComponentScan on the application that use your library.
Create a class as below and that should fix your problem.
#Configuration
#ComponentScan({"your library package"})
public class YourConfig {
}
If this doesn't solve your problem, add more information on your question and I will update my answer accordingly.

Example of BeanPostProcessor

I know how spring BeanPostProcessor works but I exactly don't get any such scenarios where BeanPostProcessor might be very helpful. If someone has implemented BeanPostProcessor in his/her application, then please give a brief about that.
The BeanPostProcessor interface is arguably the most basic and useful tool of the Spring IoC container. Take a look at the implementing classes in the javadoc.
You typically use Spring to inject beans into other beans. Spring uses AutowiredAnnotationBeanPostProcessor to achieve this. After the bean has been instantiated, this BeanPostProcessor scan the bean's fields for #Autowired targets. If it finds any, it tries to resolve a bean from the context to inject. You can find the source code here.

CDI: Injecting resources to beans from external libraries

In Spring we have annotation-based and XML-based configuration. While the first is recommended for quick development, the second is more flexible and able to handle special cases. By us there are currently 2: injecting mocks for JUnit tests and configuring beans from external libraries.
I haven't found any equivalent for XML configuration for CDI, so my question is, how to handle dependency injection for such beans? They are from external libraries, they need to be configured and there's no possibility to add any annotations to them.
You have three solutions to your need:
Use a producer
CDI provides a way to transform non CDI class in beans. It is called a producer. If you want to create a bean from a class named NonCdiClass You only have to create something like that
public class MyProducers {
#Produces
public NonCdiClass produceNonCdiClass() {
return new NonCdiClass();
};
}
}
You can now #Inject this bean when needed.
You can put as many producer method as you want in your class.
If you need to simulate injection in your produced bean you can do it thanks to CDI that injects parameters in producer methods calls.
#Produces
public NonCdiClass produceNonCdiClass(MyFisrtBean param1, MySecondBean param2) {
NonCdiClass res = new NonCdiClass(param1);
res.setParam(param2);
return res;
};
}
In this example MyFirstBean and MySecondBean are existing bean classes that will be injected by CDI at producing time.
Producers can also have Qualifiers (on them or on their parameters) or inject the InjectionPoint which is a CDI internal bean allowing you to produce your bean differently in function of where is the injection and what annotation it has.
You have a nice InjectionPoint example in Weld reference documentation.
Develop an extension
I won't go into much details here since I don't know if it's your need, but you can register bean in an extension in the AfterBeanValidation phase. These registered beans can be of any class you want.
Should you need more info I could develop here.
Use Seam Solder (legacy) or wait for Deltaspike 0.6
Solder integrated a config module but this project is no more maintained since it's been in the process to be merged in Apache Deltaspike. This merge is in Deltaspike roadmap for version 0.6: http://issues.apache.org/jira/browse/DELTASPIKE-271. So you could start using Solder config and switch to Deltaspike when it'll have the feature (which should be quite close).
This solution is not my favorite but if you really want to have a config file à la Spring, it's the closest solution
Pure CDI provides the #Alternative annotation to inject for example mock objects during testing phase via beans.xml, but many mock libraries do a better work since they're designed for it.
I'm not aware of a way to use beans.xml to inject anything outside of the ear/war itself.

Spring annotations confusing and makes me don't get the full idea behind it

Basically #Autowire and #Configurable do the same. What is the difference between these two annotation?
Please pardon me.
#Configurable allows you to inject dependencies without explicit bean definition while #Autowire used to inject the explicitly defined beans.

If a Controller has a #Controller annotation, shouldn't that be enough for Spring without component scanning?

According to the Spring docs, to enable autodetection of annotated controllers, you add component scanning to your configuration:
<context:component-scan base-package="org.springframework.samples.petclinic.web"/>
My question is, why is this necessary?
If a Controller has an annotation to already indicate what it is, shouldn't that be enough for Spring without component scanning?
How else would Spring find the classes? If you haven't told Spring to look in a certain class or package, those classes aren't going to get loaded, and Spring is never going to find them.
This is more a limitation of the java classloading model (if you can call it a limitation), then it is a limitation of Spring.
You only have to put the following in your configuration:
<context:annotation-config/>
If you only put the annotation on your class, the framework had to load all the classes to check if the annotation is present.
To minimize this overhead, you have to put the annotation-config tag in your configuration. That way the framework knows it has to check the classes from that configuration.
You can help the framework by specifying the package where your annotated classes are with the "base-package" attribute.
//EDIT//
This also explains the note in the documentation:
Note
<context:annotation-config/> only
looks for annotations on beans in the
same application context in which it
is defined. This means that, if you
put in a
WebApplicationContext for a
DispatcherServlet, it only checks for
#Autowired beans in your controllers,
and not your services.
Simply annotating a class with #Controller doesn't necessarily mean you want it to be part of your Spring context. Imagine if the class is part of another application, or part of a third party library, or a deprecated component of your system, etc. Just because it is on the classpath doesn't necessarily mean that you want it automatically instantiated as a bean in your Spring context.

Categories

Resources