SpringDI自动装配BeanSpring注解配置和Java配置类

news2024/9/29 17:30:52

依赖注入

上篇博客已经提到了DI注入方式的构造器注入,下面采用set方式进行注入

基于set方法注入

public class User {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;
<bean id="address" class="com.yuqu.pojo.Address">
	<property name="addr" value="地址"/>
</bean>
<bean id="user" class="com.yuqu.pojo.User">
  <!--      1. 普通值注入  String类型  value -->
  <property name="name" value="远丘"/>
  <!--      2. Bean注入  ref  -->
  <property name="address" ref="address"/>
  <!--      3. 数组注入 ref  -->
  <property name="books">
    <array>
      <value>Java核心编程思想</value>
      <value>Java入门到实战</value>
      <value>Java进阶编程</value>
    </array>
  </property>
  <!--     4. list集合注入   -->
  <property name="hobbys">
    <list>
      <value>篮球</value>
      <value>音乐</value>
      <value>吉他</value>
    </list>
  </property>
  <!--     5. map集合注入   -->
  <property name="card">
    <map>
      <entry key="" value=""/>
      <entry key="" value=""/>
    </map>
  </property>
  <!--     6. Set集合注入 -->
  <property name="games">
    <set>
      <value>set1</value>
      <value>set2</value>
    </set>
  </property>
  <!--     7. null注入   -->
  <property name="wife">
    <null/>
  </property>
  <!--     8. Properties   -->
  <property name="info">
    <props>
      <prop key="driver">mysql-....</prop>
      <prop key="url">localhost://3306</prop>
      <prop key="username">root</prop>
      <prop key="password">123456</prop>
    </props>
  </property>
</bean>

最终可以成功执行,以上也是在正常开发中最经常使用的一些set注入语法格式。对构造器进行输出,可以发现采用Set注入方式时,程序最开始在映射bean的时候依然是走无参构造,创建对象之后使用各个属性的set方法为其赋值

public User() {
  System.out.println("无参构造");
}
// 输出
无参构造

Spring扩展配置注入

p-namespace

p-namespace允许使用bean元素属性直接为对象参数赋值,不需要额外的< properties >子元素标签

p-namespace就对应于set方法注入

Spring官网给出:Spring supports extensible configuration formats with namespaces, which are based on an XML Schema definition. The beans configuration format discussed in this chapter is defined in an XML Schema document. However, the p-namespace is not defined in an XSD file and exists only in the core of Spring

也就是说Spring支持基于XML配置文件中定义的具有命名空间的额外可扩展配置。就是需要用带有namespace的配置到xml头文件中。同时P-namespace在不定义的情况下,仅存在于Spring的核心中(就是不配不能用)

配置头文件p-namespace:xmlns:p="http://www.springframework.org/schema/p"

映射Bean时使用:

<bean id="person" class="com.yuqu.pojo.Person" p:name="人类" p:tel="13523025288"/>
<!-- 不使用p-namespace -->
<bean id="person" class="com.yuqu.pojo.Person">
  <property name="name" value="人类"/>
  <property name="tel" value="15632808079"/>
</bean>

c-namespace

c:constructor所以c-namespace对应于构造器注入
c-namespace扩展配置头文件:xmlns:c="http://www.springframework.org/schema/c"

<bean id="person" class="com.yuqu.pojo.Person" c:name="Mountain_think" c:tel="13434544324124"/>

也可以使用c_0或者c_1,数字代表构造器参数列表中参数的索引

使用c-namespace一定要添加含参构造,spring会自动检测class所对应的类中是否有含参构造,然后根据构造器的参数给出可以配置的属性名

Bean Scopes

Bean的作用域,是指将编写好的实体类映射到applicationContext.xml文件中之后的作用范围

查询官方文档可以了解到,在映射bean的过程中不仅可以定义各种依赖项和配置值,还可以自行控制每个Bean的作用区域,不用在Java当中设置。并且Spring支持六大作用域,但其中四个只有在WebMVC中才可以配置。除此之外还可以自行定义作用域

在这里插入图片描述

singleton

单例:(默认)将单个bean定义范围限定为每个SpringIoC容器的单个对象实例。

ApplicationContext context = new ClassPathXmlApplicationContext("application-Context.xml");
Person person = context.getBean("person", Person.class);
Person person1 = context.getBean("person",Person.class);
System.out.println(person==person1);
// 最终输出 true

可以发现在不进行显式设置的情况下,所映射好的bean在springIOC容器中都是单一实例
也可以显式定义:scope="singleton"

prototype

原型: 将单个bean定义范围限定为任意数量的对象实例。
也就是你每次调用getBean方法从IOC容器中获取到的实例都是一个新对象

<bean id="person" class="com.yuqu.pojo.Person"
      c:_0="Mountain_think" c:_1="13434544324124"
      <!-- 除了单例之外的其他作用域都需要显式定义 -->
      scope="prototype" 
      />
public static void main(String[] args) {
  ApplicationContext context = new ClassPathXmlApplicationContext("application-Context.xml");
  Person person = context.getBean("person", Person.class);
  Person person1 = context.getBean("person",Person.class);
  System.out.println(person==person1);
}
// 最终打印: false

其他都是智能在Web开发中使用的Only valid in the context of a web-aware Spring ApplicationContext.
比如:
request请求作用域:只在一次请求中有效
Session会话作用域:只在一次会话中有效
application全局作用域:在整个servlet中始终有效

自动装配Bean

先前提到的依赖注入都是采用在xml文件中由我们显式的去装备,但是Spring还提供了自动装配的机制
Spring会自动的在上下文中寻找,并自动装配Bean

ByName方式

ByName使用定义

<bean id="mom" class="com.mount.pojo.Mother"/>
<bean id="dady" class="com.mount.pojo.Father"/>
<bean id="person" class="com.mount.pojo.Person" autowire="byName">
  <property name="name" value="远丘"/>
</bean>

ByName的自动装配的原理就是:根据Bean中的set方法后缀来对应xml配置文件中的id名,比如setAge那么就会寻找id为age的bean
如上述代码所示,我们不需要在PersonBean中再去配置Father和Mother属性,只需要将这两个实体类映射到Bean中,Spring会帮助我们完成装配事情

使用ByName需要保证Bean的id全局唯一,并且id名要与set方法后缀字段一致(也就是与所属类中字段属性名一致)

ByType方式

ByType使用的定义格式就是将autowire="byName"换为autowire="byType"即可

<bean  class="com.mount.pojo.Mother"/>
<bean  class="com.mount.pojo.Father"/>
<bean id="person" class="com.mount.pojo.Person" autowire="byType" >
  <property name="name" value="远丘"/>
</bean>

根据byType自动装配原理就是spring会在上下文中寻找对应的对象类型,也就是说此时即便不为其他的实体类配置id,Spring也可以找到。
但是需要保证每一个实体类的全局唯一性,否则编译报错

注解自动装配Bean

使用前的配置

头文件信息配置,使用注解需要配置context的约束

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans               https://www.springframework.org/schema/beans/spring-beans.xsd 
<!-- 配置2 -->
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置3:开启注解的使用权限 -->
  <context:annotation-config/>

</beans>

@Autowired

可以在实体类中的属性前添注解@Autowired,那么只要这个属性对应的实体类在applicationContext中注册完毕,spring在装配Bean时就会自动的将添加了@Autowired注解的属性映射到具体的Bean中

public class Person {
  private String name;
  @Autowired
  private Father dady;
  @Autowired
  private Mother mom;

@Nullable 某个字段标记了该注解则表明该字段可以为null,当然也可以设置@Autowired实现该功能,打开Autowired的源码:

public @interface Autowired {
  boolean required() default true;
}

可以发现Autowired有一个参数required,默认为true表示该属性不能为null,也可以修改为false表示该属性可以为null

@Autowired(required = false)

那么通常我们在实体类中所定义的属性名需要与xml配置文件中bean的id一致,但是即便不一致。仍然可以通过注解来解决这个问题

@Qualifier提供了value参数,如果出现了bean的id与实体类属性名不一致的问题,我们可以通过@Qualifier注解将bean中的id映射到指定的实体类字段上
@Qualifier和@Autowired经常配套使用

就像这样:

@Autowired
@Qualifier(value = "momom")
private Mother mom;
<bean id="momom"  class="com.mount.pojo.Mother"/>

当然我们也可以忽略id,只保留class属性也可以运行

<bean  class="com.mount.pojo.Mother"/>
<bean  class="com.mount.pojo.Father"/>

@Resource

@Resource注解是Java的原生注解,就功能来讲比Spring所内置的注解更加强大。它集合了Spring的@Autowired和@Qualifier两个注解的特性。

不仅可以利用指定名称映射到bean的id,也可以通过类型映射。

public class Person {
  private String name;
  @Resource
  private Father dady;
  @Resource(name = "mommm")
  private Mother mom;

也可以配置@Resource要映射的实体类type

@Resource(type = Mother.class)

xml:

<bean id="mommm"  class="com.mount.pojo.Mother"/>
<bean  class="com.mount.pojo.Father"/>

两者都是用来自动装配bean使用的
@Autowired默认采用ByType方式实现,如果ByType找不到或者存在多个同类型bean就会根据属性名与Bean的id进行查找,当bean的id与属性名不一致时就可以添加注解@Qualifier进行映射字段名

而@Resource默认采用ByName方式,不指定name属性时,就会根据字段名去扫描bean中的id,找不到就会通过ByType方式扫描,再找不到就报错
此外我们可以直接再@Resource注解中配置name字段名属性和type类型名称

利用注解开发

我们不在需要将每个需要使用的类都利用xml配置注册到spring容器当中,只需要给特定层级的类添加对应注解即可。并且要开启spring注解的支持以及对包的扫描,扫描到了注解才能将该类成功注册为spring容器中的bean

<!--  扫描包 该包下的注解才会生效  -->
<context:component-scan base-package="com.mount.pojo"/>
<!--  注解支持  -->
<context:annotation-config/>

针对实体类POJO层,使用@Component注解将该类注册为bean
DAO层使用@Repository注解
Service层使用@service注解
Controller层使用@Controller注解
上述三个注解的作用一致,均为将其所修饰的类注册到Spring容器中,由spring同一管理bean

@Scope作用域:@Scope(scopeName = "singleton")
@Value:表示为当前所修饰的属性赋值。较简单的字段可以采取该方式,复杂一些的仍然要到xml文件中去配置

示例:

// pojo层
@Component
public class User {
// dao层
@Repository
public class UserDaoImpl implements UserDao{
// service层
@Service
public class UserService {
// controller层
@Controller
@Scope(scopeName = "singleton")
public class UserController {
// value使用
@Value("远丘")
private String name;
@Value("远丘")
public void setName(String name){this.name = name;}

但是即便如此,我们的spring注入配置还没有完全脱离配置文件

使用Java配置Spring

核心:Java配置类、不再需要applicationContext.xml配置文件
不再使用ClassPathXmlApplicationContext获取Spring的上下文来获取容器
更换为使用AnnotationConfigApplicationContext获取Spring容器

先来看配置类:

@Configuration  // 配置类  也会被spring容器托管
@ComponentScan("com.mountain.pojo")// 扫描包
public class MountConfig {

  // 注册一个bean 等同于xml中的一个bean标签
  // bean的id等同于方法名  bean的class属性等同于该方法的返回值
  @Bean
  public User getUser() {
    return new User();
  }

  @Bean
  public Bitch getBitch(){
    return new Bitch();
  }
}

@Configuration:表示该类为配置类,并且其本身也被@Component标注,也就是说该类同样会被Spring容器管理

@ComponentScan等同于<context:component-scan base-package="com.mountain"/>表示开启扫描,在该包下面所有的注解才能生效

@Bean等同于先前在xml文件中映射的某一个bean,该注解所修饰的方法名等于bean的id,返回值为bean的class属性

实体类:

@Component
public class User {
  @Value("be better")
  private String name;
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
}

测试类:

public void testDemo(){
  ApplicationContext context = new AnnotationConfigApplicationContext(MountConfig.class);
  User user = context.getBean("getUser", User.class);
  System.out.println(user.getName());
  Bitch bitch = context.getBean("getBitch", Bitch.class);
  System.out.println(bitch.getAge());
}

如果使用了配置类去做,那么只能通过ApplicationContext上下文来获取容器,其参数为被标记了@Configuration的配置类,生成对象context可以用于调用在配置类中被标记为@Bean的方法获取对象

Spring注解速查

@Autowired:用在属性上,表示自动装配该属性
@Qualifier:与Autowired配套使用,用于映射bean的id名称到类的属性上
@Nullable:表示该值可以未null
@Resource:Java原生的自动装配注解 带有name、type属性
@Component【pojo层】:组件、放在类上,表示这个类注入到Spring容器中,由spring管理
@value:可以放在属性上和set方法上,表示为这个属性赋值
等价于<property name="XXX" value="XXX"/>
@Component的衍生注解:

  1. @Respository 【Dao层】
  2. @Services【service层】
  3. @Controller 【controller层】

@Scope:作用域
@Import:引入其他配置类
@Configuration:表明该类为配置类
@ComponentSan:扫描包,被扫描包下的注解可生效
@Bean:等同于bean标签的配置

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

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

相关文章

【Linux】多线程编程 - 概念/pthread库调用接口/互斥

目录 一.线程概念 1.Linux中线程如何实现 2.POSIX线程库: pthread第三方线程库 3.线程与进程的数据存放问题 4.线程的"高效"具体体现在哪 5.线程优缺点 二.线程控制 0.关于pthread_t类型 1.线程创建 2.线程终止 3.线程等待 4.线程分离 5.代码验证 三.线…

你期待已久的《动手学深度学习》(PyTorch版)来啦!

《动手学深度学习》全新PyTorch版本&#xff0c;李沐和亚马逊科学家阿斯顿张等大咖作者强强联合之作&#xff0c;机器学习、深度学习领域重磅教程&#xff0c;交互式实战环境&#xff0c;配套资源丰富&#xff01; 面向中文读者的能运行、可讨论的深度学习入门书。 动手学深度…

一个优质软件测试工程师简历的范文(一定要收藏)

很多刚转行软件测试的小伙伴是不是不知道怎么写好一份优质的软件测试工程师的简历。今天呢&#xff0c;就给大家分享一下一个优质软件测试工程师简历的范文。记得收藏起来哦。 下面的案例&#xff1a;2-3年的软件测试工程的简历 姓 名&#xff1a;XXX 学历&#xff1a…

2023备战金三银四,Python自动化软件测试面试宝典合集(五)

接上篇八、抓包与网络协议8.1 抓包工具怎么用 我原来的公司对于抓包这块&#xff0c;在 App 的测试用得比较多。我们会使用 fiddler 抓取数据检查结果&#xff0c;定位问题&#xff0c;测试安全&#xff0c;制造弱网环境;如&#xff1a;抓取数据通过查看请求数据&#xff0c;请…

FPGA实现不同分辨率视频切换输出,串口协议帧控制,提供工程源码和技术支持

目录1、不同分辨率视频切换输出原理2、设计思想和架构详解3、vivado工程详解4、上板调试验证并演示5、福利&#xff1a;工程代码的获取1、不同分辨率视频切换输出原理 不同分辨率的视频输出对应不同的时序和时钟&#xff0c;一般情况下是不存在同时或分时输出的&#xff0c;但…

结构体变量

C语言允许用户自己建立由不同类型数据组成的组合型的数据结构&#xff0c;它称为结构体&#xff08;structre&#xff09;。 在程序中建立一个结构体类型&#xff1a; 1.结构体 建立结构体 struct Student { int num; //学号为整型 char name[20]; //姓名为字符串 char se…

基于spring boot +opencv 实现车牌识别、人脸识别、证件识别等功能 附完整代码 毕业设计

界面展示: 这是一个基于spring boot + opencv 实现的项目贯穿样本处理、模型训练、图像处理、对象检测、对象识别等技术点以学习交流为目的&

装满杯子需要的最短总时长-力扣2335-java双百方案

一、题目描述 现有一台饮水机&#xff0c;可以制备冷水、温水和热水。每秒钟&#xff0c;可以装满 2 杯 不同 类型的水或者 1 杯任意类型的水。 给你一个下标从 0 开始、长度为 3 的整数数组 amount &#xff0c;其中 amount[0]、amount[1] 和 amount[2] 分别表示需要装满冷水…

用Javascript对二维数组DIY按汉语拼音的排序方法

继续编写“圳品”信息系统&#xff0c;将“圳品”信息读取到JavaScript定义的一个二维数组中进行处理和显示&#xff1a;var p [[100, "都安县丙公司", "产品ab", 5, 25, 10],[50, "南丹县a公司", "产品a", 5, 25, 10],[30, "罗…

力扣sql简单篇练习(十五)

力扣sql简单篇练习(十五) 1 直线上的最近距离 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 SELECT min(abs(p1.x-p2.x)) shortest FROM point p1 INNER JOIN point p2 ON p1.x <>p2.x1.3 运行截图 2 只出现一次的最大数字 2.1 题目内容 2…

教你如何用Python分析出选注双色球号码

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 又到了学Python时刻~ 数据集介绍 找从19年到现在的开奖历史数据&#xff0c;我们首先要把这个历史数据拿到&#xff0c; 拿到我们再进行做分析&#xff0c;分析每个号码出现的频率是多少&#xff0c; 哪个多&#x…

Java零基础教程——控制语句

目录程序流程控制顺序结构分支结构if分支语句案例&#xff1a;switch分支案例&#xff1a;循环结构for循环while循环do-while循环跳转控制语句程序流程控制 顺序结构 没什么好说的就是&#xff1a;程序默认执行流程(如下) public class Test {public static void main(String…

spring中bean的生命周期(简单5步)

目录 一、概念 1.生命是bean的生命周期&#xff1f; 2.知道bean生命周期的意义&#xff1f; 3.bean的生命周期按照粗略的五步 二、例子讲解 一、概念 1.生命是bean的生命周期&#xff1f; 答&#xff1a;spring其实就是管理bean对象的工厂&#xff0c;它负责对象的创建&…

[K8S]Kubernetes环境检测与API简介

文章目录环境判断docker环境检测K8S环境检测获取POD的NamespaceAPI Server概述API访问命令行方式编程方式REST API是Kubernetes系统的重要部分&#xff0c;组件之间的所有操作和通信均由API Server处理的REST API调用。环境判断 在使用API时&#xff0c;需要先判断是否是K8S环…

实施ITIL项目的十个参考步骤

ITIL是我们做好IT服务管理流程建设与治理的一个重要知识库&#xff0c;这个知识体系的内容非常丰富&#xff0c;做到全面领会并运用自如是比较困难的。因此&#xff0c;我们提供了这样的一份实施ITIL项目的参考步骤&#xff0c;在新建或治理企业IT管理流程时可以适当借鉴&#…

elasticsearch索引与搜索初步

ES支持cURL交互&#xff0c;使用http请求完成索引和搜索操作&#xff0c;最基本的格式如下&#xff1a;创建索引我们可以使用PUT方法创建索引&#xff0c;通过指定“索引”、“类型”、“文档ID”锁定文档&#xff0c;通过参数指定文档的数据。红色部分的路由分别指定了“索引”…

Homekit智能家居DIY一智能插座

WiFi智能插座对于新手接触智能家居产品更加友好&#xff0c;不需要额外购买网关设备 很多智能小配件也给我们得生活带来极大的便捷&#xff0c;智能插座就是其中之一&#xff0c;比如外出忘记关空调&#xff0c;可以拿起手机远程关闭。 简单说就是&#xff1a;插座可以连接wi…

【博客618】docker容器重启后读写层数据并不丢失的原理

docker容器重启后读写层数据并不丢失的原理 1、场景 当我们对docker容器执行restart后&#xff0c;其实容器中原本读写层里对临时数据还在。只有我们删除了这个容器&#xff0c;重新创建的容器是基于镜像的只读层然后挂载上新的空的读写层&#xff0c;此时临时数据是不在的 2、…

详解指针(2)(初阶版)

前言&#xff1a;内容包括&#xff1a;指针运算&#xff0c;指针和数组&#xff0c;二级指针&#xff0c;指针数组 详解指针&#xff08;1&#xff09;&#xff08;点击即跳转&#xff09; part 1&#xff1a;指针运算 1 指针-整数 以如下代码为例&#xff1a;初始化数组内容…

实验名称:经典同步问题:生成者与消费者问题

实验名称&#xff1a;经典同步问题&#xff1a;生成者与消费者问题 相关知识 信号量 信号量是用来协调不同进程间的数据对象&#xff0c;可用来保护共享资源&#xff0c;也能用来实现进程间及同一进程不同线程间的进程同步。分为二值信号灯和计算信号灯两种类型。 进程与线…