006-SSM三大框架(三)—— Spring 的 IoC 控制反转


一、Spring 框架概述


  Spring 是一个轻量级的 Java 开发框架,它是为了解决企业应用开发的复杂性而创建的。Spring 的核心是控制反转(IoC)面向切面编程(AOP)

  Spring 根据代码的功能特点,使用 Ioc 降低业务对象之间耦合度。IoC 使得主业务在相互调用过程中,不用再自己维护关系了,即不用再自己创建要使用的对象了。而是由 Spring容器统一管理,自动“注入”,注入即赋值。 而 AOP 使得系统级服务得到了最大复用,且不用再由程序员手工将系统级服务“混杂”到主业务逻辑中了,而是由 Spring 容器统一完成。


二、IoC 控制反转


一、IoC 控制反转

  指将传统上由程序代码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理。控制反转就是对对象控制权的转移,从程序代码本身反转到了外部容器。通过容器实现对象的创建,属性赋值,依赖的管理。

  依赖注入 DI(Dependency Injection):指程序运行过程中,若需要调用另一个对象协助时,无需在代码中创建被调用者,而是依赖于外部容器,由外部容器创建后传递给程序。


二、使用 Spring 创建对象

   Spring对对象的创建无需在代码中创建被调用者,而是依赖于外部容器,由外部容器创建后传递给程序,这种方式成为称为依赖注入(DI),注入的方式有两种:

   - 基于 XML 的 DI
   - 基于 注解 的 DI

   无论是使用以上哪种方式进行依赖注入创建对象,都需要先搭建一下 Spring 框架,做好前期的准备 ,以下使用 maven 项目作为演示 :

  1. 创建 maven 项目并在 pom.xml 加入 spring 的依赖:
    关于如何创建 maven 项目可参考该链接: 004-IDEA 中基于 Maven 创建 web 工程.
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>5.2.5.RELEASE</version>
</dependency>
  1. 在 resources 目录下创建 Spring 配置文件:applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
   1.beans : 是根标签,spring把java对象成为bean。
   2.spring-beans.xsd 是约束文件。
-->
<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">


</beans>
  1. 创建 Student 类和 School 类,School 是Student 类中的属性,用来接下来分别演示对简单类型和引用类型进行创建对象并且为其属性赋值
public class School {

    private String name;
    private String address;

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

    public void setAddress(String address) {
        this.address = address;
    }
}
public class Student {

    private String name;
    private int age;

    //声明一个引用类型
    private School school;
    
    public Student() {
        System.out.println("spring会调用类的无参数构造方法创建对象");
    }
    
	public Student(String name, int age, School school) {
        this.name = name;
        this.age = age;
        this.school = school;
    }

    public void setName(String name) {
        System.out.println("setName:"+name);
        this.name = name;
    }

    public void setAge(int age) {
        System.out.println("setAge:"+age);
        this.age = age;
    }

    public void setSchool(School school) {
        System.out.println("setSchool:"+school);
        this.school = school;
    }
}


一、基于 XML 的 DI

 根据注入方式的不同,常用的有两类:

一、set 注入

  set 注入也叫设值注入,是指通过 set 方法传入被调用者的实例,并且实现实例对象属性的赋值,因此需要该类必须有 set 方法才可以使用 set 注入的方式。

  1. 在 Spring 配置文件 pplicationContext.xml 分别创建 Student 对象 和 School 对象并使用 set 注入的方式进行属性赋值,然后交给 Spring 容器管理:
<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 , 就是告诉spring要创建某个类的对象。
        id:对象的自定义名称,唯一值,spring通过这个名称找到对象。
        class:类的全限定名称(不能是接口,因为spring是反射机制创建对象,必须使用类)
        因为该方式是用过无参构造方法创建对象的,所以类中必须有无参构造方法。
        一个bean标签声明一个对象,多个对象可以使用多个bean标签声明。
        声明之后 spring 就可以通过 new 的方式实现对象的创建,然后 spring 把创建好的对象放入到map中, spring框架有一个map存放对象的。
-->

	<!--创建School对象-->
  	<bean id="school" class="com.xzm.domain.School">
  	<!--
		当我们需要通过 set 注入为所创建的对象的简单类型属性进行赋值时,方法如下:
		<property name="属性名字" value="此属性的值"/>
        一个 <property> 标签只能给一个属性赋值,要给多个属性赋值需要使用多个 <property> 标签。        
	-->
        <property name="name" value="中山大学"/>
        <property name="address" value="广州海珠区" />
    </bean>
    
    <!--创建Student对象-->
    <bean id="student" class="com.xzm.domain.Student">
        <property name="name" value="路明非"></property>
        <property name="age" value="20"></property>

			<!--
		当我们需要通过 set 注入为所创建的对象的引用类型属性进行赋值时,方法如下:
		 <property name="属性名称" ref="bean的id(对象的名称)" />
        一个 <property> 标签只能给一个属性赋值,要给多个属性赋值需要使用多个 <property> 标签。        
	-->
        <property name="school" ref="school"></property>
    </bean>

</beans>
  1. 定义测试类
	@Test
    public void test01(){
    
		//创建表示spring容器的对象, ApplicationContext;
		// ApplicationContext就是表示Spring容器,通过容器获取对象了;
		// ClassPathXmlApplicationContext:表示从类路径中加载spring的配置文件;
       
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext");
        
        //从容器中获取某个对象:getBean("配置文件中的要获取的 bean 的 id 值")
         Student student = (Student) ac.getBean("student");
        System.out.println(student);
    }

二、构造注入

  spring 调用类有参数构造方法,在创建对象的同时,在构造方法中给属性赋值,因此需要该对象必须有有参构造方法才可以使用此方式。

  1. 在 Spring 配置文件 pplicationContext.xml 分别创建 Student 对象 和 School 对象并使用构造注入的方式进行属性赋值,然后交给 Spring 容器管理:
<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">



	<!--创建School对象-->
  	<bean id="school" class="com.xzm.domain.School">
  	<!--
		当我们需要通过构造注入为所创建的对象的简单类型属性进行赋值时,使用的是 <constructor-arg> 标签
        <constructor-arg> 标签属性:
           name:表示构造方法的形参名
           index:表示构造方法的参数的位置,参数从左往右位置是 0 , 1 ,2的顺序
           value:构造方法的形参类型是简单类型的,使用value
           ref:构造方法的形参类型是引用类型的,使用ref
           一个 <constructor-arg> 标签只能给一个属性赋值,要给多个属性赋值需要使用多个 <constructor-arg> 标签。        
	-->
	
		<!-- 
		使用 index 定位属性位置,根据该属性在构造方法参数的位置定位,从0开始。
		index 属性可以省略,省略时默认为构造方法第一个参数开始赋值
		-->
        <constructor-arg index="0" value="中山大学"/>
        <constructor-arg index="1" value="广州海珠区" />
    </bean>
    
    <!--创建Student对象-->
    <bean id="student" class="com.xzm.domain.Student">
    
    <!-- 使用 name 定位属性位置,根据该属性在构造方法参数的名字定位-->
        <constructor-arg name="name" value="路明非"/>
        <constructor-arg name="age" value="20"/>

	<!--当我们需要通过构造注入为所创建的对象的引用类型属性进行赋值时,只需要把 <constructor-arg> 标签中的 value 属性换为 ref 属性,该属性值为 bean 的 id(对象的名称)-->
        <constructor-arg name="school" ref="school" />
    </bean>

</beans>
  1. 定义测试类
	@Test
    public void test01(){
    
		//创建表示spring容器的对象, ApplicationContext;
		// ApplicationContext就是表示Spring容器,通过容器获取对象了;
		// ClassPathXmlApplicationContext:表示从类路径中加载spring的配置文件;
       
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext");
        
        //从容器中获取某个对象:getBean("配置文件中的要获取的 bean 的 id 值")
         Student student = (Student) ac.getBean("student");
        System.out.println(student);
    }

三、引用类型的自动注入

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

  • byName:根据名称自动注入;
  • byType: 根据类型自动注入;
  1. byName(按名称注入) : java 类中引用类型的属性名和spring 容器中(配置文件)的 id 名称一样,且数据类型是一致的,这样的容器中的bean,spring能够赋值给引用类型。
 <bean id="student" class="com.xzm.domain.Student" autowire="byName">
       <property name="name" value="诺诺"></property>
       <property name="age" value="20">
       <!--
       无需我们手动赋值,可不写
       <property name="school" ref="school" />
       --></property>
</bean>

<bean id="school" class="com.xzm.domain.School">
      <property name="name" value="中山大学"/>
      <property name="address" value="广州海珠区" />
</bean>
  1. byType(按类型注入) : java 类中引用类型的数据类型和 spring 容器中(配置文件)的class属性是同源关系的,这样的bean能够赋值给引用类型。
    同源就是一类的意思:
    (1).java类中引用类型的数据类型和bean的class的值是一样的。
    (2).java类中引用类型的数据类型和bean的class的值父子类关系的。
    (3).java类中引用类型的数据类型和bean的class的值接口和实现类关系的
 <bean id="student" class="com.xzm.domain.Student" autowire="byType">
       <property name="name" value="诺诺"></property>
       <property name="age" value="20">
       <!--
       无需我们手动赋值,可不写
       <property name="school" ref="school" />
       --></property>
</bean>

<bean id="school" class="com.xzm.domain.School">
      <property name="name" value="中山大学"/>
      <property name="address" value="广州海珠区" />
</bean>

二、基于注解的 DI

  对于 DI 使用注解,我们不再需要在 Spring 配置文件中声明 bean 实例,在 Spring 中使用注解,我们需要在 Spring 配置文件 pplicationContext.xml 中配置组件扫描器,用于在指定的基本包中扫描注解。

<!--声明组件扫描器(component-scan),组件就是java对象
    base-package:指定你要扫描你的项目中含有注解中的包名。
    component-scan工作方式: spring会扫描遍历base-package指定的包,把包中和子包中的所有类,找到类中的注解,按照注解的功能创建对象,或给属性赋值。
-->
    <context:component-scan base-package="com.xzm.damain" />

一、 定义 Bean 的注解 @Component

   @Component: 创建对象的, 等同于 < bean > 标签的功能;

  • 属性:value 就是对象的名称,value的值是唯一的,创建的对象在整个spring容器中就一个,也就是bean的id值,
  • 位置:在需要创建对象的类的上面
    @Component(value = “student”) 等同于:< bean id=“student” class=“com.xzm.damain.Student” />
@Component("school")
//value 里面的值可以省略不写为:@Component;此时不指定对象名称,由spring提供默认名称: 类名的首字母小写
public class School {

    private String name;
    private String address;

	public School() {}
 	public School(String name, String address) {
        this.name = name;
        this.address = address;
    }
}

spring 中和 @Component 功能一致,用于创建对象的注解还有:

  1. @Repository(用在持久层类的上面) : 放在dao的实现类上面,表示创建dao对象,dao对象是能访问数据库的。
  2. @Service(用在业务层类的上面):放在service的实现类上面,创建service对象,service对象是做业务处理,可以有事务等功能的。
  3. @Controller(用在控制器的上面):放在控制器(处理器)类的上面,创建控制器对象的,控制器对象,能够接受用户提交的参数,显示请求的处理结果。

以上三个注解的使用语法和@Component一样的,都能创建对象,但是这三个注解还有额外的功能


二、简单类型属性注入 @Value

   @Value: 简单类型的属性赋值

  • 属性: value 是String类型的,表示简单类型的属性值
  • 位置: 在属性定义的上面,无需 set 方法,推荐使用,如果有 set 方法,可以放在set方法的上面
@Component("school")
//value 里面的值可以省略不写为:@Component;此时不指定对象名称,由spring提供默认名称: 类名的首字母小写
public class School {

    @Value("楚子航")
    private String name;
    @Value("25")
    private int age;

	public School() {}
 	public School(String name, String address) {
        this.name = name;
        this.address = address;
    }
}

三、引用类型属性注入 @Autowired

   @Autowired: 引用类型的属性赋值,该注解默认使用 byType 自动装配Bean的方式。

  • 如果要使用 byName 方式,需要做的是:
    • 在属性上面加入@Autowired
    • 在属性上面加入@Qualifier(value=" bean的id ") :表示使用指定名称的bean完成赋值。
  • 位置: 在属性定义的上面,无需 set 方法,推荐使用,如果有 set 方法,可以放在set方法的上面
@Component
public class School {

    @Value("广州大学")
    private String name;
    @Value("广州番禺")
    private String address;
}
@Component("school")
//value 里面的值可以省略不写为:@Component;此时不指定对象名称,由spring提供默认名称: 类名的首字母小写
public class School {

    @Value("楚子航")
    private String name;
    @Value("25")
    private int age;

	//声明一个引用类型
    @Autowired
    private School school;
/*通过 byName 方式
	@Autowired
    @Qualifier("school")
    private School school;
 */
}

四、引用类型属性注入 @Resource

   @Resource:来自jdk中的注解,spring框架提供了对这个注解的功能支持,可以使用它给引用类型赋值,该注解使用的也是自动注入原理,支持byName, byType,默认是先使用 byName 自动注入,如果byName赋值失败,再使用byType;

  • 如果需要 @Resource 只使用byName方式,需要增加一个属性 name , name的值是bean的id(名称);
  • 位置: 在属性定义的上面,无需 set 方法,推荐使用,如果有 set 方法,可以放在set方法的上面;
@Component
public class School {

    @Value("广州大学")
    private String name;
    @Value("广州番禺")
    private String address;
}
@Component("school")
//value 里面的值可以省略不写为:@Component;此时不指定对象名称,由spring提供默认名称: 类名的首字母小写
public class School {

    @Value("楚子航")
    private String name;
    @Value("25")
    private int age;

	//声明一个引用类型
    @Resource
    private School school;
/*指定只使用 byName 方式
	@Resource(name = "school")
    private School school;
 */
}


相关链接:

链接: 004-SSM三大框架(二)—— MyBatis 框架动态 SQL.
链接: 003-SSM三大框架(二)—— 深入理解 MyBatis 的参数传递.
链接: 002-SSM三大框架(二)—— 基于Maven工程搭建 MyBatis 开发环境.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值