玩命加载中 . . .

Spring(01)


IOC控制反转

概述:

Spring 的主要作用就是为代码“解耦”,降低代码间的耦合度。 就是让对象和对象(模块和模块)之间关系不是使用代码关联,而是通过配置来说明。即在 Spring 中说明对象(模块)的关系。
Spring 根据代码的功能特点, 使用 IOC 降低业务对象之间耦合度。 IOC 使得主业务在相互调用过程中,不用再自己维护关系了,即不用再自己创建要使用的对象了。而是由 Spring容器统一管理,自动“注入” ,注入即赋值。 而 AOP 使得系统级服务得到了最大复用,且
不用再由程序员手工将系统级服务“混杂”到主业务逻辑中了,而是由 Spring 容器统一完成“织入”。

基于XML文件进行DI

注入分类

set 注入

set 注入也叫设值注入是指,通过 setter 方法传入被调用者的实例。这种注入方式简单、直观,因而在 Spring 的依赖注入中大量使用。

注意:spring使用set进行注入时,其使用原理是调用类中的set+变量的方法进行赋值,所以使用set方式尽心赋值类中必须有set方法。

    <bean id="student01" class="com.xrebirth.bean01.Student">
        <property name="name" value="张三" />
        <property name="age" value="10" />
        <property name="sex" value="" />
    </bean>

详见:spring联系中的LearnSpring02模块

引用类型注入

当指定 bean 的某属性值为另一 bean 的实例时,通过 ref 指定它们间的引用关系。 ref的值必须为某 bean 的 id 值。

    <bean id="student02" class="com.xrebirth.bean02.Student">
        <property name="name" value="黎霞" />
        <property name="age" value="10" />
        <property name="sex" value="" />
        <!--给引用类型对象赋值-->
        <property name="school" ref="school01" />
    </bean>
    <!--声名School对象-->
    <bean id="school01" class="com.xrebirth.bean02.School">
        <property name="name" value="漳州理工职业学院" />
        <property name="address" value="贵州省 六盘水市 水城县"/>
    </bean>

构造注入

构造注入是指:在构造调用者实例的同时,完成被调用者的实例化。即使用构造器设置依赖关系。

<constructor-arg />标签中用于指定参数的属性有:

  • name:指定参数名称。

  • index:指明该参数对应着构造器的第几个参数,从 0 开始。不过,该属性不要也行,
    但要注意,若参数类型相同,或之间有包含关系,则需要保证赋值顺序要与构造器中的参数
    顺序一致。

  • value:构造方法的形参类型是简单类型的话使用value。

  • ref:构造方法的形参类型是引用类型的话使用ref。

使用name方式进行构造注入
    <!--声名School对象-->
    <bean id="school02" class="com.xrebirth.bean03.School">
        <property name="name" value="漳州理工职业学院" />
        <property name="address" value="贵州省 六盘水市 水城县"/>
    </bean>
    <!--3.使用构造函数注入-->
    <!--使用name对构造函数赋值-->
    <bean id="student03" class="com.xrebirth.bean03.Student">
        <constructor-arg name="name" value="李四" />
        <constructor-arg name="age" value="20" />
        <constructor-arg name="sex" value="" />
        <constructor-arg name="school" ref="school02" />
    </bean>
使用value方式进行构造注入
    <!--声名School对象-->
    <bean id="school03" class="com.xrebirth.bean03.School">
        <property name="name" value="山西工商学院" />
        <property name="address" value="澳门特别行政区 离岛"/>
    </bean>
    <!--3.使用构造函数注入-->
    <!--使用index对构造函数赋值-->
    <bean id="student04" class="com.xrebirth.bean03.Student">
        <constructor-arg index="0" value="王五" />
        <constructor-arg index="3" ref="school03" />
        <constructor-arg index="1" value="27" />
        <constructor-arg index="2" value="" />
    </bean>
使用省略value方式进行构造注入
    <!--声名School对象-->
    <bean id="school04" class="com.xrebirth.bean03.School">
        <property name="name" value="山东服装职业学院" />
        <property name="address" value="北京 北京市 怀柔区"/>
    </bean>
    <!--使用省略index对构造函数赋值-->
    <!--省略index必须与构造方法中的参数顺序一样-->
    <bean id="student05" class="com.xrebirth.bean03.Student">
        <constructor-arg value="赵六" />
        <constructor-arg value="30" />
        <constructor-arg value="" />
        <constructor-arg ref="school04" />
    </bean>

引用类型自动注入

对于引用类型属性的注入,也可不在配置文件中显示的注入。可以通过为<bean/>标签设置 autowire 属性值,为引用类型属性进行隐式自动注入(默认是不自动注入引用类型属性)。根据自动注入判断标准的不同,可以分为两种:
byName:根据名称自动注入
byType: 根据类型自动注入

byName 方式自动注入

当配置文件中被调用者 bean 的 id 值与代码中调用者 bean 类的属性名相同时,可使用byName 方式,让容器自动将被调用者 bean 注入给调用者 bean。容器是通过调用者的 bean类的属性名与配置文件的被调用者 bean 的 id 进行比较而实现自动注入的。

    <!--byName进行引用类型自动赋值-->
    <bean id="student01" class="com.xrebirth.bean01.Student" autowire="byName">
        <property name="name" value="李四" />
        <property name="age" value="20" />
        <property name="sex" value="" />
        <!--Spring自动给引用类型对象赋值-->
    </bean>
    <!--声名school对象-->
    <bean id="school" class="com.xrebirth.bean01.School">
        <property name="name" value="海南外国语职业学院" />
        <property name="address" value="内蒙古自治区 巴彦淖尔市 其它区" />
    </bean>
byType 方式自动注入

使用 byType 方式自动注入,要求:配置文件中被调用者 bean 的 class 属性指定的类,要与代码中调用者 bean 类的某引用类型属性类型同源。即要么相同,要么有 is-a 关系(子类,或是实现类)。但这样的注意:同源的被调用 bean 只能有一个。多于一个,spring容器就会报错。

  1. java类中引用类型的数据类型和bean的class的值是相同的。(类型相同)
  2. java类中引用类型的数据类型和bean的class的值是父子关系。(继承关系)
  3. java类中引用类型的数据类型和bean的class的值接口和实现类关系。(实现关系)

详见:LearnSpring04模块

为应用指定多个 Spring 配置文件

在实际应用里,随着应用规模的增加,系统中 Bean 数量也大量增加,导致配置文件变得非常庞大、臃肿。为了避免这种情况的产生,提高配置文件的可读性与可维护性,可以将Spring 配置文件分解成多个配置文件。

包含关系的配置文件

多个配置文件中有一个总文件,总配置文件将各其它子文件通过引入。在 Java代码中只需要使用总配置文件对容器进行初始化即可。

school模块:

    <!--school模块所有bean声名 school模块的配置文件-->
    <bean id="school" class="com.xrebirth.bean01.School">
        <property name="name" value="田洋" />
        <property name="address" value="甘肃省 白银市 靖远县" />
    </bean>

student模块:

    <!--student模块所有bean声名 student模块的配置文件-->
    <bean id="student" class="com.xrebirth.bean01.Student">
        <property name="name" value="李四" />
        <property name="age" value="20" />
        <property name="sex" value="" />
    </bean>

spring总配置文件:

    <!--加载的是文件列表-->
    <import resource="classpath:bean01/spring-school.xml" />
    <import resource="classpath:bean01/spring-student.xml" />

Spring中可以使用通配符,但此时要求父配置文件名不能满足所能匹配的格式,否则将出现循环递归包含。就本例而言,父配置文件不能匹配 spring-*.xml 的格式,即不能起名为spring-total.xml。

使用通配符配置总配置文件:

    <import resource="classpath:bean01/spring-*.xml" />

基于注解的DI

概述:对于 DI 使用注解,将不再需要在 Spring 配置文件中声明 bean 实例。Spring 中使用注解,需要在原有 Spring 运行环境基础上再做一些改变。需要在 Spring 配置文件中配置组件扫描器,用于在指定的基本包中扫描注解。 使用注解开发需要在xml文件中加入组件扫描器,目的是通过组件扫描器扫面指定类中的注解从而实现注解开发。

声名组件扫描器

使用多次组件扫描器指定不同的包

    <!--第一种方式:使用多次组件扫描器指定不同的包-->
    <context:component-scan base-package="com.xrebirth.bean01" />
    <context:component-scan base-package="com.xrebirth.bean02" />

使用分隔符(;或,)分隔多个包名

<!--第二种方式:使用分隔符(;或,)分隔多个包名-->
<context:component-scan base-package="com.xrebirth.bean01;com.xrebirth.bean02" />

指定父包下所有资源进行自动扫描注解

注意:不建议使用顶级的父包,扫描的路径比较多,导致容器启动时间变慢。指定到目标包和合
适的。也就是注解所在包全路径。例如注解的类在 com.xrebirth 包中。

<!--第三种方式:指定父包-->
<context:component-scan base-package="com.xrebirth" />

定义 Bean 注解@Component

  • 作用:创建对象的,等同于<bean></bean>标签功能。

    @Component(value = "myStudent") 等同于 <bean id="myStudent" class="com.xrebirth.bean01.Student" />
    
  • 属性: value就是对象的名称,也就是bean的id值(value的值是唯一的,创建的对象在spring中就一个)。

  • 位置:注解使用在类的上面。

全程写法:

@Component(value = "myStudent")

简称写法:

@Component("myStudent")

注意:@Component 不指定 value 属性, bean 的 id 是类名的首字母小写。

Spring 还提供了另外 3 个创建对象的注解

  1. @Repository:用于对 DAO层 实现类进行注解。
  2. @Service :用于对 Service层 实现类进行注解。
  3. @Controller:用于对 Controller 实现类进行注解。

这三个注解与@Component 都可以创建对象,但这三个注解还有其他的含义, @Service创建业务层对象,业务层对象可以加入事务功能, @Controller 注解创建的对象可以作为处理器接收用户的请求。

@Repository, @Service, @Controller 是对@Component 注解的细化,标注不同层的对象。 即持久层对象,业务层对象,控制层对象。

简单类型属性注入@Value

需要在属性上使用注解@Value,该注解的 value 属性用于指定要注入的值。使用该注解完成属性注入时,类中无需 setter。当然,若属性有 setter,则也可将其加到 setter 上。

//注解参数中省略了value属性,该属性用于指定Bean的id
@Component("myStudent")
public class Student {
    //@Value(value = "小明")简写("常用方式")
    @Value("小明")
    private String name;
    //@Value(value = "20")
    //简写("常用方式")
    @Value("20")
    private int age;
}

byType 自动注入@Autowired

需要在引用属性上使用注解@Autowired,该注解默认使用按类型自动装配 Bean 的方式。使用该注解完成属性注入时,类中无需 setter。当然,若属性有 setter,则也可将其加到 setter 方法上。Autowired默认使用的是byType自动注入。

    //使用在属性上面
    @Autowired
    private School school;
   //使用在set方法上面
    //@Autowired
    public void setSchool(School school) {
        this.school = school;
    }

byName 自动注入@Autowired 与@Qualifier

@Autowired 注解默认注入方式为byType如果需要byName方式则需要在引用属性上联合使用注解@Autowired 与@Qualifier。 @Qualifier 的 value 属性用于指定要匹配的 Bean 的 id 值。 类中无需 set 方法,也可加到 set 方法上。

    //使用在属性上面
    @Autowired
    @Qualifier("mySchool")
    private School school;
    //使用在set方法上面
    //@Autowired
    //@Qualifier("mySchool")
    public void setSchool(School school) {
        this.school = school;
    }

@Autowired默认属性

@Autowired 还有一个属性 required,默认值为 true,表示当匹配失败后,会终止程序运行。若将其值设置为 false,则匹配失败,将被忽略,未匹配的属性值为 null。

    @Autowired(required=false)
    @Qualifier("mySchool")
    private School school;

JDK 注解@Resource 自动注入

Spring提供了对JDK中@Resource注解的支持。@Resource 注解既可以按名称匹配Bean,也可以按类型匹配 Bean。 默认是按名称注入。 使用该注解,要求 JDK 必须是 6 及以上版本。@Resource 可在属性上,也可在 set 方法上。

    //使用在属性上面
    @Resource
    private School school;

使用byName匹配则需要加入那么属性

    //使用在属性上面
    @Resource(name = "mySchool")
    private School school;

注意:@Resource 注解自JDK6以上才会支持,但是自JDK11版本移除了javax.annotation包,所以如果JDK11使用需要在Maven中加入相关的依赖才可使用。

    <!--@Resource注解依赖-->
    <dependency>
      <groupId>javax.annotation</groupId>
      <artifactId>javax.annotation-api</artifactId>
      <version>1.3.2</version>
    </dependency>

注解与 XML 的对比

注解优点:

  • 方便
  • 直观
  • 高效(代码少,没有配置文件的书写那么复杂)

注解缺点:

以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码。

XML 方式优点:

配置和代码是分离的

在 xml 中做修改,无需编译代码,只需重启服务器即可将新的配置加载。

XML 方式缺点:

编写麻烦,效率低,大型项目过于复杂。


文章作者: 小靳同学
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 小靳同学 !
评论
 上一篇
Spring(02) Spring(02)
AOP 面向切面编程作用 在目标类不增加代码的情况下,给目标类增加功能。 减少重复的代码。 让开发人员更加专注于业务逻辑的实现。 解耦合:将
2022-01-08
下一篇 
接收json数组报错使用JSON.parse()方法将数据(字符串)转化js对象 接收json数组报错使用JSON.parse()方法将数据(字符串)转化js对象
问题:接收json数组报错使用JSON.parse()方法将数据(字符串)转化js对象问题:在后端传给前端数据(JSON数组)时,JS通过J
2021-12-22
  目录