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);
}
}
}

效果显示:

单实例问题:

  1. 判断组件在容器中是否为单实例:
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注解的使用的更多相关文章

  1. SpringBoot启动流程分析(五):SpringBoot自动装配原理实现

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  2. springboot自动装配原理,写一个自己的start

    springboot自动装配原理 第一次使用springboot的时候,都感觉很神奇.只要加入一个maven的依赖,写几行配置,就能注入redisTemple,rabbitmqTemple等对象. 这 ...

  3. SpringBoot自动装配原理解析

    本文包含:SpringBoot的自动配置原理及如何自定义SpringBootStar等 我们知道,在使用SpringBoot的时候,我们只需要如下方式即可直接启动一个Web程序: @SpringBoo ...

  4. SpringBoot | 2.1 SpringBoot自动装配原理

    @ 目录 前言 1. 引入配置文件与配置绑定 @ImportResource @ConfigurationProperties 1.1 @ConfigurationProperties + @Enab ...

  5. springboot自动装配原理回顾、配置文件分析

    配置文件 spring boot官方文档 官方外部配置文件说明参考文档 自动配置原理分析 1. SpringBoot启动的时候加载主配置类,开启了自动配置功能@EnableAutoConfigurat ...

  6. springboot自动装配原理

    最近开始学习spring源码,看各种文章的时候看到了springboot自动装配实现原理.用自己的话简单概括下. 首先打开一个基本的springboot项目,点进去@SpringBootApplica ...

  7. 【Springboot】Springboot自动装配原理

    1.核心注解就是 EnableAutoConfiguration  该注解会激活SpringBoot的自动装配功能: 代码如下: @Target(ElementType.TYPE) @Retentio ...

  8. SpringBoot 自动装配原理

    早期的Spring项目需要添加需要配置繁琐的xml,比如MVC.事务.数据库连接等繁琐的配置.Spring Boot的出现就无需这些繁琐的配置,因为Spring Boot基于约定大于配置的理念,在项目 ...

  9. SpringBoot:带你认认真真梳理一遍自动装配原理

    前言 Spring翻译为中文是“春天”,的确,在某段时间内,它给Java开发人员带来过春天,但是随着我们项目规模的扩大,Spring需要配置的地方就越来越多,夸张点说,“配置两小时,Coding五分钟 ...

随机推荐

  1. IDEA debug ConcurrentLinkedQueue时抽风

    1. 介绍 如标题所见,我在使用IDEA debug ConcurrentLinkedQueue的Offer方法时,发生了下面的情况. 代码如下: ConcurrentLinkedQueue<s ...

  2. win10家庭中文版CUDA+CUDNN+显卡GPU使用tensorflow-gpu训练模型安装过程(精华帖汇总+重新修改多次复现)

    查看安装包 pip list 本帖提供操作过程,具体操作网上有好多了,不赘述.红色字体为后来复现出现的问题以及批注 题外话: (1)python 的环境尽量保持干净,尽量单一,否则容易把自己搞晕,不知 ...

  3. MindSpore图像分类模型支持(Lite)

    MindSpore图像分类模型支持(Lite) 图像分类介绍 图像分类模型可以预测图片中出现哪些物体,识别出图片中出现物体列表及其概率. 比如下图经过模型推理的分类结果为下表: 类别 概率 plant ...

  4. Turing渲染着色器网格技术分析

    Turing渲染着色器网格技术分析 图灵体系结构通过使用 网格着色器 引入了一种新的可编程几何着色管道.新的着色器将计算编程模型引入到图形管道中,因为协同使用线程在芯片上直接生成紧凑网格( meshl ...

  5. win10下abd环境配置

    一.下载安装 Android SDK 下载地址: http://tools.android-studio.org/index.php/sdk 下载完成后进行解压至D盘根目录下,也可以自定义英文路径下 ...

  6. 深入理解java虚拟机笔记Chapter8

    运行时栈帧结构 栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈(Virtual Machine Stack)的栈元素.栈帧存储了方法 ...

  7. springboot的restful风格获取请求中携带的参数

    http://localhost:8080/emp/1 有以上请求,我们controller要怎么获取请求中传递的参数1呢? 通过PathVariable注解,如下: @DeleteMapping(& ...

  8. springboot——发送put、delete请求

    在springmvc中我们要发送put和delete请求,需要先配置一个过滤器HiddenHttpMethodFilter,而springboot中,已经帮我们自动配置了,所以我们可以不用配置这个过滤 ...

  9. Java Shutdown Hook 场景使用和源码分析

    我是陈皮,一个在互联网 Coding 的 ITer,微信搜索「陈皮的JavaLib」第一时间阅读最新文章,回复[资料],即可获得我精心整理的技术资料,电子书籍,一线大厂面试资料和优秀简历模板. 背景 ...

  10. 【题解】【洛谷 P1967】 货车运输

    目录 洛谷 P1967 货车运输 原题 题解 思路 代码 洛谷 P1967 货车运输 原题 题面请查看洛谷 P1967 货车运输. 题解 思路 根据题面,假设我们有一个普通的图: 作图工具:Graph ...