如果在未使用@Configuration注释的类中声明@Bean方法,则将它们称为在“精简”模式下进行处理。在@Component或什至在简单的旧类中声明的Bean方法将被视为“精简版”,其包含类的主要目的有所不同,而@Bean方法只是其中的一种奖励。例如,服务组件可以通过每个适用组件类上的其他@Bean方法将管理视图公开给容器。在这种情况下,@ Bean方法是一种简单的通用工厂方法机制。
与完整的@Configuration不同,lite @Bean方法无法声明Bean间的依赖关系。相反,它们对包含组件的内部状态以及可能声明的自变量进行操作。因此,这样的@Bean方法不应调用其他@Bean方法。每个这样的方法实际上只是用于特定bean引用的工厂方法,而没有任何特殊的运行时语义。这里的积极副作用是,不必在运行时应用CGLIB子类,因此在类设计方面没有任何限制(即,包含类仍然可以是最终类,等等)。
常规Spring组件中的@Bean方法的处理方式与Spring @Configuration类中的@Bean方法不同。不同之处在于,使用CGLIB不能增强@Component类,以拦截方法和字段的调用。CGLIB代理是一种调用@Configuration类中@Bean方法中的方法或字段的方法,以创建Bean元数据引用来协作对象。这样的方法不是用普通的Java语义调用的,而是经过容器以提供通常的生命周期管理和Spring bean的代理,即使通过@Bean方法的编程调用引用其他bean时也是如此。 相反,在普通@Component类内的@Bean方法中调用方法或字段具有标准Java语义,而无需特殊的CGLIB处理或其他约束。
我希望下面的代码抛出异常/ bean1.bean2为null,并且不会执行init方法。但是,以下代码可以正常运行并显示:
Should never be invoked
Expected null but is ch.litebeans.Bean2@402bba4f
Run Code Online (Sandbox Code Playgroud)
因此,对我而言,精简bean的行为与从@Configuration注释类构造的bean相同。有人可以指出在哪种情况下不是这种情况吗?
。
package ch.litebeans;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationConfig.class);
Bean1 bean1 = ctx.getBean(Bean1.class);
System.out.println("Expected null but is " + bean1.getBean2());
}
}
package ch.litebeans;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = {"ch.litebeans"})
public class ApplicationConfig {}
package ch.litebeans;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class Factory1 {
@Bean
public Bean1 getBean1(Bean2 bean2){
return new Bean1(bean2);
}
}
package ch.litebeans;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class Factory2 {
@Bean(initMethod = "init")
public Bean2 getBean2(){
return new Bean2();
}
}
package ch.litebeans;
public class Bean1 {
private Bean2 bean2;
public Bean1(Bean2 bean2){
this.bean2 = bean2;
}
public Bean2 getBean2(){
return bean2;
}
}
package ch.litebeans;
public class Bean2 {
public void init(){
System.out.println("Should never be invoked");
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:
基于对Mike Hill的解释,我添加了一个示例来说明差异:
public class BeanLiteRunner {
public static void main(String[] args) {
AnnotationConfigApplicationContext acac = new AnnotationConfigApplicationContext(MyComponent.class,
MyConfiguration.class);
MyComponent.MyComponentBean1 componentBean1 = acac.getBean(MyComponent.MyComponentBean1.class);
MyComponent.MyComponentBean1 componentBean2 = acac.getBean(MyComponent.MyComponentBean1.class);
MyConfiguration.MyConfigurationBean1 configurationBean1 = acac.getBean(MyConfiguration
.MyConfigurationBean1.class);
MyConfiguration.MyConfigurationBean1 configurationBean2 = acac.getBean(MyConfiguration
.MyConfigurationBean1.class);
}
}
@Component
public class MyComponent {
@Bean
public MyComponent.MyComponentBean1 getMyComponentBean1(){
return new MyComponent.MyComponentBean1(getMyComponentBean2());
}
@Bean
public MyComponent.MyComponentBean2 getMyComponentBean2(){
return new MyComponent.MyComponentBean2();
}
public static class MyComponentBean1{
public MyComponentBean1(MyComponent.MyComponentBean2 myComponentBean2){
}
}
public static class MyComponentBean2{
public MyComponentBean2(){
System.out.println("Creating MyComponentBean2");
}
}
}
@Configuration
public class MyConfiguration {
@Bean
public MyConfigurationBean1 getMyConfigurationBean1(){
return new MyConfigurationBean1(getMyConfigrationBean2());
}
@Bean
public MyConfigurationBean2 getMyConfigrationBean2(){
return new MyConfigurationBean2();
}
public static class MyConfigurationBean1{
public MyConfigurationBean1(MyConfigurationBean2 myConfigurationBean2){}
}
public static class MyConfigurationBean2{
public MyConfigurationBean2(){
System.out.println("Creating MyConfigrationBean2");
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出符合预期
> Creating MyComponentBean2
> Creating MyComponentBean2
> Creating MyConfigrationBean2
Run Code Online (Sandbox Code Playgroud)
Mik*_*ill 18
这不是一个错误。在组件扫描期间,Spring 的 lite bean 定义会自动添加到上下文中。使用工厂方法的 Bean 定义(即所有@Bean定义的 Bean)将自动尝试使用当前上下文自动装配参数。有关ConstructorResolver#instantiateUsingFactoryMethod更多详细信息,请参阅。
引用的文档可能并不完全清楚。“精简”和“完整”bean 配置之间的主要区别严格来说是在“完整”( @Configuration) 模式下完成的代理。举个例子,如果我们在一个@Configuration类中定义我们的 bean 会发生什么:
@Configuration
public MyConfiguration {
@Bean
public Bean1 bean1() {
return new Bean1(bean2());
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
Run Code Online (Sandbox Code Playgroud)
bean2()从内部调用bean1()实际上将引用上下文中的单例 bean2实例,而不是直接调用已bean2()实现的方法。事实上,bean2()从那个配置类中调用多少方法并不重要——真正的bean2方法只会被执行一次。
“Lite”模式不代理这些方法,这意味着每个bean2()方法调用实际上将直接引用方法实现,并且不会返回上下文中的 bean。相反,它将创建一个不受上下文跟踪的新的单独实例(这是默认的 Java 行为)。
| 归档时间: |
|
| 查看次数: |
715 次 |
| 最近记录: |