Как конфигурация режима бобов создает прокси на бинах - PullRequest
0 голосов
/ 21 марта 2020

Я читаю часть spring do c о режиме @Bean Lite здесь Как я понимаю, если config помечен как компонент, то spring не создает прокси-класс этой конфигурации и все настроенные bean-компоненты внутри этого класса обрабатываются как простые вызовы методов. Однако, согласно этому примеру, Spring создал прокси для bean-компонента, аннотированного как @ Transactional и настроенного внутри @ 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() {

        }
    }
}

Вывод:

Conf
TranslatorApplication$ProxyBean$$EnhancerBySpringCGLIB$$f4c1a493

Это означает, что ProxyBean - это прокси, созданный CGLIB. Вопрос в том, что если класс конфигурации не является прокси, то как Spring создал прокси для метода public ProxyBean bean()? Версия Spring Boot - 2.1.6

1 Ответ

1 голос
/ 22 марта 2020

Я попытаюсь объяснить

, если конфиг помечен как компонент, то Spring не создает прокси-класс этого конфига

Контейнер Spring создает прокси для бина только если это требуется, как для любой специальной обработки для компонента, например: AOP, Transaction Management. Я объяснил это для другого SO вопроса здесь , пожалуйста, go через раздел A2 ответа, если вы заинтересованы.

Так, например, компонент класса Conf будет прокси, если класс аннотирован @Transactional.

все сконфигурированные компоненты внутри этого класса рассматриваются как простой метод звонки

Не правильно. Все самостоятельные вызовы или внутренние вызовы методов в режиме Lite являются простыми вызовами методов в отличие от специальной обработки внутри класса, помеченного @Configuration. В аннотированном классе @Configuration несколько вызовов аннотированного метода @Bean возвращают один и тот же экземпляр компонента.

Из документации @ Bean

В отличие от семантики для методов bean-компонентов в классах @Configuration, «ссылки между компонентами» не поддерживаются в облегченном режиме. Вместо этого, когда один @ Bean-метод вызывает другой @ Bean-метод в облегченном режиме, это стандартный вызов метода Java; Spring не перехватывает вызов через прокси-сервер CGLIB. Это аналогично вызовам метода inter-@Transactional, когда в режиме прокси Spring не перехватывает вызов - Spring делает это только в режиме AspectJ.

Итак, наблюдение, что

Spring создал прокси для bean-компонента, аннотированного как @Transactional и настроенного внутри класса @Component

, как и ожидалось по причинам

  1. Класс, аннотированный @Transactional, нуждается в проксировании
  2. Класс, помеченный @Component, в этом примере не требует специальной обработки

Я изменил ваш пример, чтобы объяснить это лучше

Заметные изменения

  1. Аннотируемый @Component аннотированный класс с @Transactional для объяснения проксирования.
  2. Добавление класса @Configuration для объяснения поддержки 'межбиновых ссылок'
  3. Нет @Transactional для 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

Обратите внимание, что

  1. ComponentConf bean-компонент прокси.
  2. ComponentBean r Возврат двух разных экземпляров бина из-за режима Lite .
  3. ConfigurationBean возвращает один и тот же экземпляр.
  4. ConfigurationBean экземпляры не проксируются.

Отличный ответ от @kriegaex о работе класса @Configuration. Читайте.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...