来自Spring 5文档
当@bean方法在未使用@configuration注释的类中声明时,它们被称为以'lite'模式处理。在@组件中,甚至在普通的旧类中声明的Bean方法将被视为“lite”,包含类的主要目的不同,而@Bean方法只是一种额外的好处。例如,服务组件可能通过每个适用的组件类上的附加@bean方法向容器公开管理视图。在这样的场景中,@bean方法是一种简单的通用工厂方法机制。
与full@configuration不同,lite@bean方法不能声明bean间依赖关系。相反,它们对包含组件的内部状态进行操作,并可选地对它们可能声明的参数进行操作。因此,这样的@bean方法不应该调用其他@bean方法;每个这样的方法实际上只是一个特定bean引用的工厂方法,没有任何特殊的运行时语义。这里的积极副作用是在运行时不需要应用CGLIB子类,因此在类设计方面没有限制(即包含类可能是最终类等)。
常规Spring组件中的@bean方法的处理方式不同于Spring@Configuration类中的对应方法。不同的是,@Component类没有用CGLIB增强以拦截方法和字段的调用。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
所以对我来说,lite 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");
}
}
编辑:
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");
}
}
}
> Creating MyComponentBean2
> Creating MyComponentBean2
> Creating MyConfigrationBean2
这不是窃听器。Spring的lite bean定义会在组件扫描期间自动添加到上下文中。使用工厂方法的Bean定义(即,所有@Bean
定义的Bean)将自动尝试使用当前上下文自动连接参数。有关更多详细信息,请参阅ConstructorResolver#InstantiateUsingFactoryMethod
。
所引用的文档可能并不完全清楚。“lite”和“full”bean配置之间的主要区别严格地说是在“full”(@configuration
)模式下完成的代理。例如,如果我们在@configuration
类中定义bean会发生什么:
@Configuration
public MyConfiguration {
@Bean
public Bean1 bean1() {
return new Bean1(bean2());
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
从bean1()
内调用bean2()
实际上将从上下文引用单个bean2
实例,而不是直接调用已实现的bean2()
方法。实际上,从该配置类中进行多少bean2()
方法调用并不重要--真正的bean2
方法将只执行一次。
“lite”模式不代理这些方法,这意味着每个bean2()
方法调用实际上将直接引用方法实现,而不会html" target="_blank">返回上下文中的bean。相反,它将创建一个不被上下文跟踪的新的单独实例(这是默认的Java行为)。
Spring 4:https://docs.Spring.io/autorepo/docs/Spring/4.2.4.release/javadoc-api/org/springframework/web/context/request/requestattributes.html#scope_global_session Spring 5:https://docs.Spring.io/autor
完整@Configuration vs“lite”@Bean模式?在Spring文档中,他们提到了不带@Configuration注释类的@Bean注释方法。有谁能帮我得到一个完美的例子,它在哪里有用(在那种情况下)? https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-标准注释(概
我知道从中调用带注释的方法,前面已经讨论过了。 但是我不明白为什么当bean被覆盖时它就不起作用了。 我有一个遗留类,我不能修改。它是一个配置,同时也是一个业务bean。这是一个简化版本: 现在,调用返回而不是。 当配置被删除并且测试上下文的配置被设置为时,一切都能正常工作(结果为)。 在测试中注册bean有什么不同?
我创建了spring boot 2.0演示应用程序,其中包含两个使用WebClient进行通信的应用程序。当我从WebClient的响应中使用Flux的block()方法时,它们经常停止通信。由于某些原因,我想使用列表而不是通量。 服务器端应用程序是这样的。它只返回Flux对象。 而客户端(或BFF端)应用程序是这样的。我从服务器获取Flux,并通过调用block()方法将其转换为List。 虽然
本文向大家介绍详解Spring中Bean的加载的方法,包括了详解Spring中Bean的加载的方法的使用技巧和注意事项,需要的朋友参考一下 之前写过bean的解析,这篇来讲讲bean的加载,加载要比bean的解析复杂些,从之前的例子开始. Spring中加载一个bean的方式: 来看看getBean(String name)方法源码, 该getBean(String name)方法位于Abstra
问题内容: 我注意到一种奇怪的行为,我不确定这是设计使然还是我自己的误解。Spring将在以ComponentScan标记的@ Service,@ Component等注释的Bean中实现@Lookup方法,但不会在@Configuration类(Application.java)中定义的@Bean中实现这种方法。 这不是什么大问题,因为我可以从配置中删除@Bean定义,而直接对其类进行注释。但我