Spring Proxy Создание классов, аннотированных @Configuration или @Component - PullRequest
2 голосов
/ 17 июня 2019

Spring использует динамические прокси JDK или CGLIB для создания прокси для данного целевого объекта.Если класс аннотирован @Configuration, тогда используется CGLIB.

Однако одно из ограничений Spring AOP состоит в том, что, как только вызов наконец достигнет целевого объекта, любые вызовы методов, которые он может совершить для себя, будут вызываться для ссылки this, а не для прокси.Эту информацию важно помнить при использовании @Transactional и в других местах.

Итак, имея эти знания в приведенном ниже коде, Spring вводит фактический экземпляр или прокси-сервер SimpleBean?

@Configuration
public class Config {

@Bean
public SimpleBean simpleBean() {
    return new SimpleBean();
}

@Bean
public SimpleBeanConsumer simpleBeanConsumer() {
    return new SimpleBeanConsumer(simpleBean()); //<---
}
}

А каково поведение, если класс имеет аннотацию с @Component?

1 Ответ

1 голос
/ 17 июня 2019

Позвольте мне дать вам другую перспективу.

Скажем, есть еще один компонент AnotherBeanConsumer, которому также требуется simpleBean.Simple Bean имеет область действия Singleton :

 @Configuration
 public class Config {
    @Bean
    public SimpleBean simpleBean() {
       return new SimpleBean();
    }

    @Bean
    public SimpleBeanConsumer simpleBeanConsumer() {
       return new SimpleBeanConsumer(simpleBean());
    }

    @Bean
    public AnotherBeanConsumer anotherBeanConsumer() {
       return new AnotherBeanConsumer(simpleBean());
    }        
 }

Теперь вопрос состоит в том, как возможно, что два вызова simpleBean(), сделанные из различных методов simpleBeanConsumer и anotherBeanConsumer, возвращаюттот же самый экземпляр простого бина (поскольку он, очевидно, является синглтоном)?

IMO (и отказ от ответственности, я не связан с Spring или чем-то подобным), это главная причина создания прокси, которые обертывают конфигурации.

Теперь, действительно, у Spring AOP есть ограничение вызова методов, как вы и заявили, однако кто сказал, что подпружиненный Spring использует AOP пружины?Инструментарий байт-кода, выполняемый на гораздо более низких уровнях, не имеет таких ограничений.В конце концов, создание прокси означает: «создайте прокси-объект, который будет иметь тот же интерфейс, но изменит поведение», верно?

Например, если вы используете CGLIB, который использует наследование, вы можете создать прокси из конфигурацииэто выглядит примерно так (схематично):

class CGLIB_GENERATED_PROXY extends Config {

     private Map<String, Object> singletonBeans;

     public SimpleBean simpleBean() {
         String name = getNameFromMethodNameMaybePrecached();
         if(singletonBeans.get(name) != null) {
            return singletonBeans.get(name);
         }  
         else {
            SimpleBean bean = super.simpleBean(); 
            singletonBeans.put(name, bean);
            return bean;    
         }
     }
     ....
}

Конечно, это всего лишь схематическое изображение, в реальной жизни есть контекст приложения, который в основном обеспечивает такой доступ к карте, но вы понимаете, в чем дело.

Если этого недостаточно, то существуют еще более сложные фреймворки, которые пружина должна использовать для загрузки конфигурации (например, ASM) ...

Вот пример: есливы используете @ConditionalOnClass(A.class) и класс на самом деле не существует во время выполнения, как Spring может загрузить байт-код конфигурации, которая использует эту конфигурацию, и не дать сбой чему-то вроде NoClassDefFoundException?

Я хочу сказать, что онвыходит далеко за пределы весеннего АОП и имеет свои причуды:)

Сказав это, ничего из того, что я описал выше, не требуетРеальные компоненты должны быть всегда в прокси любого вида.Таким образом, в самом тривиальном случае, когда SimpleBean сам по себе не имеет некоторых аннотаций, требующих генерации прокси (например, @Cached, @Transactional и т. Д.), Spring не будет переносить объект этого типа, и вы 'получите простой SimpleBean объект.

...