Reputation: 8943
I was trying to understand difference between @component
and @Bean
in Spring framework
, and referred to this SO question.
Based on the answer, I got a fair understanding, and tried to reinforce the concept by implementing a simple example (to check whether I really understood the concept).
The below is the code which I wrote. I wanted to see @Bean
for "third party" libs (so that it can be instantiated using @Bean
annotation)
package com.example.thirdparty.code;
public class ThirdPartyUtil {
public ThirdPartyUtil() {
}
public void print(String str) {
System.out.println("String passed is --> " + str);
}
}
In above, I tried to simulate a "third party lib/class - NON spring" which isn't a spring based (and so there won't be any @component
in that class.
Now, below is the main application which I created:
package com.example.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import com.example.thirdparty.code.ThirdPartyUtil;
@Configuration
@ComponentScan(basePackages = { "com.example.spring" })
@Component
public class SpringBasedMainApp {
@Autowired
private ApplicationContext ctx;
@Autowired
private static ThirdPartyUtil thirdPartyUtil;
@Bean
public ThirdPartyUtil beanThirdPartyUtil() {
try {
Class c = getClass().getClassLoader().loadClass("com.example.thirdparty.code.ThirdPartyUtil");
return (ThirdPartyUtil) ctx.getBean(c);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Exception");
}
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringBasedMainApp.class);
System.out.println("thirdPartyUtil is " + thirdPartyUtil);
}
}
I was hoping that using @Bean
annotation, it would create ThirdPartyUtil
as Spring bean, and then inject using @Autowired
into field thirdPartyUtil
.
However, when I run this program, I got altogether a surprising exception, listed below:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'beanThirdPartyUtil' defined in com.example.spring.SpringBasedMainApp: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.thirdparty.code.ThirdPartyUtil]: Factory method 'beanThirdPartyUtil' threw exception; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'beanThirdPartyUtil': Requested bean is currently in creation: Is there an unresolvable circular reference?
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:627)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:456)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1288)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:846)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:863)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:88)
at com.example.spring.SpringBasedMainApp.main(SpringBasedMainApp.java:41)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.thirdparty.code.ThirdPartyUtil]: Factory method 'beanThirdPartyUtil' threw exception; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'beanThirdPartyUtil': Requested bean is currently in creation: Is there an unresolvable circular reference?
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622)
... 14 more
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'beanThirdPartyUtil': Requested bean is currently in creation: Is there an unresolvable circular reference?
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:339)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:215)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:224)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1112)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:407)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:341)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:335)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1101)
at com.example.spring.SpringBasedMainApp.beanThirdPartyUtil(SpringBasedMainApp.java:33)
at com.example.spring.SpringBasedMainApp$$EnhancerBySpringCGLIB$$d93c67f4.CGLIB$beanThirdPartyUtil$0(<generated>)
at com.example.spring.SpringBasedMainApp$$EnhancerBySpringCGLIB$$d93c67f4$$FastClassBySpringCGLIB$$9349d69b.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363)
at com.example.spring.SpringBasedMainApp$$EnhancerBySpringCGLIB$$d93c67f4.beanThirdPartyUtil(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
... 15 more
I didn't understand why it is giving this exception. I am creating an applicationContext using AnnotationConfigApplicationContext
and passing the necessary details to it.
I expected it to work, however got the above exception (which I have seen maiden time).
Why has this exception been thrown, is my understanding not correct about @Bean
?
Upvotes: 2
Views: 1027
Reputation: 747
To extend @JB Nizet answer, instantiate your third party class in spring constructor like below.
@Autowired
private static ThirdPartyUtil thirdPartyUtil;
@Autowired
public SpringBean() {
this.thirdPartyUtil = new ThirdPartyUtil();
}
Upvotes: -1
Reputation: 692121
The goal of the @Bean
annotation is to annotate a method whose responsibility is to create an object, that will then be registered as a bean by Spring.
But inside your method, you ask Spring (using ctx.getBean()
) to give you the bean that you're currently creating. So you get that exception.
Here's what your methd should look like:
@Bean
public ThirdPartyUtil beanThirdPartyUtil() {
return new ThirdPartyUtil();
}
Upvotes: 3