I read a part of spring doc about @Bean Lite mode here As I understand, if config is annotated as component then spring doesn't create proxy class of this config and all configured beans inside this class are treated as plain method calls. However, according to this example, Spring created proxy for bean annotated as @Transactional and configured inside @Component class
@SpringBootApplication
public class TranslatorApplication implements CommandLineRunner {
@Autowired
ProxyBean bean;
@Autowired
Conf conf;
public static void main(final String[] args) {
SpringApplication.run(TranslatorApplication.class, args);
}
@Override
public final void run(final String... args) {
System.out.println(conf.getClass().getSimpleName());
System.out.println(bean.getClass().getSimpleName());
}
@Component
static class Conf {
@Bean
public ProxyBean bean() {
return new ProxyBean();
}
}
static class ProxyBean {
@Transactional
public void init() {
}
}
}
The output:
Conf
TranslatorApplication$ProxyBean$$EnhancerBySpringCGLIB$$f4c1a493
Which means that ProxyBean is a proxy created by CGLIB. The question is, if configuration class is not a proxy then how Spring created a proxy for method public ProxyBean bean()
? Spring Boot version - 2.1.6
I will try to explain
if config is annotated as component then spring doesn't create proxy class of this config
Spring container creates proxy for a bean only if it is required , like for any special processing for the bean eg: AOP , Transaction Management. I have explained this for another SO question here , please go through A2 section of the answer if interested.
So for example , the Conf
class bean will be a proxy if the class is annotated with @Transactional
.
all configured beans inside this class are treated as plain method calls
Not correct. All the self invocation or internal method calls in a Lite mode are plain method calls in contrast to the special processing within a class annotated with @Configuration
. In a @Configuration
annotated class , multiple calls to a @Bean
annotated method returns the same bean instance.
From the documentation of @Bean
In contrast to the semantics for bean methods in @Configuration classes, 'inter-bean references' are not supported in lite mode. Instead, when one @Bean-method invokes another @Bean-method in lite mode, the invocation is a standard Java method invocation; Spring does not intercept the invocation via a CGLIB proxy. This is analogous to inter-@Transactional method calls where in proxy mode, Spring does not intercept the invocation — Spring does so only in AspectJ mode.
So the observation that
Spring created proxy for bean annotated as @Transactional and configured inside @Component class
is as expected for the reasons
@Transactional
needs proxying@Component
does not require any special processing in this exampleI have modified your example to explain this better
Notable changes are
@Component
annotated class with @Transactional
to explain the proxying.@Configuration
class to explain the 'inter-bean references' support@Transactional
for ConfigurationBean.init()
method to explain the proxying.Code
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@SpringBootApplication
public class TranslatorApplication implements CommandLineRunner {
@Autowired
ComponentBean beanOne;
@Autowired
ComponentBean beanTwo;
@Autowired
ComponentConf conf;
@Autowired
ConfigurationBean beanThree;
@Autowired
ConfigurationBean beanFour;
@Autowired
ConfigurationConf config;
public static void main(final String[] args) {
SpringApplication.run(TranslatorApplication.class, args);
}
@Override
public final void run(final String... args) {
System.out.println(conf+" : "+conf.getClass().getSimpleName());
System.out.println(beanOne+" : "+beanOne.getClass().getSimpleName());
System.out.println(beanTwo+" : "+beanTwo.getClass().getSimpleName());
System.out.println(config+" : "+config.getClass().getSimpleName());
System.out.println(beanThree+" : "+beanThree.getClass().getSimpleName());
System.out.println(beanFour+" : "+ beanFour.getClass().getSimpleName());
}
interface ComponentConfIntf{}
@Component
@Transactional
static class ComponentConf{
@Bean
public ComponentBean beanOne() {
return new ComponentBean();
}
@Bean
public ComponentBean beanTwo() {
return beanOne();
}
}
static class ComponentBean {
@Transactional
public void init() {
}
}
@Configuration
static class ConfigurationConf {
@Bean
public ConfigurationBean beanThree() {
return new ConfigurationBean();
}
@Bean
public ConfigurationBean beanFour() {
return beanThree();
}
}
static class ConfigurationBean {
public void init() {
}
}
}
Prints
rg.xx.xx.TranslatorApplication$ComponentConf@8a589a2 : TranslatorApplication$ComponentConf$$EnhancerBySpringCGLIB$$e204f764
rg.xx.xx.TranslatorApplication$ComponentBean@c65a5ef : TranslatorApplication$ComponentBean$$EnhancerBySpringCGLIB$$d3d05c88
rg.xx.xx.TranslatorApplication$ComponentBean@6b5176f2 : TranslatorApplication$ComponentBean$$EnhancerBySpringCGLIB$$d3d05c88
rg.xx.xx.TranslatorApplication$ConfigurationConf$$EnhancerBySpringCGLIB$$9369a982@b672aa8 : TranslatorApplication$ConfigurationConf$$EnhancerBySpringCGLIB$$9369a982
rg.xx.xx.TranslatorApplication$ConfigurationBean@2fab4aff : ConfigurationBean
rg.xx.xx.TranslatorApplication$ConfigurationBean@2fab4aff : ConfigurationBean
Do note that
ComponentConf
bean is proxied. ComponentBean
returns two different bean instances due to Lite mode.ConfigurationBean
returns the same instance. ConfigurationBean
instances are not proxied. There is an excellent answer by @kriegaex on the working of a @Configuration
class. Do read.
Hope this helps.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.