- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我阅读了有关 @Bean Lite 模式的 spring 文档的一部分 here据我了解,如果配置被注释为组件,那么 spring 不会创建此配置的代理类,并且该类中的所有配置的 bean 都被视为普通方法调用。然而,根据这个例子,Spring为注释为@Transactional的bean创建了代理,并在@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
最佳答案
我会尽力解释
if config is annotated as component then spring doesn't create proxy class of this config
Spring 容器仅在需要时才为 bean 创建代理,例如对 bean 的任何特殊处理,例如:AOP、事务管理。我已经为另一个SO问题解释了这一点here ,如果有兴趣,请仔细阅读答案的 A2 部分。
例如,如果 Conf
类 bean 使用 @Transactional
注解,则该类将成为代理。
all configured beans inside this class are treated as plain method calls
不正确。 Lite 模式中的所有自调用或内部方法调用都是普通方法调用,这与使用 @Configuration
注解的类中的特殊处理形成鲜明对比。在 @Configuration
带注解的类中,对 @Bean
带注解的方法的多次调用会返回同一个 bean 实例。
来自 @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.
观察结果
Spring created proxy for bean annotated as @Transactional and configured inside @Component class
正如预期的原因
@Transactional
注解的类需要代理@Component
注解的类不需要任何特殊处理我修改了您的示例以更好地解释这一点
显着的变化是
@Transactional
注释@Component
注释类来解释代理。@Configuration
类来解释“bean 间引用”支持ConfigurationBean.init()
方法的 @Transactional
来解释代理。代码
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
由于 Lite 模式返回两个不同的 Bean 实例。ConfigurationBean
返回相同的实例。ConfigurationBean
实例不被代理。有一个很棒的answer作者:@kriegaex 关于 @Configuration
类的工作。请阅读。
希望这有帮助。
关于java - Bean 轻量模式配置如何在 Bean 上创建代理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60782970/
我是一名优秀的程序员,十分优秀!