gpt4 book ai didi

java - Bean 轻量模式配置如何在 Bean 上创建代理

转载 作者:行者123 更新时间:2023-12-02 08:50:53 31 4
gpt4 key购买 nike

我阅读了有关 @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

正如预期的原因

  1. 使用 @Transactional 注解的类需要代理
  2. 在此示例中,使用 @Component 注解的类不需要任何特殊处理

我修改了您的示例以更好地解释这一点

显着的变化是

  1. 使用@Transactional注释@Component注释类来解释代理。
  2. 添加一个 @Configuration 类来解释“bean 间引用”支持
  3. 没有用于 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

请注意

  1. ComponentConf bean 已被代理。
  2. ComponentBean 由于 Lite 模式返回两个不同的 Bean 实例。
  3. ConfigurationBean 返回相同的实例。
  4. ConfigurationBean 实例不被代理。

有一个很棒的answer作者:@kriegaex 关于 @Configuration 类的工作。请阅读。

希望这有帮助。

关于java - Bean 轻量模式配置如何在 Bean 上创建代理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60782970/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com