[英]How Bean light mode configuration creates proxy on beans
我读到@Bean精简版模式春天文档的一部分, 在这里我的理解,如果配置被注释为组件然后春天不会创建代理类,这个配置和这个类里面的所有配置的bean被视为普通的方法调用。 但是,根据此示例,Spring 为 bean 创建了代理,注释为@Transactional并在@Component类中配置
@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() {
}
}
}
输出:
Conf
TranslatorApplication$ProxyBean$$EnhancerBySpringCGLIB$$f4c1a493
这意味着ProxyBean 是CGLIB 创建的代理。 问题是,如果配置类不是代理,那么 Spring 如何为public ProxyBean bean()
方法创建代理? Spring Boot 版本 - 2.1.6
我会尽力解释
如果 config 被注释为组件,则 spring 不会创建此配置的代理类
Spring 容器仅在需要时为 bean 创建代理,例如对 bean 的任何特殊处理,例如:AOP、事务管理。 我已经在这里为另一个 SO 问题解释了这一点,如果有兴趣,请阅读答案的 A2 部分。
因此,例如,如果使用@Transactional
注释该类,则Conf
类 bean 将成为代理。
此类中所有配置的 bean 都被视为普通方法调用
不正确。 与使用@Configuration
注释的类中的特殊处理相比, Lite模式中的所有自调用或内部方法调用都是普通方法调用。 在@Configuration
注释类中,对@Bean
注释方法的多次调用返回相同的 bean 实例。
来自@Bean的文档
与@Configuration 类中 bean 方法的语义相反,精简模式不支持“bean 间引用”。 相反,当一个@Bean-method 在 lite 模式下调用另一个 @Bean-method 时,该调用是标准的 Java 方法调用; Spring 不会通过 CGLIB 代理拦截调用。 这类似于 @Transactional 间的方法调用,在代理模式下,Spring 不会拦截调用——Spring 只在 AspectJ 模式下这样做。
所以观察到
Spring 为 bean 创建了代理,注释为 @Transactional 并在 @Component 类中配置
由于原因,正如预期的那样
@Transactional
注释的类需要代理@Component
注解的@Component
在本例中不需要任何特殊处理我已经修改了您的示例以更好地解释这一点
显着的变化是
@Transactional
注释@Component
注释的类以解释代理。@Configuration
类来解释“豆间引用”支持@Transactional
for ConfigurationBean.init()
方法来解释代理。代码
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() {
}
}
}
印刷
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
请注意
ComponentConf
bean 被代理。ComponentBean
返回两个不同的 bean 实例。ConfigurationBean
返回相同的实例。ConfigurationBean
实例没有被代理。 @kriegaex 关于@Configuration
类的工作有一个很好的答案。 阅读。
希望这可以帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.