为什么我的配置 class 没有用 @Configurable 和 @ComponentScan 注释而不初始化 bean 两次?
Why isn't my config class annotated with @Configurable and @ComponentScan not initializing beans twice?
我读过
"The fact that @Configuration classes are @Components also means that your @Configuration classes are picked up automatically if you have component scanning enabled on the package that contains them. This can have both intended and unintended consequences. If your @Configuration class enables component scanning on the same package it resides in, your beans could be instantiated twice, which isn’t good."(威廉姆斯 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 (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
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
实际上,如果我用 spring 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
所以我猜,我有正确的想法作者试图传达,但如果我没有,如果有人能向我展示一个可能导致 Williams 评论到的问题的演示程序,我将非常感激表面。
这个问题不存在了。
作为证明 - 查看 @SpringBootApplication
来自 Spring Boot 的注释。它本质上是 @Configuration
和 @ComponentScan
在与 class 本身相同的包中的组合(加上一些其他与这里无关的东西)。
我读过
"The fact that @Configuration classes are @Components also means that your @Configuration classes are picked up automatically if you have component scanning enabled on the package that contains them. This can have both intended and unintended consequences. If your @Configuration class enables component scanning on the same package it resides in, your beans could be instantiated twice, which isn’t good."(威廉姆斯 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 (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
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
实际上,如果我用 spring 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
所以我猜,我有正确的想法作者试图传达,但如果我没有,如果有人能向我展示一个可能导致 Williams 评论到的问题的演示程序,我将非常感激表面。
这个问题不存在了。
作为证明 - 查看 @SpringBootApplication
来自 Spring Boot 的注释。它本质上是 @Configuration
和 @ComponentScan
在与 class 本身相同的包中的组合(加上一些其他与这里无关的东西)。