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. 痞子衡嵌入式:在SBL项目实战中妙用i.MXRT1xxx里SystemReset不复位的GPR寄存器

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1xxx里SystemReset不复位的GPR寄存器的小妙用. 我们知道稍大规模的项目代码设计一般都是多人协作完成的,在项目 ...

  2. 云ERP真的已经玩不转了吗?

    欢迎关注微信公众号:sap_gui (ERP咨询顾问之家) 注:以下云ERP特指Saas ERP,非指ERP系统部署在云端. 不得不说,如今市场对传统ERP的接受度要远比云ERP高得多,95%的中大型 ...

  3. mybatis-plus 分页查询+ dao层抽象

    1.配置文件添加paginationInterceptor @Configuration @MapperScan("fama.cost.*.mapper") public clas ...

  4. Linux分区创建、挂载

    fdisk -l 这块盘是没有分区的,没有被使用. fdisk /dev/vdb 操作这块磁盘, 创建分区 格式化/dev/sdb1为ext4 mkfs -t ext4 /dev/vdb1 mkfs. ...

  5. NVIDIA Jarvis:一个GPU加速对话人工智能应用的框架

    NVIDIA Jarvis:一个GPU加速对话人工智能应用的框架 Introducing NVIDIA Jarvis: A Framework for GPU-Accelerated Conversa ...

  6. 2019个嵌入式市场研究,持续的C/C++优势

    2019个嵌入式市场研究,持续的C/C++优势 2019 Embedded Markets Study reflects emerging technologies, continued C/C++ ...

  7. 你,确定了解Java的String字符串?

    本文将描述JDK6中String.intern()是如何实现的,以及在JDK7和JDK8中对字符串池化技术做了哪些改变. String池化介绍 String池化就是把一些值相同,但是标识符不同的字符串 ...

  8. SpringBoot代码与jar包分离部署

    第一步,打出带有jar包的SpringBoot工程 首先配置pom.xml文件 <build> <finalName>demo</finalName> <pl ...

  9. top命令信息详解

    top详解 [root@localhost ~]# top top - 09:36:38 up 17:59, 3 users, load average: 0.00, 0.03, 0.00 Tasks ...

  10. 关于MySql数据库误操作数据找回的办法

    先讲个事,前段时间,系统长时间不用的一个功能被开放出来了,想当然的我没有在测试平台上测试,直接操作了正式系统(的确是我不严谨),导致好多数据异常,页面展示错乱了.于是我想到的第一个就是进行备份还原.项 ...