SpringBoot框架学习笔记(二):容器功能相关注解详解

news2024/9/21 22:58:19

Spring 注入组件的注解

@Component、@Controller、 @Service、@Repository这些在 Spring 中的传统注解仍然有效,通过这些注解可以给容器注入组件 

2 @Configuration

2.1 应用实例

需求说明: 演示在 SpringBoot, 如何通过@Configuration 创建配置类来注入组件 

回顾传统方式如何通过配置文件注入组件 

(1)创建 com\springboot\bean\Monster.java

package com.springboot.bean;

public class Monster {

    private Integer id;
    private String name;
    private Integer age;
    private String skill;

    public Monster(Integer id, String name, Integer age, String skill) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.skill = skill;
    }

    public Monster() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getSkill() {
        return skill;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }

    @Override
    public String toString() {
        return "Monster{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", skill='" + skill + '\'' +
                '}';
    }
}

 (2)创建 src\main\resources\beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="monster03" class="com.springboot.bean.Monster">
        <property name="name" value="牛魔王~"></property>
        <property name="age" value="5000"></property>
        <property name="skill" value="芭蕉扇~"></property>
        <property name="id" value="1000"></property>
    </bean>
</beans>

(3)在主程序中进行测试

ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster monster = ioc.getBean("monster03", Monster.class);
System.out.println("monster=" + monster);

运行结果

使用 SpringBoot 的@Configuration 添加/注入组件 

(1)创建 src\main\java\com\springboot\config\BeanConfig.java 

package com.springboot.config;

import com.springboot.bean.Monster;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 1. @Configuration 标识这是一个配置类, 等价于配置文件
 * 2. 程序员可以通过@Bean 注解注入bean对象到容器
 * 3. 当一个类被 @Configuration 标识,该类-Bean 也会注入容器
 */
@Configuration
public class BeanConfig {

    /**
     * 1. @Bean : 给容器添加组件, 就是Monster bean
     * 2. monster01() : 默认方法名monster01 作为Bean的名字/id
     * 3. Monster : 注入类型, 注入bean的类型是Monster
     * 4. new Monster(200,"牛魔王",500,"疯魔拳") 注入到容器中具体的Bean信息
     * 5. @Bean(name = "monster_nmw") : 在配置、注入Bean指定名字/id monster_nmw
     * 6. 默认是单例注入
     * 7. 通过 @Scope("prototype")  这样设置就会让每次getBean()返回新的对象,即多例.
     */
    //@Bean(name = "monster_nmw")
    @Bean
    //@Scope("prototype")
    public Monster monster01() {
        return new Monster(200, "牛魔王", 500, "疯魔拳");
    }
    
}

(2)修改 MainApp.java , 从配置文件/容器获取 bean , 并完成测试

//启动springboot应用程序
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);

//===演示 @Configuration====
Monster monster01 = ioc.getBean("monster01", Monster.class);
Monster monster02 = ioc.getBean("monster01", Monster.class);

System.out.println("monster01--" + monster01 + " " + monster01.hashCode());
System.out.println("monster02--" + monster02 + " " + monster02.hashCode());

运行结果

成功注入容器,且两次返回的对象的哈希值相同,可知返回的是同一个对象,即单例 

2.2 @Configuration 注意事项和细节 

(1)配置类本身也是组件, 因此也可以获取

//===演示 配置类也会被注入容器 ====

BeanConfig bean = ioc.getBean(BeanConfig.class);
System.out.println("bean--" + bean);

(2)pringBoot2 新增特性: proxyBeanMethods 指定 Full 模式 和 Lite 模式

proxyBeanMethods:代理bean的方法 

  • proxyBeanMethods = true 表示Full模式,保证每个@Bean方法被调用多少次返回的组件都是单实例的, 是代理方式
  • proxyBeanMethods = false 表示Lite模式,每个@Bean方法被调用多少次返回的组件都是新创建的, 是非代理方式
  • 特别说明: proxyBeanMethods 是在 调用@Bean方法才生效,因此,需要先获取BeanConfig 组件,再调用方法。而不是直接通过 SpringBoot 主程序得到的容器来获取bean, 直接通过ioc.getBean() 获取Bean, proxyBeanMethods 值并没有生效
  • 如何选择: 组件依赖必须使用Full模式默认。如果不需要组件依赖使用 Lite模式。默认为 true
  • Lite模 也称为轻量级模式,因为不检测依赖关系,运行速度快 
// 指定Lite模式
@Configuration(proxyBeanMethods = false)
public class BeanConfig {

主程序测试

//===演示@Configuration(proxyBeanMethods = xxx) 

//1. 先得到BeanConfig组件
BeanConfig beanConfig = ioc.getBean(BeanConfig.class);
Monster monster_01 = beanConfig.monster01();
Monster monster_02 = beanConfig.monster01();
//
System.out.println("monster_01-" + monster_01 + " " + monster_01.hashCode());
System.out.println("monster_02-" + monster_02 + " " + monster_02.hashCode());


//直接通过ioc.getBean() 获取Bean, proxyBeanMethods 值并没有生效

Monster monster01 = ioc.getBean("monster01", Monster.class);
Monster monster02 = ioc.getBean("monster01", Monster.class);
System.out.println("monster01-" + monster01 + " " + monster01.hashCode());
System.out.println("monster02-" + monster02 + " " + monster02.hashCode());

运行结果

(3)配置类可以有多个, 就和 Spring 可以有多个 ioc 配置文件是一个道理。但是bean的id不能重复

@Import

通过查看@Import 源码可以了解,该注解可以通过指定一个 class类型的数组, 来注入指定类型的Bean

public @interface Import {
    Class<?>[] value();
}

通过@Import 方式注入的组件, 默认组件id就是对应类型的全类名

1.3.1 应用实例

需求说明: 演示在 SpringBoot, 如何通过 @Import 来注入组件

(1)创建 bean\Cat.java 和 bean\Dog.java 

package com.springboot.bean;

public class Cat {
}
package com.springboot.bean;

public class Dog {
}

(2)修改 BeanConfig.java 通过@Import 注入组件

// 这样配置即可将 Dog,Cat注入组件
// 默认id为com.springboot.bean.Dog 和 com.springboot.bean.Cat
@Import({Dog.class, Cat.class})

(3)修改 MainApp.java 完成测试

//===测试@Import 使用

Dog dogBean = ioc.getBean(Dog.class);
Cat catBean = ioc.getBean(Cat.class);
System.out.println("dogBean--" + dogBean);
System.out.println("catBean--" + catBean);

 运行结果

@Conditional 

4.1 @Conditional 介绍

(1)条件装配:满足 Conditional 指定的条件,则进行组件注入

(2)@Conditional 是一个根注解,下面有很多扩展注解 

4.2 应用实例

需求说明: 演示在 SpringBoot, 如何通过 @ConditionalOnBean 来注入组件,只有在容器中有 name = monster_nmw 的组件时,才注入 dog01

代码实现:

修改 BeanConfig.java , 加入@ConditionalOnBean 条件约束,并完成测试

@Bean
/**
 * 1. @ConditionalOnBean(name = "monster_nmw") 表示
 * 2. 当容器中有一个Bean , 名字是monster_nmw (类型不做约束), 就注入dog01这个Dog bean
 * 3. 如果没有 名字是monster_nmw Bean 就不注入dog01这个Dog bean
 * 4. @ConditionalOnMissingBean(name = "monster_nmw") 表示在容器中,
 * 没有 名字/id 为 monster_nmw 才注入dog01这个Bean
 * 5. @ConditionalOnBean(name = "monster_nmw") 也可以放在配置类上
 * 表示对该配置类的所有要注入的组件,都进行条件约束.
 */
@ConditionalOnBean(name = "monster_nmw")
//@ConditionalOnMissingBean(name = "monster_nmw")
public Dog dog01() {
    return new Dog();
}

特别说明:@ConditionalOnBean(name = "monster_nmw") 也可以放在配置类上,表示对该配置类的所有要注入的组件,都进行条件约束

主方法中加入测试

//===演示 @ConditionalOnBean 使用 start ====

Dog dog01 = ioc.getBean("dog01", Dog.class);
System.out.println("dog01--" + dog01);

运行结果

由运行结果可知,由于容器中没有 name = monster_nmw 的组件,所以 dog01 没有被注入容器

@ImportResource

作用:原生配置文件引入, 也就是可以直接导入 Spring 传统的 beans.xml ,可以认为是 SpringBoot 对 Spring 容器文件的兼容. 

5.1 @ImportResource 应用实例 

需求: 将 beans.xml 导入到 BeanConfig.java 配置类, 并测试是否可以获得 beans.xml 注入/配置的组件 。beans.xml 文件如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="monster03" class="com.springboot.bean.Monster">
        <property name="name" value="牛魔王~"></property>
        <property name="age" value="5000"></property>
        <property name="skill" value="芭蕉扇~"></property>
        <property name="id" value="1000"></property>
    </bean>
</beans>

(1)创建新的 BeanConfig3.java 来测试, 使用@ImportResource 导入 beans.xml

package com.springboot.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

@Configuration
//导入beans.xml - 就可以获取到beans.xml 中配置的bean
//可以简写为@ImportResource("classpath:beans.xml")
//可以同时导入多个配置文件,如下
//@ImportResource(locations = {"classpath:beans.xml","classpath:beans02.xml"})
@ImportResource(locations = "classpath:beans.xml")
public class BeanConfig3 {
}

(2)在 MainApp.java 测试

//演示@ImportResource 使用 start===

System.out.println("monster03 bean 是否存在-" + ioc.containsBean("monster03"));

运行结果

6 @ConfigurationProperties 配置绑定 

说明:使用 Java 读取到 SpringBoot 核心配置文件 application.properties 的内容, 并且把它封装到 JavaBean 中

6.1 应用实例

需求: application.properties 指定的 k-v JavaBean 绑定 

(1)在 application.properties 文件中指定k-v

#设置Furn的属性k-v
#前面的 furn01 是用于指定不同的绑定对象,这样可以在绑定Furn bean属性时
#通过 furn01 前缀进行区分
#furn01.id 中的 id 就是要绑定的 Furn bean的属性值
furn01.id=100
furn01.name=TV
furn01.price=1000.9

(2)创建 bean\furn.java,使用 @ConfigurationProperties 注解完成配置绑定

package com.springboot.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "furn01")
public class Furn {
    private Integer id;
    private String name;
    private Double price;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }
}

(3) controller/FurnController.java

package com.springboot.controller;

import com.springboot.bean.Furn;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;

@Controller
public class FurnController {
    // 装配到FurnController
    @Resource
    private Furn furn;

    @RequestMapping("/furn")
    @ResponseBody
    public Furn furn(){
        return furn;
    }
}

(4)启动SpringBoot主程序,在浏览器中输入网址 localhost:8080/furn,完成测试。效果如下

  

(5)特别说明,在 Furn 类上注销 @Component 并 在 BeanConfig.java( 也 可 以 是 其 它 配 置 类 ) 配 置 @EnableConfigurationProperties(Furn.class) 或 @Import( Furn.class), 效果一样

6.2 注意事项和细节

(1)如果 application.properties 有中文, 需要转成 unicode 编码写入, 否则出现乱码 

#设置属性 k-v
furn01.id=100
furn01.name=soft_chair\u6c99\u53d1!!
furn01.price=45678.9

(2)使用 @ConfigurationProperties(prefix = "furn01") 会提示如下信息, 但是不会影响使用

(3)解决 @ConfigurationProperties(prefix = "furn01") 提示信息, 在 pom.xml 增加以下依赖, 即可 

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1933084.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

少儿编程启蒙宝典:Scratch动画游戏108变

一、编程教育的时代价值与意义 随着数字时代的深入发展&#xff0c;社会对人才的需求正发生深刻变革&#xff0c;计算思维与编程能力已成为衡量个人竞争力的重要指标。在此背景下&#xff0c;培养孩子们运用计算思维解决实际问题的能力&#xff0c;成为教育领域的重要任务。编…

【PPT笔记】1-3节 | 默认设置/快捷键/合并形状

文章目录 说明笔记1 默认设置1.1 OFFICE版本选择1.1.1 Office某某数字专属系列1.1.2 Office3651.1.3 产品信息怎么看 1.2 默认设置1.2.1 暗夜模式1.2.2 无限撤回1.2.3 自动保存&#xff08;Office2013版本及以上&#xff09;1.2.4 图片压缩1.2.5 字体嵌入1.2.6 多格式导出1.2.7…

C++ | Leetcode C++题解之第235题二叉搜索树的最近公共祖先

题目&#xff1a; 题解&#xff1a; class Solution { public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {TreeNode* ancestor root;while (true) {if (p->val < ancestor->val && q->val < ancestor->val) {anc…

音视频开发入门教程(2)配置FFmpeg编译 ~共210节

在上一篇博客介绍了安装&#xff0c;音视频开发入门教程&#xff08;1&#xff09;如何安装FFmpeg&#xff1f;共210节-CSDN博客 感兴趣的小伙伴&#xff0c;可以继续跟着老铁&#xff0c;一起开始音视频剪辑功能&#xff0c;&#x1f604;首先查看一下自己的电脑是几核的&…

《昇思25天学习打卡营第20天|GAN图像生成》

生成对抗网络&#xff08;GAN&#xff09;是一种深度学习模型&#xff0c;用于生成逼真的图像。在手写数字识别的任务中&#xff0c;GAN 可以用来生成与真实手写数字相似的图像&#xff0c;以增强模型的训练数据集。GAN 主要由两个部分组成&#xff1a;生成器&#xff08;Gener…

httpx 的使用

httpx 是一个可以支持 HTTP/2.0 的库 还有一个是&#xff1a; hyper 库 这里有一个由HTTP/2.0的网站&#xff1a; https://spa16.scrape.center/ 使用 requests 库 进行爬取 import requests url https://spa16.scrape.center/ response requests.get(url) print(response…

Lua基础知识入门

1 基础知识 标识符&#xff1a;标识符的定义和 C语言相同&#xff1a;字母和下划线_ 开头&#xff0c; 下划线_ 大写字母一般是lua保留字&#xff0c; 如_VERSION 全局变量&#xff1a;默认情况下&#xff0c;变量总是认为是全局的&#xff0c;不需要申明&#xff0c;给一个变…

28_EfficientNetV2网络详解

V1&#xff1a;https://blog.csdn.net/qq_51605551/article/details/140487051?spm1001.2014.3001.5502 1.1 简介 EfficientNetV2是Google研究人员Mingxing Tan和Quoc V. Le等人在2021年提出的一种深度学习模型&#xff0c;它是EfficientNet系列的最新迭代&#xff0c;旨在提…

golang单元测试性能测试常见用法

关于go test的一些说明 golang安装后可以使用go test工具进行单元测试 代码片段对比的性能测试,使用起来还是比较方便,下面是一些应用场景 平时自己想做一些简单函数的单元测试&#xff0c;不用每次都新建一个main.go 然后go run main.go相对某个功能做下性能测试 看下cpu/内存…

Anthropic推出1亿美元AI基金,加剧与OpenAI的竞争|TodayAI

人工智能初创公司Anthropic和风险投资公司Menlo Ventures宣布&#xff0c;他们将共同推出一支价值1亿美元的基金&#xff0c;以支持早期初创公司并推动它们使用Anthropic的技术。这个名为Anthology Fund的新基金&#xff0c;将为初创公司提供资金和技术支持&#xff0c;旨在模仿…

三、GPIO口

我们在刚接触C语言时&#xff0c;写的第一个程序必定是hello world&#xff0c;其他的编程语言也是这样类似的代码是告诉我们进入了编程的世界&#xff0c;在单片机中也不例外&#xff0c;不过我们的传统就是点亮第一个LED灯&#xff0c;点亮电阻&#xff0c;电容的兄弟&#x…

锁策略和CAS指令

锁策略 一、锁策略的引入二、锁策略的分类&#xff08;1&#xff09;乐观锁和悲观锁&#xff08;2&#xff09;重量级锁和轻量级锁&#xff08;3&#xff09; 自旋锁和挂起等待锁&#xff08;4&#xff09;可重入锁和不可重入锁&#xff08;5&#xff09;公平锁和非公平锁&…

SQL面试题练习 —— 统计最大连续登录天数区间

目录 1 题目2 建表语句3 题解 1 题目 2 建表语句 CREATE TABLE IF NOT EXISTS user_login_tb (uid INT,login_date DATE ); insert into user_login_tb(uid, login_date) values( 1, 2022-08-02),(1, 2022-08-03),(2, 2022-08-03),(2, 2022-08-04),(2, 2022-08-05),(2, 2022-08…

使用Python的Turtle模块绘制小黄人

引言 在Python编程的世界里&#xff0c;turtle 模块是一个非常有趣且实用的工具&#xff0c;它允许程序员通过简单的指令控制一个虚拟的画笔&#xff08;称为“海龟”&#xff09;在屏幕上移动和绘制图形。本篇博客将详细介绍如何使用turtle模块来绘制一个卡通人物&#xff0c…

Redis-布隆过滤器(Bloom Filter)详解

文章目录 什么是布隆过滤器 布隆过滤器的优点&#xff1a;布隆过滤器的缺点&#xff1a;其他问题 布隆过滤器适合的场景布隆过滤器原理 数据结构增加元素查询元素删除元素 如何使用布隆过滤器 Google开源的Guava自带布隆过滤器Redis实现布隆过滤器 Redis中配置布隆过滤器Redis…

给Wordpress添加评分功能到评论表单

今天要 给你的 Wordpress 添加评分功能到评论表单 吗&#xff1f; 评分功能效果图 什么类型的网站需要评分&#xff1f; 资源站教程站其他&#xff0c;我也没想到。。。 但我这个网站&#xff0c;因为是电影类的网站&#xff0c;好像还是有点需要的&#xff0c;所以&#xf…

完美的用户体验:如何设计一个直观和有效的网站导航?

APP的顶部导航栏对我们来说很熟悉。导航栏是UI设计中不可或缺的一部分&#xff0c;几乎每个页面都使用导航栏。虽然导航栏看起来很简单&#xff0c;不需要太多精力&#xff0c;但是设计一个与产品需求和客户目标高度匹配的导航栏并不是那么容易的。导航栏的设计标准有很多细节需…

SpringBoot集成MQTT实现交互服务通信

引言 本文是springboot集成mqtt的一个实战案例。 gitee代码库地址&#xff1a;源码地址 一、什么是MQTT MQTT&#xff08;Message Queuing Telemetry Transport&#xff0c;消息队列遥测传输协议&#xff09;&#xff0c;是一种基于发布/订阅&#xff08;publish/subscribe&…

C++ : 移除链表元素/合并两个有序链表题解

目录 1.移除链表元素 分析 代码 2.合并两个有序链表 分析 代码 1.移除链表元素 分析 像这种移除元素的&#xff0c;加个哨兵位头节点会比较方便&#xff0c;因为旧的头会有被移除的情况&#xff0c;不好控制。这里只需要用cur指向待遍历的节点&#xff0c;prev指向cur的…

AI大牛Karpathy创办Eureka Labs专注AI+教育

&#x1f989; AI新闻 &#x1f680; AI大牛Karpathy创办Eureka Labs专注AI教育 摘要&#xff1a;前OpenAI大牛Karpathy离职半年后宣布创办专注AI与教育的公司Eureka Labs&#xff0c;旨在通过生成式AI优化教育体验。公司首个项目LLM101n课程已在GitHub获得高赞&#xff0c;目…