Behaviour of lite #Bean methods in Spring 5 - java

From the Spring 5 docs
When #Bean methods are declared within classes that are not annotated
with #Configuration they are referred to as being processed in a
'lite' mode. Bean methods declared in a #Component or even in a plain
old class will be considered 'lite', with a different primary purpose
of the containing class and an #Bean method just being a sort of bonus
there. For example, service components may expose management views to
the container through an additional #Bean method on each applicable
component class. In such scenarios, #Bean methods are a simple
general-purpose factory method mechanism.
Unlike full #Configuration, lite #Bean methods cannot declare
inter-bean dependencies. Instead, they operate on their containing
component’s internal state and optionally on arguments that they may
declare. Such an #Bean method should therefore not invoke other #Bean
methods; each such method is literally just a factory method for a
particular bean reference, without any special runtime semantics. The
positive side-effect here is that no CGLIB subclassing has to be
applied at runtime, so there are no limitations in terms of class
design (i.e. the containing class may nevertheless be final etc).
The #Bean methods in a regular Spring component are processed
differently than their counterparts inside a Spring #Configuration
class. The difference is that #Component classes are not enhanced with
CGLIB to intercept the invocation of methods and fields. CGLIB
proxying is the means by which invoking methods or fields within #Bean
methods in #Configuration classes creates bean metadata references to
collaborating objects; such methods are not invoked with normal Java
semantics but rather go through the container in order to provide the
usual lifecycle management and proxying of Spring beans even when
referring to other beans via programmatic calls to #Bean methods. In
contrast, invoking a method or field in an #Bean method within a plain
#Component class has standard Java semantics, with no special CGLIB
processing or other constraints applying.
I would have expected that the following code throws an exception / bean1.bean2 to be null and that the init method would not be executed. However, the code below runs fine and prints:
Should never be invoked
Expected null but is ch.litebeans.Bean2#402bba4f
So for me it looks like lite beans behave the same as beans constructed from an #Configuration annotated class. Can someone point out in which scenario this is not the case?
.
package ch.litebeans;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationConfig.class);
Bean1 bean1 = ctx.getBean(Bean1.class);
System.out.println("Expected null but is " + bean1.getBean2());
}
}
package ch.litebeans;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan(basePackages = {"ch.litebeans"})
public class ApplicationConfig {}
package ch.litebeans;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
#Component
public class Factory1 {
#Bean
public Bean1 getBean1(Bean2 bean2){
return new Bean1(bean2);
}
}
package ch.litebeans;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
#Component
public class Factory2 {
#Bean(initMethod = "init")
public Bean2 getBean2(){
return new Bean2();
}
}
package ch.litebeans;
public class Bean1 {
private Bean2 bean2;
public Bean1(Bean2 bean2){
this.bean2 = bean2;
}
public Bean2 getBean2(){
return bean2;
}
}
package ch.litebeans;
public class Bean2 {
public void init(){
System.out.println("Should never be invoked");
}
}
EDIT:
Based on the explanation of Mike Hill I added an example demonstrating the difference:
public class BeanLiteRunner {
public static void main(String[] args) {
AnnotationConfigApplicationContext acac = new AnnotationConfigApplicationContext(MyComponent.class,
MyConfiguration.class);
MyComponent.MyComponentBean1 componentBean1 = acac.getBean(MyComponent.MyComponentBean1.class);
MyComponent.MyComponentBean1 componentBean2 = acac.getBean(MyComponent.MyComponentBean1.class);
MyConfiguration.MyConfigurationBean1 configurationBean1 = acac.getBean(MyConfiguration
.MyConfigurationBean1.class);
MyConfiguration.MyConfigurationBean1 configurationBean2 = acac.getBean(MyConfiguration
.MyConfigurationBean1.class);
}
}
#Component
public class MyComponent {
#Bean
public MyComponent.MyComponentBean1 getMyComponentBean1(){
return new MyComponent.MyComponentBean1(getMyComponentBean2());
}
#Bean
public MyComponent.MyComponentBean2 getMyComponentBean2(){
return new MyComponent.MyComponentBean2();
}
public static class MyComponentBean1{
public MyComponentBean1(MyComponent.MyComponentBean2 myComponentBean2){
}
}
public static class MyComponentBean2{
public MyComponentBean2(){
System.out.println("Creating MyComponentBean2");
}
}
}
#Configuration
public class MyConfiguration {
#Bean
public MyConfigurationBean1 getMyConfigurationBean1(){
return new MyConfigurationBean1(getMyConfigrationBean2());
}
#Bean
public MyConfigurationBean2 getMyConfigrationBean2(){
return new MyConfigurationBean2();
}
public static class MyConfigurationBean1{
public MyConfigurationBean1(MyConfigurationBean2 myConfigurationBean2){}
}
public static class MyConfigurationBean2{
public MyConfigurationBean2(){
System.out.println("Creating MyConfigrationBean2");
}
}
}
The output is as expected
> Creating MyComponentBean2
> Creating MyComponentBean2
> Creating MyConfigrationBean2

This is not a bug. Spring's lite bean definitions are automatically added to the context during the component scan. Bean definitions using a factory method (i.e., all #Bean-defined beans) will automatically attempt to autowire parameters using the current context. See ConstructorResolver#instantiateUsingFactoryMethod for more details.
The referenced documentation is perhaps not entirely clear. The primary differentiation between "lite" and "full" bean configurations is strictly the proxying that is done in "full" (#Configuration) mode. Take for example what would happen if we instead defined our beans in a #Configuration class:
#Configuration
public MyConfiguration {
#Bean
public Bean1 bean1() {
return new Bean1(bean2());
}
#Bean
public Bean2 bean2() {
return new Bean2();
}
}
The call to bean2() from within bean1() will actually reference the singleton bean2 instance from the context rather than directly calling the bean2() method as implemented. In fact, it doesn't matter how many bean2() method calls are made from within that configuration class -- the real bean2 method will only be executed one time.
"Lite"-mode does not proxy these methods, meaning that each bean2() method call will actually directly reference the method implementation and will not return the bean that is in the context. Rather, it will create a new separate instance that is not tracked by the context (as is the default Java behavior).

Related

Call singleton class in spring boot rest api controller

I am new to spring framework. I have to use spring boot and have a rest controller as below :-
#RestController
public class StatisticsController {
private TransactionCache transactionCache;
public StatisticsController(TransactionCache transactionCache) {
this.transactionCache = transactionCache;
}
#PostMapping("/tick")
public ResponseEntity<Object> addInstrumentTransaction(#Valid #RequestBody InstrumentTransaction instrumentTransaction) {
transactionCache.addTransaction(instrumentTransaction);
return new ResponseEntity<>(HttpStatus.CREATED);
}
and I have a class which needs to be singleton :-
#Component
public class TransactionStatisticsCacheImpl implements TransactionCache {
private static TransactionStatisticsCacheImpl instance;
public static TransactionStatisticsCacheImpl getInstance(){
if(Objects.isNull(instance)){
synchronized (TransactionStatisticsCacheImpl.class) {
if(Objects.isNull(instance)){
instance = new TransactionStatisticsCacheImpl();
}
}
}
return instance;
}
private TransactionStatisticsCacheImpl() {}
I want to know the correct way to call this singleton class in my rest controller. I know that by default the scope of a bean in spring is singleton. Is this the correct way to call the singleton class in rest controller?
#RestController
public class StatisticsController {
private TransactionCache transactionCache;
public StatisticsController(TransactionCache transactionCache) {
this.transactionCache = transactionCache;
}
#PostMapping("/tick")
public ResponseEntity<Object> addInstrumentTransaction(#Valid #RequestBody InstrumentTransaction instrumentTransaction) {
transactionCache.addTransaction(instrumentTransaction);
return new ResponseEntity<>(HttpStatus.CREATED);
}
or
We need to call it using the getInstance() method? Also do we need to explicitly have the getInstance method in the TransactionStatisticsCacheImpl class?
One of the major advantages of container injection is that you can get the benefits of singleton semantics without all the serious problems of "hard" singletons (such as difficulty testing). Get rid of the getInstance manual business and let Spring take care of ensuring that a single instance is created and used for the context.
Just for clarification: By default, the spring IOC container will create only one instance per bean definition, unless if you specified otherwise using the #Scope stereotype. But if you create an instance using getInstance() the bean pre-processors and post-processors will not work correctly on that bean definition. And also you can use the #Autowired stereotype to inject a bean definition as needed and if you have different implementations for the same definition you can use the #Qualifier stereotype to specify the implementation that you need to inject, alternatively, you can use the constructor injection to inject your bean definition as needed without auto wiring as mentioned here Spring #Autowire on Properties vs Constructor
I would stick to the answers above. However, if you want to preserve further instantiation of the class in your code (or you want to keep your specific implementation of singleton), you can do it with getInstance().
Firstly, get rid of #Component annotation in your class:
// #Component
public class TransactionStatisticsCacheImpl implements TransactionCache {
private static TransactionStatisticsCacheImpl instance;
public static TransactionStatisticsCacheImpl getInstance(){
if(Objects.isNull(instance)){
synchronized (TransactionStatisticsCacheImpl.class) {
if(Objects.isNull(instance)){
instance = new TransactionStatisticsCacheImpl();
}
}
}
return instance;
}
private TransactionStatisticsCacheImpl() {}
}
Then, you may instantiate your singleton #Bean by defining #Configuration class - this way your bean would get managed by spring container.
#Configuration
public class SingletonConfiguration {
#Bean
public TransactionCache transactionCache() {
return TransactionCacheImpl.getInstance();
}
}
Eventually, you can have your singleton injected in your RestController using #Autowired.
#RestController
public class StatisticsController {
private TransactionCache transactionCache;
#Autowired
public StatisticsController(TransactionCache transactionCache) {
this.transactionCache = transactionCache;
}
#PostMapping("/tick")
public ResponseEntity<Object> addInstrumentTransaction(#Valid #RequestBody InstrumentTransaction instrumentTransaction) {
transactionCache.addTransaction(instrumentTransaction);
return new ResponseEntity<>(HttpStatus.CREATED);
}
}

Spring beans initialization through method

I have a little question about bean creation that bothers me a lot.
For example I have classes
public class A {
B b;
public A(B b) {
this.b = b;
}
}
public class B {}
And I want to make beans for them like this:
#Configuration
public class Config {
#Bean
public B beanB() {
return new B();
}
//version 1
#Bean
public A beanA() {
return new A(beanB())
}
//version 2
#Bean
public A beanA(B beanB) {
return new A(beanB)
}
}
So, my question is what is the right way to create bean A?
I think that the right one is version 2, because in the version 1 I think beanB can be invoked 2 times: on the creation of beanA and when spring will create it for it's context. But I can't find anything that will prove my opinion.
The "right" way is to do it the way the documentation, i.e. the javadoc of #Bean, shows it:
#Bean Methods in #Configuration Classes
Typically, #Bean methods are declared within #Configuration classes. In this case, bean methods may reference other #Bean methods in the same class by calling them directly. This ensures that references between beans are strongly typed and navigable. Such so-called 'inter-bean references' are guaranteed to respect scoping and AOP semantics, just like getBean() lookups would. These are the semantics known from the original 'Spring JavaConfig' project which require CGLIB subclassing of each such configuration class at runtime. As a consequence, #Configuration classes and their factory methods must not be marked as final or private in this mode. For example:
#Configuration
public class AppConfig {
#Bean
public FooService fooService() {
return new FooService(fooRepository());
}
#Bean
public FooRepository fooRepository() {
return new JdbcFooRepository(dataSource());
}
// ...
}
That means version 1 in the question code.
Spring dynamically subclasses AppConfig, so only one instance is created no matter how many times the method is called, e.g. functionally something like this:
public class $dynamic$ extends AppConfig {
private FooRepository cachedFooRepository;
#Override
public FooRepository fooRepository() {
if (this.cachedFooRepository == null)
this.cachedFooRepository = super.fooRepository();
return cachedFooRepository;
}
}

Specify specific bean to be injected from specific configuration class

I am having one problem where bean definition for a single Service are defined in 2 different configuration classes.
#Configuration
public class ConfigurationA{
#Primary
#Bean("beana")
public beanA(){
return Mockito.mock(BeanA.class);
}
#Bean("beanb")
public beanB(){
return new BeanB(beanA());
}
#PostConstruct
public void initialize(){
beanA().dosomething();
}
}
#Configuration
public class ConfigurationB{
#Bean("beana")
public beanA(){
return new BeanA();
}
}
So when intialize() method is called, I am expecting mocked instance of BeanA will be used but its using real instance that is injected via ConfigurationB class.
I have marked "beana" as primary bean so spring should Ideally use this instance but its using the actual real instance defined in different configuration class.
Is there any way we can configure to use the bean definition from ConfigurationA class instead of ConfigurationB?

Spring annotations confusion

i am really confused with spring annotations.
where to use # Autowired, where class is # Bean or # Component,
i understand we cannot use
Example example=new Example("String");
in Spring
but how alone
#Autowired
Example example;
will solve the purpose?
what about Example Constructor ,how spring will provide String value to Example Constructor?
i went through one of the article but it does not make much sense to me.
it would be great if some one can give me just brief and simple explanation.
Spring doesn't say you can't do Example example = new Example("String"); That is still perfectly legal if Example does not need to be a singleton bean. Where #Autowired and #Bean come into play is when you want to instantiate a class as a singleton. In Spring, any bean you annotate with #Service, #Component or #Repository would get automatically registered as a singleton bean as long as your component scanning is setup correctly. The option of using #Bean allows you to define these singletons without annotating the classes explicitly. Instead you would create a class, annotate it with #Configuration and within that class, define one or more #Bean definitions.
So instead of
#Component
public class MyService {
public MyService() {}
}
You could have
public class MyService {
public MyService() {}
}
#Configuration
public class Application {
#Bean
public MyService myService() {
return new MyService();
}
#Autowired
#Bean
public MyOtherService myOtherService(MyService myService) {
return new MyOtherService();
}
}
The trade-off is having your beans defined in one place vs annotating individual classes. I typically use both depending on what I need.
You will first define a bean of type example:
<beans>
<bean name="example" class="Example">
<constructor-arg value="String">
</bean>
</beans>
or in Java code as:
#Bean
public Example example() {
return new Example("String");
}
Now when you use #Autowired the spring container will inject the bean created above into the parent bean.
Default constructor + #Component - Annotation is enough to get #Autowired work:
#Component
public class Example {
public Example(){
this.str = "string";
}
}
You should never instantiate a concrete implementation via #Bean declaration. Always do something like this:
public interface MyApiInterface{
void doSomeOperation();
}
#Component
public class MyApiV1 implements MyApiInterface {
public void doSomeOperation() {...}
}
And now you can use it in your code:
#Autowired
private MyApiInterface _api; // spring will AUTOmaticaly find the implementation

How do I express a dependency on a bean defined in an imported configuration in Spring?

I recently started working at a place that uses Java configuration for Spring as opposed to XML and so far I'm loving it.
My question is the following:
If we have a #Configuration annotated class A that imports another #Configuration annotated class B, what is the proper, type-safe way for a bean defined in A to depend on a bean defined in B.
Here's an example I saw in a blog (https://blog.codecentric.de/en/2012/07/spring-dependency-injection-styles-why-i-love-java-based-configuration/):
#Configuration
public class PartnerConfig {
#Bean
public PartnerService partnerService() {
return new PartnerServiceImpl();
}
}
#Configuration
#Import(PartnerConfig.class)
public class CashingConfig {
#Autowired
private PartnerConfig partnerConfig;
#Bean
public CashingService cashingService() {
return new CashingServiceImpl(partnerConfig.partnerService());
}
}
As a second part to my question, if I was to do the above, would Spring interpret as a bean dependency? That is, when I do
partnerConfig.partnerService()
in the example above, am I getting Spring to fetch me the partnerService bean, or am I just calling a regular java method and creating a new instance of the PartherService (which is NOT what I want, since the bean should be a singleton) ?
EDIT:
It has been suggested to use a #Qualifier. Would this work?
#Configuration
public class PartnerConfig {
#Bean
#MyCustomQualifier
public PartnerService partnerService() {
return new PartnerServiceImpl();
}
}
#Configuration
#Import(PartnerConfig.class)
public class CashingConfig {
#Bean
public CashingService cashingService(#MyCustomQualifier PartnerService partnerService) {
return new CashingServiceImpl(partnerService);
}
}
I recommend giving the docs a read: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html
Refer to the section:
#Bean Methods in #Configuration Classes
This sums it up very well.
Typically, #Bean methods are declared within #Configuration classes. In this case, bean methods may reference other #Bean methods in the same class by calling them directly. This ensures that references between beans are strongly typed and navigable.
Also take a look at: http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html
Section:
Composing #Configuration classes
Just add the dependency as an argument to the #Bean annotated method and remove the autowiring of the configuration.
#Configuration
#Import(PartnerConfig.class)
public class CashingConfig {
#Bean
public CashingService cashingService(PartnerService partnerService) {
return new CashingServiceImpl(partnerService);
}
}
or simply autowire the PartnerService instead of the configuration.
#Configuration
#Import(PartnerConfig.class)
public class CashingConfig {
#Autowire
private PartnerService partnerService;
#Bean
public CashingService cashingService() {
return new CashingServiceImpl(partnerService);
}
}

Categories