SpringBoot自动装配原理之Configuration以及@Bean注解的使用
Configuration以及Bean注解的使用
该知识点在Spring中应该学过,没有学过或者遗忘的的朋友需要预习或温习前置知识点。SpringBoot其实就是Spring的进一步简化,所以前置知识点还是有必要的学习的,这样更能明白其底层的原理。
好了,废话不多说,开始!
结构目录:

pojo--User:
package com.xbhog.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class User {
private String name;
private int age;
}
config-MyConfig:
package com.xbhog.config;
import com.xbhog.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig {
@Bean
public User user(){
return new User("xbhog",18);
}
}
controller-Mycontroller:
package com.xbhog.controller;
import com.xbhog.config.MyConfig;
import com.xbhog.pojo.User;
import org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Mycontroller {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
User user = context.getBean("user", User.class);
System.out.println(user.toString());
}
}
前面这三个文件埋了一个坑,使用SpringBoot启动的话是找不到Bean的,因为我们必须把文件放到与主启动程序同一目录下,这样才能找到,可以这样:这是由于SpringBootApplication的扫描路径决定的


但是当我们把Myapp放入主程序文件夹时:发现并没有找到相应的组件信息

在不改变原来的程序的情况下,我们可以使用手动扫描的方式,设置自定义扫名路径:
package com.xbhog.springboot1times;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
//@SpringBootApplication
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.xbhog") //设置扫描路径
public class Myapp {
public static void main(String[] args) {
/*1. 返回我们IOC容器*/
ConfigurableApplicationContext run = SpringApplication.run(Myapp.class, args);
/*2.查看容器里面的组件*/
String[] names = run.getBeanDefinitionNames();
for(String name:names){
System.out.println(name);
}
}
}
效果显示:

单实例问题:
- 判断组件在容器中是否为单实例:
package com.xbhog.springboot1times;
import com.xbhog.pojo.Pet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
//@SpringBootApplication
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.xbhog")
public class Myapp {
public static void main(String[] args) {
/*1. 返回我们IOC容器*/
ConfigurableApplicationContext run = SpringApplication.run(Myapp.class, args);
/*2.从容器中获取组件*/
Pet tom1 = run.getBean("tom11", Pet.class);
Pet tom2 = run.getBean("tom11", Pet.class);
System.out.println("组件是否为单实例:"+(tom1== tom2));
}
}
组件是否为单实例:true
Myconfig调用问题:
因为配置类也属于组件,如果我们获取配置类组件后,通过实例化对象在调用其中的bean,是调用普通方法呢,还是调用容器中的相应的组件?
package com.xbhog.springboot1times;
import com.xbhog.config.MyConfig;
import com.xbhog.pojo.Pet;
import com.xbhog.pojo.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
//@SpringBootApplication
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.xbhog")
public class Myapp {
public static void main(String[] args) {
/*1. 返回我们IOC容器*/
ConfigurableApplicationContext run = SpringApplication.run(Myapp.class, args);
/*2.查看容器里面的组件*/
String[] names = run.getBeanDefinitionNames();
for(String name:names){
System.out.println(name);
}
/*3.从容器中获取组件*/
Pet tom1 = run.getBean("tom11", Pet.class);
Pet tom2 = run.getBean("tom11", Pet.class);
System.out.println("组件是否为单实例:"+(tom1== tom2));
MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean);
User user1 = bean.user();
User user2 = bean.user();
System.out.println("测试通过Myconfig类调用的user组件:"+(user1==user2));
}
}
效果如下:
组件是否为单实例:true
com.xbhog.config.MyConfig EnhancerBySpringCGLIB 9b1ae7c2@6c0905f6
测试通过Myconfig类调用的user组件:true
上面的效果也就是Configuration(proxyBeanMethods=true)的作用,保证每个@Bean方法被调用多少次返回的组件都是单实例的

实际上就是proxyBeanMethods:代理bean的方法(true),外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象,也叫:FULL模式.
当proxyBeanMethods=true时:
MyConfig返回的Bean本身就是代理对象,CGLIB,并且测试通过Myconfig类调用的user组件:true.
com.xbhog.config.MyConfig EnhancerBySpringCGLIB 9b1ae7c2@6c0905f6
MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean);
//如果@Configuration(proxyBeanMethods = true)代理对象调用方法。
// SpringBoot总会检查这个组件是否在容器中有。
User user1 = bean.user();
User user2 = bean.user();
System.out.println("测试通过Myconfig类调用的user组件:"+(user1==user2));
当:proxyBeanMethods=false时(Lite模式-轻量级):
MyCnfig返回的就不是代理模式,测试通过Myconfig类调用的user组件:false
总结:
proxyBeanMethods:代理bean的方法 ;
- Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的】
- Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的】
- 组件依赖必须使用Full模式默认。其他默认是否Lite模式
使用场景:
现在向pojo.User中添加Pet对象:
package com.xbhog.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class User {
private String name;
private int age;
private Pet pet;
}
在proxyBeanMethods=true模式下才是正确的;
package com.xbhog.config;
import com.xbhog.pojo.Pet;
import com.xbhog.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration //告诉SpringBoot这是一个配置类 == application.xml
public class MyConfig {
@Bean //给容器添加组件,以方法名作为组件的id,返回类型就是组件类型。返回的值,就是组件在容器中的实例
public User user(){
User user = new User("xbhog", 18);
//user组件依赖与Pet组件,用户中的宠物与容器中的宠物时一样的
user.setPet(tomcat());
return user;
}
@Bean("tom11") //设置bean别名--》id的名字
public Pet tomcat(){
return new Pet("tomcat");
}
}
User user = run.getBean("user", User.class);
Pet tom3 = run.getBean("tom11", Pet.class);
System.out.println("用户的宠物"+(user.getPet() == tom3));
用户的宠物true;
在proxyBeanMethods=false模式后,就不会扫描容器,直接创建对象:
组件是否为单实例:true
com.xbhog.config.MyConfig@330c1f61
测试通过Myconfig类调用的user组件:false
用户的宠物false
如果你看到这里或者正好对你有所帮助,希望能点个关注或者推荐,感谢;
有错误的地方,欢迎在评论指出,作者看到会进行修改。
SpringBoot自动装配原理之Configuration以及@Bean注解的使用的更多相关文章
- SpringBoot启动流程分析(五):SpringBoot自动装配原理实现
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- springboot自动装配原理,写一个自己的start
springboot自动装配原理 第一次使用springboot的时候,都感觉很神奇.只要加入一个maven的依赖,写几行配置,就能注入redisTemple,rabbitmqTemple等对象. 这 ...
- SpringBoot自动装配原理解析
本文包含:SpringBoot的自动配置原理及如何自定义SpringBootStar等 我们知道,在使用SpringBoot的时候,我们只需要如下方式即可直接启动一个Web程序: @SpringBoo ...
- SpringBoot | 2.1 SpringBoot自动装配原理
@ 目录 前言 1. 引入配置文件与配置绑定 @ImportResource @ConfigurationProperties 1.1 @ConfigurationProperties + @Enab ...
- springboot自动装配原理回顾、配置文件分析
配置文件 spring boot官方文档 官方外部配置文件说明参考文档 自动配置原理分析 1. SpringBoot启动的时候加载主配置类,开启了自动配置功能@EnableAutoConfigurat ...
- springboot自动装配原理
最近开始学习spring源码,看各种文章的时候看到了springboot自动装配实现原理.用自己的话简单概括下. 首先打开一个基本的springboot项目,点进去@SpringBootApplica ...
- 【Springboot】Springboot自动装配原理
1.核心注解就是 EnableAutoConfiguration 该注解会激活SpringBoot的自动装配功能: 代码如下: @Target(ElementType.TYPE) @Retentio ...
- SpringBoot 自动装配原理
早期的Spring项目需要添加需要配置繁琐的xml,比如MVC.事务.数据库连接等繁琐的配置.Spring Boot的出现就无需这些繁琐的配置,因为Spring Boot基于约定大于配置的理念,在项目 ...
- SpringBoot:带你认认真真梳理一遍自动装配原理
前言 Spring翻译为中文是“春天”,的确,在某段时间内,它给Java开发人员带来过春天,但是随着我们项目规模的扩大,Spring需要配置的地方就越来越多,夸张点说,“配置两小时,Coding五分钟 ...
随机推荐
- properties模板
jdbc.driver=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/ssmdemo1?useSSL=true&useUn ...
- LR: GLU-Net: Global-Local Universal Network for Dense Flow and Correspondences
Abstract 在图像中简历稠密匹配是很重要的任务, 包括 几何匹配,光流,语义匹配. 但是这些应用有很大的挑战: 大的平移, 像素精度, 外观变化: 当前是用特定的网络架构来解决一个单一问题. 我 ...
- 使用Jprofiler分析Java项目的内存开销情况并利用强制回收控制内存
一.问题背景 自己开发的Java项目中占用太多的Heap Space.即使在Eclipse的虚拟机参数中设置"-Xms128m -Xms2048m -XX:MetaspaceSize=512 ...
- FinFET与2nm晶圆工艺壁垒
FinFET与2nm晶圆工艺壁垒 谈到半导体工艺尺寸的时候,通常对于下面的一串数字耳熟能详:3um.2um.1.5um.1um.0.8um.0.5um.0.35um.0.25um.0.18um.0.1 ...
- 07:mysql的unknown variable ‘xxxxx’
简单说明一下: 可能有的找不到配置文件的,不要慌,这个时候 你可能以前安装了多个版本的mysql 就是说你以前是mysql5,现在换成了mysql8, 矮!! 你可能发现你的mysql8里面没有配置文 ...
- TopN算法,流式数据获取前N条数据
背景:由于业务需求,用户想要统计每周,每月,几个月,一年之中的前N条数据. 根据已有的思路无非就是对全部的数据进行排序,然后取出前N条数据,可是这样的话按照目前最优的排序算法复杂度也在O(nlog(n ...
- 十亿级流量下,我与Redis时延小突刺的战斗史
一.背景 某一日收到上游调用方的反馈,提供的某一个Dubbo接口,每天在固定的时间点被短时间熔断,抛出的异常信息为提供方dubbo线程池被耗尽.当前dubbo接口日请求量18亿次,报错请求94W/天, ...
- noip2010 总结
机器翻译 题目背景 小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章. 题目描述 这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换.对于每个英文单词 ...
- 『无为则无心』Python基础 — 5、Python开发工具的安装与使用
目录 1.Pycharm下载 2.Pycharm安装 3.PyCharm界面介绍 4.基本使用 (1)新建Python项目 (2)编写Python代码 (3)执行代码查看结果 (4)设置PyCharm ...
- Mybatis学习01:利用mybatis查询数据库
通过mybatis来操作mysql数据库的步骤大致可分为以下几步: 在这里,我们以对下面这个这个表格进行操作为例: 表名:ssm 1 配置依赖 在pom.xml中添加所需要的的依赖 <!-- m ...