Почему мой класс конфигурации не аннотирован @Configurable, а @ComponentScan не инициализирует bean-компоненты дважды? - PullRequest
0 голосов
/ 06 мая 2018

Я прочитал это

"Тот факт, что классы @Configuration являются @Components, также означает, что ваши классы @Configuration выбираются автоматически, если у вас включено сканирование компонентов в пакете, который их содержит. Это может иметь как предполагаемые, так и непреднамеренные последствия. Если ваша @Configuration класс включает сканирование компонентов в том же пакете, в котором он находится, ваши компоненты могут быть созданы дважды, что нехорошо. "(Уильямс 346)

Я не уверен, что автор пытался донести, так как не было никаких конкретных примеров, и после целого дня размышлений самым близким, что я мог попытаться решить эту проблему, был код ниже, который для меня прекрасно работает без инициализация любых bean-компонентов (либо через тег @Bean), либо через тег @Component, дважды.

Обратите внимание, что объектный код одинаков для bean-компонента X, а также каждый отдельный метод вызывается только один раз, включая конструктор.

package com.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

public class ConfigurationCSTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        System.out.println(context.getBean("config"));
        context.registerShutdownHook();
    }
}

@Configuration
@ComponentScan(basePackages = "com")
class Config {
     public Config() {
       System.out.println("called once");
    }

    @Bean
    public Object x() {
        final Object o = new Object();
        System.out.println("now creating bean " + o + " only called once");
        return o;
    }

    public String toString() {
        return "I am also a component";
    }
}

@Component
class ComponentY {
    @Autowired
    public ComponentY(Object x) {
        System.out.println("now printing bean " + x);
    }
}

и результат запуска main

called once
now creating bean java.lang.Object@290222c1 only called once
now printing bean java.lang.Object@290222c1
I am also a component

Тем не менее, я получаю сообщение об ошибке, которое похоже на то, что Spring сделал эту проблему исправленной к Spring

сказано

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.springframework.cglib.core.ReflectUtils$1 (file:/home/someuser/.m2/repository/org/springframework/spring-core/5.0.2.RELEASE/spring-core-5.0.2.RELEASE.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
WARNING: Please consider reporting this to the maintainers of org.springframework.cglib.core.ReflectUtils$1
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

И на самом деле, если я попробую это с пружиной 3.2.9.RELEASE, она будет отклонена с

May 06, 2018 3:44:12 PM org.springframework.beans.factory.support.DefaultListableBeanFactory destroySingletons
INFO: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6f96c77: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,config,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component class: file [/home/someuser/dev/repl/target/classes/com/spring/Config.class]; nested exception is org.springframework.core.NestedIOException: ASM ClassReader failed to parse class file - probably due to a new Java class file version that isn't supported yet: file [/home/someuser/dev/repl/target/classes/com/spring/Config.class]; nested exception is java.lang.IllegalArgumentException
    at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(ClassPathScanningCandidateComponentProvider.java:290)
    at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:242)
    at org.springframework.context.annotation.ComponentScanAnnotationParser.parse(ComponentScanAnnotationParser.java:130)
    at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:189)
    at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:164)
    at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:139)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:284)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:225)
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:630)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:461)
    at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:73)
    at com.spring.ConfigurationCSTest.main(ConfigurationCSTest.java:12)
Caused by: org.springframework.core.NestedIOException: ASM ClassReader failed to parse class file - probably due to a new Java class file version that isn't supported yet: file [/home/someuser/dev/repl/target/classes/com/spring/Config.class]; nested exception is java.lang.IllegalArgumentException
    at org.springframework.core.type.classreading.SimpleMetadataReader.<init>(SimpleMetadataReader.java:56)
    at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:80)
    at org.springframework.core.type.classreading.CachingMetadataReaderFactory.getMetadataReader(CachingMetadataReaderFactory.java:102)
    at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(ClassPathScanningCandidateComponentProvider.java:266)
    ... 11 more
Caused by: java.lang.IllegalArgumentException
    at org.springframework.asm.ClassReader.<init>(Unknown Source)
    at org.springframework.asm.ClassReader.<init>(Unknown Source)
    at org.springframework.asm.ClassReader.<init>(Unknown Source)
    at org.springframework.core.type.classreading.SimpleMetadataReader.<init>(SimpleMetadataReader.java:53)
    ... 14 more

Так что я думаю, у меня была правильная идея, которую автор пытался донести, но если бы я этого не сделал, я был бы очень признателен, если бы кто-нибудь показал мне демонстрационную программу, которая может вызвать проблему, которую Уильямс прокомментировал на поверхность.

1 Ответ

0 голосов
/ 06 мая 2018

Эта проблема больше не существует.

В качестве доказательства - посмотрите аннотацию @SpringBootApplication от Spring Boot. По сути, это комбинация @Configuration и @ComponentScan в том же пакете, что и сам класс (плюс несколько других вещей, не относящихся к делу).

...