Full @Configurationlite @Bean mode 是 Spring Java Config 中两个非常有意思的概念。

先来看一下官方文档关于这两者的相关内容:

The @Bean methods in a regular Spring component are processed differently than their counterparts inside a Spring @Configuration class. The difference is that @Component classes are not enhanced with CGLIB to intercept the invocation of methods and fields. CGLIB proxying is the means by which invoking methods or fields within @Bean methods in @Configuration classes creates bean metadata references to collaborating objects. Such methods are not invoked with normal Java semantics but rather go through the container in order to provide the usual lifecycle management and proxying of Spring beans, even when referring to other beans through programmatic calls to @Bean methods. In contrast, invoking a method or field in a @Bean method within a plain @Component class has standard Java semantics, with no special CGLIB processing or other constraints applying.

机器翻译结果:常规Spring组件中的@Bean方法与Spring @Configuration类中的对应方法处理方式不同。不同之处在于,@Component类没有使用CGLIB增强来拦截方法和字段的调用。CGLIB代理是通过调用@Configuration类中的@Bean方法中的方法或字段来创建对协作对象的bean元数据引用的方法。这些方法不是用普通的Java语义调用的,而是通过容器来提供Spring bean通常的生命周期管理和代理,即使在通过对@Bean方法的编程调用引用其他bean时也是如此。相反,在普通@Component类中调用@Bean方法中的方法或字段具有标准的Java语义,不需要使用特殊的CGLIB处理或其他约束。

When @Bean methods are declared within classes that are not annotated with @Configuration, they are referred to as being processed in a “lite” mode. Bean methods declared in a @Component or even in a plain old class are considered to be “lite”, with a different primary purpose of the containing class and a @Bean method being a sort of bonus there. For example, service components may expose management views to the container through an additional @Bean method on each applicable component class. In such scenarios, @Bean methods are a general-purpose factory method mechanism. Unlike full @Configuration, lite @Bean methods cannot declare inter-bean dependencies. Instead, they operate on their containing component’s internal state and, optionally, on arguments that they may declare. Such a @Bean method should therefore not invoke other @Bean methods. Each such method is literally only a factory method for a particular bean reference, without any special runtime semantics. The positive side-effect here is that no CGLIB subclassing has to be applied at runtime, so there are no limitations in terms of class design (that is, the containing class may be final and so forth). In common scenarios, @Bean methods are to be declared within @Configuration classes, ensuring that “full” mode is always used and that cross-method references therefore get redirected to the container’s lifecycle management. This prevents the same @Bean method from accidentally being invoked through a regular Java call, which helps to reduce subtle bugs that can be hard to track down when operating in “lite” mode.

机器翻译:当@Bean方法在没有使用@Configuration注释的类中声明时,它们被称为在“lite”模式下处理。在@Component中声明的Bean方法,甚至在普通的旧类中声明的Bean方法,都被认为是“lite”,包含类的主要目的不同,而@Bean方法在这里是一种附加功能。例如,服务组件可以通过每个适用组件类上的附加@Bean方法向容器公开管理视图。在这种情况下,@Bean方法是一种通用的工厂方法机制。与完整的@Configuration不同,lite @Bean方法不能声明bean之间的依赖关系。相反,它们对包含它们的组件的内部状态进行操作,并可选地对它们可能声明的参数进行操作。因此,这样的@Bean方法不应该调用其他@Bean方法。每个这样的方法实际上只是一个特定bean引用的工厂方法,没有任何特殊的运行时语义。这里的积极副作用是在运行时不需要应用CGLIB子类,所以在类设计方面没有限制(也就是说,包含的类可能是final类,等等)。在常见的场景中,@Bean方法将在@Configuration类中声明,以确保始终使用“full”模式,并因此将交叉方法引用重定向到容器的生命周期管理。这可以防止通过常规Java调用意外调用相同的@Bean方法,这有助于减少在“lite”模式下操作时难以跟踪的细微bug。


相关定义

  • lite @Bean mode :当@Bean方法在没有使用@Configuration注解的类中声明时称之为lite @Bean mode
  • Full @Configuration:如果@Bean方法在使用@Configuration注解的类中声明时称之为Full @Configuration

有何区别

总结一句话,Full @Configuration中的@Bean方法会被CGLIB所代理,而 lite @Bean mode中的@Bean方法不会被CGLIB代理。

举个例子

有一普通Java类,现在分别使用Full @Configurationlite @Bean mode这两种模式注册到Spring容器中。

public class User {
public User() {
System.out.println("user create... hashCode :" + this.hashCode());
}
}

Full @Configuration

配置类:

@Configuration
public class AppConfig { @Bean
public User user() {
return new User();
} @Bean
public String name(User user) {
System.out.println(user.hashCode());
System.out.println(user().hashCode());
return "123";
}
}

主程序:

public class FullMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
User user = context.getBean(User.class);
System.out.println(user.hashCode());
context.close();
}
}

运行结果:

user create... hashCode :1709537756
1709537756
1709537756
1709537756

分析:@Bean是在使用了@Configuration注解的类上被声明的,属于Full @Configuration@Configuration类中的@Bean地方会被CGLIB进行代理。Spring会拦截该方法的执行,在默认单例情况下,容器中只有一个Bean,所以我们多次调用user()方法,获取的都是同一个对象。

注意:被CGLIB的方法是不能被声明为privatefinal,因为CGLIB是通过生成子类来实现代理的,privatefinal方法是不能被子类Override的,也就是说,Full @Configuration模式下,@Bean的方法是不能不能被声明为privatefinal,不然在启动时Spring会直接报错。

lite @Bean mode

配置类:

@Component
public class LiteAppConfig { @Bean
public User user() {
System.out.println("user() 方法执行");
return new User();
} @Bean
public String name(User user) {
System.out.println("name(User user) 方法执行");
System.out.println(user.hashCode());
System.out.println("再次调用user()方法: " + user().hashCode());
return "123";
}
}

主程序:

public class LiteMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LiteAppConfig.class);
User user = context.getBean(User.class);
System.out.println(user.hashCode());
context.close();
}
}

运行结果:

user() 方法执行
user create... hashCode :254413710
name(User user) 方法执行
254413710
user() 方法执行
user create... hashCode :1793329556
再次调用user()方法: 1793329556
254413710

分析:在lite @Bean mode模式下, @Bean方法不会被CGLIB代理,所以多次调用user()会生成多个user对象。

使用建议

为了防止出现一些奇怪的问题,建议都使用Full @Configuration


欢迎关注个人公众号:

你真的懂Spring Java Config 吗?Full @Configuration vs lite @Bean mode的更多相关文章

  1. spring java config 初探

    Java Config 注解 spring java config作为同xml配置形式的另一种表达形式,使用的场景越来越多,在新版本的spring boot中 大量使用,今天我们来看下用到的主要注解有 ...

  2. Spring面试底层原理的那些问题,你是不是真的懂Spring?

    1.什么是 Spring 框架?Spring 框架有哪些主要模块?Spring 框架是一个为 Java 应用程序的开发提供了综合.广泛的基础性支持的 Java 平台.Spring帮助开发者解决了开发中 ...

  3. spring java config配置搭建工程资料收集(网文)

    https://blog.csdn.net/poorcoder_/article/details/70231779 https://github.com/lovelyCoder/springsecur ...

  4. 终于搞懂Spring中Scope为Request和Session的Bean了

    之前只是很模糊的知道其意思,在request scope中,每个request创建一个新的bean,在session scope中,同一session中的bean都是一样的 但是不知道怎么用代码去验证 ...

  5. Spring boot添加配置类@Configuration并初始化@Bean,@Resource和@Autowired都为null

    大写加黑,找了好久@Resource和@Autowired都依赖不到创建的bean的原因:@Bean的方法名即是创建的Bean名称 import org.activiti.engine.Process ...

  6. Spring注解@Configuration和Java Config

    1.从Spring 3起,JavaConfig功能已经包含在Spring核心模块,它允许开发者将bean定义和在Spring配置XML文件到Java类中.但是,仍然允许使用经典的XML方式来定义bea ...

  7. 真懂Spring的@Configuration配置类?你可能自我感觉太良好

    当大潮退去,才知道谁在裸泳.关注公众号[BAT的乌托邦]开启专栏式学习,拒绝浅尝辄止.本文 https://www.yourbatman.cn 已收录,里面一并有Spring技术栈.MyBatis.中 ...

  8. Spring 4 and MyBatis Java Config

    TL;DR With the Java Config enhancements in Spring 4, you no longer need xml to configure MyBatis for ...

  9. Spring Security4实例(Java config版)——ajax登录,自定义验证

    本文源码请看这里 相关文章: Spring Security4实例(Java config 版) -- Remember-Me 首先添加起步依赖(如果不是springboot项目,自行切换为Sprin ...

随机推荐

  1. lightoj 1074 - Extended Traffic(spfa+负环判断)

    题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1074 题意:有n个城市,每一个城市有一个拥挤度ai,从一个城市I到另一个城市J ...

  2. happen before 原则

    并发一直都是程序开发者绕不开的难题,在上一篇文章中我们知道了导致并发问题的源头是 : 多核 CPU 缓存导致程序的可见性问题.多线程间切换带来的原子性问题以及编译优化带来的顺序性问题. 原子性问题我们 ...

  3. Nginx使用GeoIP模块来限制地区访问

    举例比如限制泰国地区的IP访问: 前提条件,安装了http geoip 或stream geoip模块的Nginx Plus或者开源nginx Maxmind的GeoLite Legacy数据库 1. ...

  4. Java ArrayList源码分析(有助于理解数据结构)

    arraylist源码分析 1.数组介绍 数组是数据结构中很基本的结构,很多编程语言都内置数组,类似于数据结构中的线性表 在java中当创建数组时会在内存中划分出一块连续的内存,然后当有数据进入的时候 ...

  5. javascript合并两个数组

    在开发的过程中,我们很多时候会遇到需要将两个数组合并成一个数组的情况出现. var arr1 = [1, 2, 3]; var arr2 = [4, 5, 6]; // 将arr1和arr2合并成为[ ...

  6. 自己在WEB学习过程中遇到的问题

    问题一: 下面这两段代码差别不大,为何test1结果不同: 代码1: public void doGet(HttpServletRequest request, HttpServletResponse ...

  7. 基于 HTML5 的 PID-进料系统可视化界面

    前言 随着工业物联网和互联网技术的普及和发展,人工填料的方式已经逐渐被机械设备取代.工业厂商减小误操作.提升设备安全以及追求高效率等制造特点对设备的要求愈加高标准.严要求.同时机械生产以后还需遵从整个 ...

  8. 最佳内存缓存框架Caffeine

    Caffeine是一种高性能的缓存库,是基于Java 8的最佳(最优)缓存框架. Cache(缓存),基于Google Guava,Caffeine提供一个内存缓存,大大改善了设计Guava's ca ...

  9. CF979C Kuro and Walking Route(简单的dfs/树形dp)

    题意:给出一个$n$个点,$n-1$条边的无向连通图,给出两个点$x,y$,经过$x$后的路径上就不能经过$y$,问可以走的路径$(u,v)$有多少条,($(u,v)$和$(v,u)$考虑为两条不同的 ...

  10. JAVA多线程高并发面试题总结

    ReadMe : 括号里的内容为补充或解释说明. 多线程和高并发是毕业后求职大厂面试中必问的知识点,自己之前总是面试前才去找相关的知识点面试题来背背,隔段时间又忘了,没有沉淀下来,于是自己总结了下相关 ...