Suppose we have a method for creating some bean
#Bean MongoClient getMongo() {}
Occasionally, I see in examples people calling several times to the method itself when they want to use the bean (in our example getMongo())
Does Spring Boot somehow enable the creation of the bean only once or is it being created with every call to the method?
Actually each time you get the same object. As it was said, the default scope for spring beans is singleton which means there is only one instance of your class in Spring container.
Why do you receive the same object each time?
It's because #Configuration annotation that you used in your class implicates creation of proxy (which is subclass of your class annotated with #Configuration). This proxy stores singleton and returns reference to it whenever you call #Bean method.
Why #Bean method returns reference instead of creating object as it is in implementation?
Proxy also overrides your #Bean method.
Related
I'm curious about how spring injection handles calling methods with the #Bean annotation. If I put a #Bean annotation on a method, and return an instance, I understand that that tells spring to create a bean by calling the method and getting the returned instance. However, sometimes that bean has to be used to wire other beans or setup other code. The usual way this is done is to call the #Bean annotated method to get an instance. My question is, why doesn't this cause there to be multiple instances of the bean floating around?
For example, see the code below (taken from another question). The entryPoint() method is annotated with #Bean, so I would imagine spring will create a new instance of BasicAuthenticationEntryPoint as a bean. Then, we call entryPoint() again in the configure block, but it seems like entryPoint() returns the bean instance, and isn't called multiple times (I tried logging, and only got one log entry). Potentially we could call entryPoint() multiple times in other parts of the configuration, and we would always get the same instance. Is my understanding of this correct? Does spring do some magical rewriting of methods annotated with #Bean?
#Bean
public BasicAuthenticationEntryPoint entryPoint() {
BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
basicAuthEntryPoint.setRealmName("My Realm");
return basicAuthEntryPoint;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(entryPoint())
.and()
.authorizeUrls()
.anyRequest().authenticated()
.and()
.httpBasic();
}
Yes, Spring does some magic. Check the Spring Docs:
This is where the magic comes in: All #Configuration classes are subclassed at startup-time with CGLIB. In the subclass, the child method checks the container first for any cached (scoped) beans before it calls the parent method and creates a new instance.
This means that the calls to #Bean methods are proxied via CGLIB and therefore the cached version of the bean is returned (a new one is not created).
The default scope of #Beans is SINGLETON, if you specify a different scope such as PROTOTYPE the call will be passed to the original method.
Please note that this is not valid for static methods. As per the spring docs:
Calls to static #Bean methods never get intercepted by the container, not even within #Configuration classes (as described earlier in this section), due to technical limitations: CGLIB subclassing can override only non-static methods. As a consequence, a direct call to another #Bean method has standard Java semantics, resulting in an independent instance being returned straight from the factory method itself.
In the past I have seen people using the following 2 idioms to inject dependencies from the same #Configuration:
#Configuration
public class MyConfiguration {
#Bean
public MyBeanDependencyA myBeanDependencyA(){
return new MyBeanDependencyA();
}
#Bean . //IDIOM 1
public MyBeanDependencyB1 myBeanDependencyB1(){
return new MyBeanDependencyB1(myBeanDependencyA());
}
#Bean //IDIOM 2
public MyBeanDependencyB2 myBeanDependencyB2(MyBeanDependencyA myBeanDependencyA){
return new MyBeanDependencyB1(myBeanDependencyA);
}
}
Is there any practical difference between them?
Does Spring process the whole instantiation method in each call for IDIOM 1? (relevant if method has any side-effect, might be not idempotent)?
Does otherwise Spring inject the global managed instance when injecting for IDIOM 1? (relevant If some external process changes the state of the original singleton bean)
Is Spring container that smart?
Does Spring process the whole instantiation method in each call for IDIOM 1? (relevant if method has any side-effect, might be not idempotent)?
By default #Configuration classes are proxied at runtime so the MyBeanDependencyA will be created once and myBeanDependencyA() will be called only once by Spring and next calls will be proxied to return the same instance (as far as example that you shared is concerned). There will be only one instance of this bean in the context as it's scope is Singleton.
Does otherwise Spring inject the global managed instance when injecting for IDIOM 1? (relevant If some external process changes the state of the original singleton bean)
The IOC container will return same instance of Singleton bean when it is queried to do so. Since it is a Singleton all changes to this bean (if it is mutable) will be visible to components that have reference to it.
As a side note you can disable autoproxing of configuration class since Spring 5.2 by using :
#Configuration(proxyBeanMethods = false)
which will prevent proxying calls of methods annotated with #Bean invoked from other #Bean methods.
Does Spring process the whole instantiation method in each call for IDIOM 1?
No, This is called inter-bean dependencies, a method that annotated with #Bean annotation in #Configuration class will create a bean in spring IOC container
The #Bean annotation is used to indicate that a method instantiates, configures and initializes a new object to be managed by the Spring IoC container. For those familiar with Spring's XML configuration the #Bean annotation plays the same role as the element. You can use #Bean annotated methods with any Spring #Component, however, they are most often used with #Configuration beans.
Does otherwise Spring inject the global managed instance when injecting for IDIOM 1?
Yes, spring injects the same bean if it is required at multiple places Basic concepts: #Bean and #Configuration This inter-bean dependencies will only work in combination of #Bean and #Configuration which also prevents calling same bean method multiple times.
Only using #Bean methods within #Configuration classes is a recommended approach of ensuring that 'full' mode is always used. This will prevent the same #Bean method from accidentally being invoked multiple times and helps to reduce subtle bugs that can be hard to track down when operating in 'lite' mode.
I need to reinit singleton bean instance for all previously autowired fields.
I tried to remove the bean from registy in app context, and re-register new object.
ConfigurableApplicationContext configContext = (ConfigurableApplicationContext)appContext;
SingletonBeanRegistry beanRegistry = configContext.getBeanFactory();
((DefaultListableBeanFactory) beanRegistry).destroySingleton("fbdProg");
((DefaultListableBeanFactory) beanRegistry).registerSingleton("fbdProg", program);
It works only once, the first time it is called.
The issue is how to reinit the bean to make new instance available in other classes, where it is autowired
If you need a new instance of this bean everytime it is injected, you can use #Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) on your bean. E.g:
#Component
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class MyComponent {
// methods, fields, etc.
}
Spring then creates a new instance of MyComponent everytime it is injected into another component. So Bean A will have a different instance of MyComponent than Bean B, evaluating beanA.myComponent != beanB.myComponent to true
Every class with a #Bean annotation is a singleton by default in spring boot, but you can provide a #Scope annotation if you want that the lifehook of a variable to be related to
a session
an http request
the lifehook of a serveletContext
anyway you have to keep in mind that #Bean should be singleton, for example in the persistence pattern you have an entity and a repository. The respository should be a singletone because it essentialy gives only methods to store and retrieve entities, while an entity should not be a singletone because you need an entity for every object you have to store in a database. The same for services. You may also want to taake a look at this article: spring boot scopes
Looking through question Autowire a bean within Spring's Java configuration I got a question.
#Configuration
public class Config {
#Bean
public RandomBean randomBean(){
return new RandomBean();
}
#Bean
public AnotherBean anotherBean(){
return new AnotherBean(randomBean()); // this line
}
}
How Spring guarantees that method randomBean() will return the same reference as one which was injected into AnotherBean?
Is it achieved via proxies?
On the other hand, doing it with providing dependencies as method parameters is quiet obvious:
#Configuration
public class Config {
#Bean
public RandomBean randomBean(){
return new RandomBean();
}
#Bean
public AnotherBean anotherBean(RandomBean randomBean){
return new AnotherBean(randomBean);
}
}
Edit: finally, I found this behavior described in Further information about how Java-based configuration works internally topic.
There is only one "randomBean" because the default scope is "singleton".(To force Spring to produce a new bean instance each time one is needed, you should declare the bean's scope attribute to be prototype)
singleton
This scopes the bean definition to a single instance per Spring IoC
container (default).
prototype
This scopes a single bean definition to have any number of object
instances.
Spring guarantees that method randomBean() will return the same reference as one which was injected into AnotherBean By using proxies.
In order to generate proxies, Spring uses a third party library called CGLIB.
Spring enhances classes by generating a CGLIB subclass which
interacts with the Spring container to respect bean scoping
semantics for methods.
Each such bean method will be overridden in the generated subclass,
only delegating to the actual bean method implementation if the
container actually requests the construction of a new instance.
Otherwise, a call to such an bean method serves as a reference back
to the container, obtaining the corresponding bean by name.
see org.springframework.context.annotation.ConfigurationClassEnhancer.BeanMethodInterceptor
// To handle the case of an inter-bean method reference, we must explicitly check the
// container for already cached instances.
// First, check to see if the requested bean is a FactoryBean. If so, create a subclass
// proxy that intercepts calls to getObject() and returns any cached bean instance.
// This ensures that the semantics of calling a FactoryBean from within #Bean methods
// is the same as that of referring to a FactoryBean within XML. See SPR-6602.
if (factoryContainsBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName) && factoryContainsBean(beanName)) {
Object factoryBean = this.beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
if (factoryBean instanceof ScopedProxyFactoryBean) {
// Pass through - scoped proxy factory beans are a special case and should not
// be further proxied
}
else {
// It is a candidate FactoryBean - go ahead with enhancement
return enhanceFactoryBean(factoryBean.getClass(), beanName);
}
}
If you want to get two different beans, you should change the default scope by #Scope
#Configuration
public class Config {
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public RandomBean randomBean(){
return new RandomBean();
}
#Bean
public AnotherBean anotherBean(){
return new AnotherBean(randomBean()); // this line
}
}
According to Spring documentation injection of inter-bean possible only when #Bean method declared within #Configuration. It uses CGLIB and all #Configuration classes are subclassed by it.
Please, check this reference https://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-java-bean-annotation, section '7.12.4 Using the #Configuration annotation'. You will find answer on your question from original source.
I created a bean instance with
Type instance = new Type();
and autowired it using
ctx.getAutowireCapableBeanFactory().autowireBean(instance);
The beans run method is executed by a ThreadPoolTaskExecuter and is annotated with the
#Transactional annotation which has no effect in this case. Since lazy loading problems occur. I need a transaction here.
How can I create a transactional proxy and wrap my instance?
Is there a way other than using transaction-manager manually?
You should get the correct proxy if you apply BeanPostProcessors from the context:
instance = ctx.getAutowireCapableBeanFactory().applyBeanPostProcessorsAfterInitialization(instance);
You can certainly create a PlatformTransactionManager subclass manually and use its methods to create and commit or rollback transactions.
If you want to proxy an object, the class you probably want is org.springframework.transaction.interceptor.TransactionProxyFactoryBean. Setup an instance of that and call getObject() to get your proxied class.