zoukankan      html  css  js  c++  java
  • Spring 中提供了 3 种方法进行beand装配

    而在 Spring 中提供了 3 种方法进行配置:

    • 在 XML 文件中显式配置
    • 在 Java 的接口和类中实现配置
    • 隐式 Bean 的发现机制和自动装配原则

    通过 XML 配置装配 Bean

    使用 XML 装配 Bean 需要定义对应的 XML,这里需要引入对应的 XML 模式(XSD)文件,这些文件会定义配置 Spring Bean 的一些元素,当我们在 IDEA 中创建 XML 文件时,会有友好的提示:

    一个简单的 XML 配置文件如下:

     这就只是一个格式文件,引入了一个 beans 的定义,引入了 xsd 文件,它是一个根元素,这样它所定义的元素将可以定义对应的 Spring Bean

    装配简易值

    先来一个最简单的装配:

    简单解释一下:

    • id 属性是 Spring 能找到当前 Bean 的一个依赖的编号,遵守 XML 语法的 ID 唯一性约束。必须以字母开头,可以使用字母、数字、连字符、下划线、句号、冒号不能以 / 开头
      不过 id 属性不是一个必需的属性name 属性也可以定义 bean 元素的名称,能以逗号或空格隔开起多个别名,并且可以使用很多的特殊字符,比如在 Spring 和 Spring MVC 的整合中,就得使用 name 属性来定义 bean 的名称,并且使用 / 开头。

    注意: 从 Spring 3.1 开始,id 属性也可以是 String 类型了,也就是说 id 属性也可以使用 / 开头,而 bean 元素的 id 的唯一性由容器负责检查。
    如果 id 和 name 属性都没有声明的话,那么 Spring 将会采用 “全限定名#{number}” 的格式生成编号例如这里,如果没有声明 “id="c"” 的话,那么 Spring 为其生成的编号就是 “pojo.Category#0”,当它第二次声明没有 id 属性的 Bean 时,编号就是 “pojo.Category#1”,以此类推。

    • class 属性显然就是一个类的全限定名
    • property 元素是定义类的属性,其中的 name 属性定义的是属性的名称,而 value 是它的值

    这样的定义很简单,但是有时候需要注入一些自定义的类,比如之前饮品店的例子,JuickMaker 需要用户提供原料信息才能完成 juice 的制作:

    这里先定义了一个 name 为 source 的 Bean,然后再制造器中通过 ref 属性去引用对应的 Bean,而 source 正是之前定义的 Bean 的 name ,这样就可以相互引用了。

    • 注入对象使用 ref 属性

    装配集合

    有些时候我们需要装配一些复杂的东西,比如 Set、Map、List、Array 和 Properties 等,为此我们在 Packge【pojo】下新建一个 ComplexAssembly 类:

     开始装配复杂的类型

     

     

    • 装配复杂数据类型的总结:

    • List 属性为对应的 <list> 元素进行装配,然后通过多个 <value> 元素设值
    • Map 属性为对应的 <map> 元素进行装配,然后通过多个 <entry> 元素设值,只是 entry 包含一个键值对(key-value)的设置
    • Properties 属性为对应的 <properties> 元素进行装配,通过多个 <property> 元素设值,只是 properties 元素有一个必填属性 key ,然后可以设置值
    • Set 属性为对应的 <set> 元素进行装配,然后通过多个 <value> 元素设值
    • 对于数组而言,可以使用 <array> 设置值,然后通过多个 <value> 元素设值。

    上面看到了对简单 String 类型的各个集合的装载,但是有些时候可能需要更为复杂的装载,比如一个 List 可以是一个系列类的对象,为此需要定义注入的相关信息,其实跟上面的配置没什么两样,只不过加入了 ref 这一个属性而已:

    集合注入总结:

    List 属性使用 <list> 元素定义注入,使用多个 <ref> 元素的 Bean 属性去引用之前定义好的 Bean

     Map 属性使用 <map> 元素定义注入,使用多个 <entry> 元素的 key-ref 属性去引用之前定义好的 Bean 作为键,而用 value-ref 属性引用之前定义好的 Bean 作为值

     Set 属性使用 <set> 元素定义注入,使用多个 <ref> 元素的 bean 去引用之前定义好的 Bean

    通过注解装配 Bean

    上面,我们已经了解了如何使用 XML 的方式去装配 Bean,但是更多的时候已经不再推荐使用 XML 的方式去装配 Bean,更多的时候会考虑使用注解(annotation) 的方式去装配 Bean。

    • 优势:

    1.可以减少 XML 的配置,当配置项多的时候,臃肿难以维护
    2.功能更加强大,既能实现 XML 的功能,也提供了自动装配的功能,采用了自动装配后,程序猿所需要做的决断就少了,更加有利于对程序的开发,这就是“约定由于配置”的开发原则

    在 Spring 中,它提供了两种方式来让 Spring IoC 容器发现 bean

    • 组件扫描:通过定义资源的方式,让 Spring IoC 容器扫描对应的包,从而把 bean 装配进来。
    • 自动装配:通过注解定义,使得一些依赖关系可以通过注解完成。

    使用@Compoent 装配 Bean

    我们把之前创建的 Student 类改一下:

    解释一下

    • @Component注解:
      示 Spring IoC 会把这个类扫描成一个 bean 实例,而其中的 value 属性代表这个类在 Spring 中的 id,这就相当于在 XML 中定义的 Bean 的 id:<bean id="student1" class="pojo.Student" />,也可以简写成 @Component("student1"),甚至直接写成 @Component ,对于不写的,Spring IoC 容器就默认以类名来命名作为 id,只不过首字母小写,配置到容器中
    • @Value注解:
      表示值的注入,跟在 XML 中写 value 属性是一样的。

    这样我们就声明好了我们要创建的一个 Bean,就像在 XML 中写下了这样一句话:

     但是现在我们声明了这个类,并不能进行任何的测试,因为 Spring IoC 并不知道这个 Bean 的存在,这个时候我们可以使用一个 StudentConfig 类去告诉 Spring IoC :

    这个类十分简单,没有任何逻辑,但是需要说明两点:

    • 该类和 Student 类位于同一包名下
    • @ComponentScan注解:
      代表进行扫描,默认是扫描当前包的路径,扫描所有带有 @Component 注解的 POJO。

    这样一来,我们就可以通过 Spring 定义好的 Spring IoC 容器的实现类——AnnotationConfigApplicationContext 去生成 IoC 容器了:

     这里可以看到使用了 AnnotationConfigApplicationContext 类去初始化 Spring IoC 容器它的配置项是 StudentConfig 类,这样 Spring IoC 就会根据注解的配置去解析对应的资源,来生成 IoC 容器了。

    • 明显的弊端:
    • 对于 @ComponentScan 注解,它只是扫描所在包的 Java 类,但是更多的时候我们希望的是可以扫描我们指定的类
    • 上面的例子只是注入了一些简单的值,测试发现,通过 @Value 注解并不能注入对象

    自动装配——@Autowired

    上面提到的两个弊端之一就是没有办法注入对象,通过自动装配我们将解决这个问题

    所谓自动装配技术是一种由 Spring 自己发现对应的 Bean,自动完成装配工作的方式,它会应用到一个十分常用的注解 @Autowired 上,这个时候 Spring 会根据类型去寻找定义的 Bean 然后将其注入,听起来很神奇,让我们实际来看一看:

    1.先在 Package【service】下创建一个 StudentService 接口:

     2.为上面的接口创建一个 StudentServiceImp 实现类:

     该实现类实现了接口的 printStudentInfo() 方法,打印出成员对象 student 的相关信息,这里的 @Autowired 注解,表示在 Spring IoC 定位所有的 Bean 后,这个字段需要按类型注入,这样 IoC 容器就会寻找资源,然后将其注入。

    • 再次理解: @Autowired 注解表示在 Spring IoC 定位所有的 Bean 后,再根据类型寻找资源,然后将其注入。
    • 过程: 定义 Bean ——》 初始化 Bean(扫描) ——》 根据属性需要从 Spring IoC 容器中搜寻满足要求的 Bean ——》 满足要求则注入
    • 问题: IoC 容器可能会寻找失败,此时会抛出异常(默认情况下,Spring IoC 容器会认为一定要找到对应的 Bean 来注入到这个字段,但有些时候并不是一定需要,比如日志
    • 解决: 通过配置项 required 来改变,比如 @Autowired(required = false)

    @Autowired 注解不仅仅能配置在属性之上,还允许方法配置,常见的 Bean 的 setter 方法也可以使用它来完成注入,总之一切需要 Spring IoC 去寻找 Bean 资源的地方都可以用到,例如:

    自动装配的歧义性(@Primary和@Qualifier)

    在上面的例子中我们使用 @Autowired 注解来自动注入一个 Source 类型的 Bean 资源,但如果我们现在有两个 Srouce 类型的资源,Spring IoC 就会不知所措,不知道究竟该引入哪一个 Bean

    我们可以会想到 Spring IoC 最底层的容器接口——BeanFactory 的定义,它存在一个按照类型获取 Bean 的方法,显然通过 Source.class 作为参数无法判断使用哪个类实例进行返回,这就是自动装配的歧义性。

    为了消除歧义性,Spring 提供了两个注解:

    • @Primary 注解:
      代表首要的,当 Spring IoC 检测到有多个相同类型的 Bean 资源的时候,会优先注入使用该注解的类
    • 问题:该注解只是解决了首要的问题,但是并没有选择性的问题
    • @Qualifier 注解:
      上面所谈及的歧义性,一个重要的原因是 Spring 在寻找依赖注入的时候是按照类型注入引起的。除了按类型查找 Bean,Spring IoC 容器最底层的接口 BeanFactory 还提供了按名字查找的方法,如果按照名字来查找和注入不就能消除歧义性了吗?
    • 使用方法: 指定注入名称为 “source1” 的 Bean 资源

     使用@Bean 装配 Bean

    • 问题: 以上都是通过 @Component 注解来装配 Bean ,并且只能注解在类上,当你需要引用第三方包的(jar 文件),而且往往并没有这些包的源码,这时候将无法为这些包的类加入 @Component 注解,让它们变成开发环境中的 Bean 资源。
    • 解决方案:

    1.自己创建一个新的类来扩展包里的类,然后再新类上使用 @Component 注解,但这样很 low
    2.使用 @Bean 注解,注解到方法之上,使其成为 Spring 中返回对象为 Spring 的 Bean 资源。

    我们在 Package【pojo】 下新建一个用来测试 @Bean 注解的类:

    • 注意: @Configuration 注解相当于 XML 文件的根元素,必须要,有了才能解析其中的 @Bean 注

    然后我们在测试类中编写代码,从 Spring IoC 容器中获取到这个 Bean :

    @Bean 的配置项中包含 4 个配置项:

    • name: 是一个字符串数组,允许配置多个 BeanName
    • autowire: 标志是否是一个引用的 Bean 对象,默认值是 Autowire.NO
    • initMethod: 自定义初始化方法
    • destroyMethod: 自定义销毁方法

    使用 @Bean 注解的好处就是能够动态获取一个 Bean 对象能够根据环境不同得到不同的 Bean 对象。或者说将 Spring 和其他组件分离(其他组件不依赖 Spring,但是又想 Spring 管理生成的 Bean)

    Bean 的作用域

    在默认的情况下,Spring IoC 容器只会对一个 Bean 创建一个实例,但有时候,我们希望能够通过 Spring IoC 容器获取多个实例,我们可以通过 @Scope 注解或者 <bean> 元素中的 scope 属性来设置,例如:

     扩展阅读:@Profile 注解 、 条件化装配 Bean

    Spring 表达式语言简要说明

    Spring 还提供了更灵活的注入方式,那就是 Spring 表达式,实际上 Spring EL 远比以上注入方式都要强大,它拥有很多功能:

    • 使用 Bean 的 id 来引用 Bean
    • 调用指定对象的方法和访问对象的属性
    • 进行运算
    • 提供正则表达式进行匹配
    • 集合配置

    我们来看一个简单的使用 Spring 表达式的例子:

     与属性文件中读取使用的 “$” 不同,在 Spring EL 中则使用 “#

    扩展阅读: Spring 表达式语言

    来源于:---->

  • 相关阅读:
    eslint 的 env 配置是干嘛使的?
    cookie httpOnly 打勾
    如何定制 antd 的样式(theme)
    剑指 Offer 66. 构建乘积数组
    剑指 Offer 65. 不用加减乘除做加法
    剑指 Offer 62. 圆圈中最后剩下的数字
    剑指 Offer 61. 扑克牌中的顺子
    剑指 Offer 59
    剑指 Offer 58
    剑指 Offer 58
  • 原文地址:https://www.cnblogs.com/JonaLin/p/12669339.html
Copyright © 2011-2022 走看看