I had being using the JSR 330 #Inject annotation to autowire my Spring beans. I started experimenting by removing the #Inject annotation - yet my application context still gets loaded correctly. Not sure if this is expected and cant find any spring documentation to verify this use case.
// This context is loaded correctly - and beans exist for B, C and Db
final ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
#Import({ B.class })
#Configuration
public class ApplicationConfig {
#Bean
public Db db() {
return new Database();
}
#Bean
// I thought this method would need an #Autowire or #Inject annotation to resolve b!?
public C c(final B b){
return new C(b);
}
}
#Configuration
public class BConfig {
#Bean
public B b() {
return new B();
}
}
#Autowired (or #Inject if you prefer) is implicit in #Bean methods (always has been as far as I know).
Related
My #Configuration defines a couple of beans - A & B
#Configuration
public class MyConfiguration {
#Bean
public A supplyA() {
return new A(...);
}
#Bean
public B supplyB() {
return new B(...);
}
}
I was expecting that I should #Autowire A and B where they are needed, like so:
#Controller
public MyController {
#Autowire
public MyController(A a, B b) {
}
}
But it does work fine without the #Autowire on the constructor. What gives? (I'm on Spring 5 if that matters)
I think what you're trying is constructor injection, check https://docs.spring.io/spring/docs/4.3.26.RELEASE/spring-framework-reference/htmlsingle/#beans-constructor-injection
#Autowire, normally used for set injection.
Please understand the difference, before you make a change
Suppose we start with an xml-based config, say main.xml, that imports a java config FullConfig.java via:
<context:annotation-config/>
<bean class="test.FullConfig"/>
This java config has the form:
#Configuration
#Import(value = {IncludeConfig.class})
public class FullConfig {
#Autowired
#Qualifier(value = "tmpBean")
private DataClazz autowired;
#Bean
public DataClazz someOtherBean() {
System.out.println("Using autowired tmpBean:" + autowired);
return new DataClazz();
}
}
so it imports a further java config, which contains a definition of the tmpBean of DataClazz type,
#Configuration
public class IncludeConfig {
#Bean
public DataClazz tmpBean() {
return new DataClazz();
}
}
Now two questions:
Is this "transitive inclusion" guaranteed to work in spring (i.e. is someOtherBean() guaranteed not to thrown a NPE)?
IntelliJ up to version 2017.2 does mark #Qualifier(value = "tmpBean") red with a message "Cannot find bean with qualifier 'tmpBean'". Should that be considered a bug?
Note: I have checked that an application using ClassPathXmlApplicationContext("main.xml") does work correctly, i.e. no NPE is thrown (and all relevant beans are visible).
You need to return DataClazz:
#Bean
public DataClazz someOtherBean() {
System.out.println("Using autowired tmpBean:" + autowired);
return autowired;
}
Probably yes but try to test it.
IDEA-82844 (Bug)
I am getting NoSuchBeanDefinitionException if I add #Async on a method in a class annotated with #Service, if that class is used in another bean instantiated with #Bean in a #Configuration class.
Below I sketched a simple example:
#Configuration
#EnableAsync
public class Configuration() {
#Bean
public A a(C c) {
return new A(c);
}
}
public interface B {
public void asyncMethod();
}
public class A {
private B b;
public A (B b) {
this.b = b;
}
public void someMethod() {
b.asyncMethod();
}
}
#Service
public class C implements B{
#Async
#Overrides
public void asyncMethod() {
// to stuff
}
}
If I remove the #Async from asyncMethod, the application starts.
If I instantiate A by annotating it with #Service and #Autowired on the constructor, the application starts.
The constraint is that I must instantiate class A from a separate #Configuration class.
I am using a clean code architecture on the application, where classes in the core domain don't use any spring annotations on them. A class is part of the core domain.
I am instantiating some of these classes as Spring Beans from an outer layer so I don't "pollute" them with spring-specific annotations. B is part of the outer layer and can have Spring annotations.
If I put a break-point in class B's constructor, I can see it is instantiated by spring just before I get: NoSuchBeanDefinitionException for it.
I assume that the #Async is causing some weird behavior on the proxies. How can I approach this?
In xml defined beans you can define two classes like this
<bean id="classA" class="ex.ClassA"/>
<bean id="classB" class="ex.classB"/>
Then in your java implementation you can autowire the constructor of one of the classes in example
public class ClassA {
#autowired
public(ClassB classB){
this.classB = classB;
}
Now how does one do that with java config beans since in example
#Bean
public ClassA classA(){
return new ClassB();
}
#Bean
public ClassB classB(){
return new ClassB()
}
the compiler would warn that Class a does not have any such constructor, how does one do that in java, with autowiring?
Thanks all
See http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-java-injecting-dependencies
Note that the ClassB bean is implicitly a singleton. The use of the annotation #Configuration on the Config class ensures that Spring returns the singleton instance of the ClassB bean in the classB() call.
#Configuration
public class Config {
#Bean
public ClassA classA(){
return new ClassA( classB() );
}
#Bean
public ClassB classB(){
return new ClassB();
}
}
Or you may prefer this approach (Spring 4.2.1+ required)
#Configuration
#Import(ClassA.class)
public class Config {
#Bean
public ClassB classB(){
return new ClassB();
}
}
#Component
public class ClassA {
#Autowired
public ClassA(ClassB classB) {
...
}
}
Pass the beans you want as parameters to the #Bean method, or use component scanning to create the dependent bean implicitly.
I wonder if there is a way to get #Required working when doing the configuration by annotations. I turned my configuration up-and-down and back again but nothing seems to work for me. I'm using Spring 3.1
My basic configuration looks like this:
#Configuration
public class SpringConfig {
#Bean
public MailSender mailSender() {
MailSender MailSender = new MailSender();
// mailSender.setBean(dlMailSender);
return mailSender;
}
#Bean
public MyBean myBean() {
MyBean myBean = new MyBean();
// setting som props
return myBean;
}
}
MailSender is here:
#Configurable
public class MailSender {
private MyBean myBean;
#Required
public void setMyBean(MyBean myBean) {
this.myBean = myBean;
}
}
I'm testing it with this junit:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { SpringConfig.class }, loader = AnnotationConfigContextLoader.class)
public class MailSenderTest {
#Test
public void test_main_beans_exists() {
// when then given
}
}
Thanks for any help
Short answer - this is not even theoretically possible.
When using XML-based, bean definitions with their dependencies are completely managed by application context. Spring is able to check, what is being set and what is not being set.
When using annotation-based configuration, you are setting the dependencies yourself. There is no way how Spring can even know what you are doing with the bean before returning it from the factory method.
If you want to check whether the bean is correctly initialized, use InitializingBean or #PostConstruct and implement self-checking method. Spring is doing this regularly in its own beans.