当前位置: 首页 > 知识库问答 >
问题:

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

单昊穹
2023-03-14

我在这里阅读了spring文档中关于@Bean Lite模式的部分内容,根据我的理解,如果config被注释为component,那么spring就不会创建这个config的代理类,并且这个类中所有配置的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

共有1个答案

戎泰
2023-03-14

我会试着解释

如果将config注释为component,则spring不会创建此config的代理类

Spring container仅在需要时才为bean创建代理,比如为bean的任何特殊处理(如AOP、事务管理)创建代理。我已经为另一个SO问题解释了这一点,如果有兴趣,请浏览答案的A2部分。

该类中所有配置的bean都被视为普通方法调用

不正确。Lite模式下的所有自调用或内部方法调用都是普通方法调用,与使用@configuration注释的类中的特殊处理形成鲜明对比。在@configuration注释类中,对@bean注释方法的多次调用将返回同一个bean实例。

来自@bean的文档

是预期的原因

  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
    null

对于@configuration类的工作,@Kriegaex给出了一个很好的答案。一定要读。

希望这有帮助。

 类似资料:
  • 我想在Spring Boot应用程序的配置类中使用注释将定义为应用程序bean。 我正在调用我的应用流程中不同地方的4个rest服务。当前,我在每次请求时都创建。是否有一种方法可以使用将其定义为应用程序bean,并使用注入应用程序bean? 出现这个问题的主要原因是,我可以使用定义,但当我用注入它时,我会丢失所有已定义的拦截器(拦截器不会被调用。) 配置类 服务类别 看来我的在这种配置下根本没有被

  • 我对单元测试有问题。下面是示例代码片段。我模拟了一个bean,并将其注入@configuration类,然后使用mocked属性创建另一个bean。 在下面的示例中,如果我检查,b.getSomething()会返回默认值,如字符串为“”,int为0等。我不会得到模拟值。你知道怎么做吗?

  • 我正在创建JavaMailSender的bean类,并自动拥有javamailsender,但我得到错误 我不能为bean id="mail Sender"创建bean类。我在过去的两天里一直在努力,请让我离开它。 和错误页 组织。springframework。豆。工厂BeanCreationException:创建名为“employeeController”的bean时出错:自动连线依赖项的注

  • 问题内容: 我使用ektorp连接到CouchDB。 构建ektorp 实例的方法是使用构建器模式: 我对Spring比较陌生。请为我提供有关如何在上下文中配置以便通过进行创建的建议。 一种方法是使用。还有其他选择吗? 问题答案: 您可以尝试实现接口: 并添加到配置以下bean定义: 然后,您可以将此bean注入另一个bean,它将作为实例进行解析。

  • 我正在尝试使用Java配置从头开始构建基于spring的应用程序,但我得到了一个我完全不理解的警告。。。有人能告诉我哪里出了什么问题吗? 错误:警告:上下文初始化期间遇到异常-正在取消刷新尝试组织。springframework。豆。工厂BeanCreationException:创建名为“applicationContext”的bean时出错:bean实例化失败;嵌套异常为org。springf