Spring学习(3)——IoC控制反转(Inversion of Control)


IoC (Inversion of Control) : 控制反转, 是一个理论,概念,思想。

描述:把对象的创建,赋值,管理工作都交给代码之外的容器实现, 也就是对象的创建是由其它外部资源完成。

控制: 创建对象,对象的属性赋值,对象之间的关系管理。

反转: 把原来的开发人员管理、创建对象的权限转移给代码之外的容器实现。 由容器代替开发人员管理对象。创建对象,给属性赋值。

正转:由开发人员在代码中,使用new 构造方法创建对象, 开发人员主动管理对象。例如:

public static void main(String args[]){
    Student student = new Student(); // 在代码中, 创建对象。--正转。
}

容器:是一个服务器软件, 一个框架(spring)

为什么要使用IoC: 目的就是减少对代码的改动, 也能实现不同的功能。 实现解耦合。

首先,我们需要了解一下java中创建对象有哪几种方式呢?

  1. 构造方法 , new Student()
  2. 反射
  3. 序列化
  4. 克隆 clone()
  5. ioc :容器创建对象
  6. 动态代理

IoC在学习Spring之前的体现

主要体现在servlet上面

  1. 创建类继承HttpServelt
  2. 在web.xml 注册servlet , 使用
<servlet-name> myservlet </servlet-name>
<servelt-class>com.bjpwernode.controller.MyServlet1</servlet-class>
  1. 没有创建 Servlet对象, 没有 MyServlet myservlet = new MyServlet()

  2. Servlet 是Tomcat服务器它能你创建的。 Tomcat也称为容器
    Tomcat作为容器:里面存放的有Servlet对象, Listener , Filter对象

Spring 容器是一个超级大工厂,负责创建、管理所有的 Java 对象,这些 Java 对象被称为 Bean。Spring 容器管理着容器中 Bean 之间的依赖关系,Spring 使用“依赖注入”的方式来管理 Bean 之间的依赖关系。使用 IoC 实现对象之间的解耦和。

Spring 框架使用依赖注入(DI)实现 IoC

依赖注入(DI)

DI(Dependency Injection) :依赖注入, 只需要在程序中提供要使用的对象名称就可以, 至于对象如何在容器中创建、赋值、查找都由容器内部实现。

spring是使用的di实现了ioc的功能, spring底层创建对象,使用的是反射机制。

基于XML的DI

注入方式分为两类:一类是set注入,另一类是构造注入

set方式注入

set注入(设值注入):spring调用类的set方法,为属性赋值。它只会调用set方法,而不会去管你set方法里面到底写的什么。

1) 简单类型的set注入

简单类型:spring中规定java的基本数据类型和String都是简单类型
语法:

<bean id="xx" class="yyy">
      <property name="属性名字" value="此属性的值"/>
      注意:一个property只能给一个属性赋值。如果有多个属性,则需要写多个property标签
</bean>

2). 引用类型的set注入

同样是spring调用类的set方法

区别在于需要将引用类型再单独写个bean来为它创建对象传入主类的set方法里面

例如:我定义了一个Student类,他有一个School属性

public class Student {

    private String name;
    private int age;

    //定义一个引用数据类型
    private School school;

}
public class School {

    private String name;
    private String address;
}

此时配置文件为:

	<bean id="myStudent2" class="com.ba02.Student">
        <property name="name" value="张三"/>
        <property name="age" value="26"/>
        <!--引用类型-->
        <property name="school" ref="mySchool"/>
    </bean>

    <!--声明school对象-->
    <bean id="mySchool" class="com.ba02.School">
        <property name="name" value="北京大学"/>
        <property name="address" value="北京海淀区"/>
    </bean>

此外,对于引用类型属性的注入,也可不在配置文件中显示的注入。可以通过为<bean/>标签设置 autowire 属性值,为引用类型属性进行隐式自动注入,称为引用类型的自动注入

根据自动注入判断标准的不同,可以分为两种:byName和byType

  1. byName(按名称注入):java类中引用类型的属性名和spring容器中(配置文件)<bean>的id名称一样,且数据类型是一致的,这样的容器中的bean,spring能够赋值给引用类型

语法:

<bean id="xx" class="yyy" autowire="byName">
		简单类型属性赋值
</bean>
  1. byType(按类型注入):java类中引用类型的数据类型和spring容器中(配置文件)的class属性是同源关系,这样的bean能够赋值给引用类型
    同源就是一类的意思:
    1)java类中引用类型的数据类型和bean的class值时一样的
    2)java类中引用类型的数据类型和bean的class的值是父子类关系的
    3)java类中引用类型的数据类型和bean的class的值是接口和实现类关系的

注意:byType 方式中只能有一种同源关系,如果 bean中两种或以上则会报错

语法:

<bean id="xx" class="yyy" autowire="byType">
		简单类型属性赋值
</bean>

以上两种方式事实上就是用autowire标签代替了语句<property name="school" ref="mySchool"/>的执行。

构造注入

即直接调用有参构造方法创建对象。spring调用类的有参构造方法,在创建对象的同时,给属性赋值,构造注入使用<constructor-arg>标签

注意:一个标签只能传一个参数

<constructor-arg>标签属性:
name: 表示形参名
index:参数的位置,从左往右。0,1,2的顺序
value:简单类型使用value
ref:引用类型

	<bean id="myStudent" class="com.ba03.Student">
        <constructor-arg name="name" value="张三"/>
        <constructor-arg name="age" value="21"/>
        <constructor-arg name="school" ref="mySchool"/>
    </bean>

    <!--使用index属性-->
    <bean id="myStudent2" class="com.ba03.Student">
        <constructor-arg index="0" value="张三"/>
        <constructor-arg index="1" value="21"/>
        <constructor-arg index="2" ref="mySchool"/>
    </bean>
    <!--省略index属性-->
    <bean id="myStudent3" class="com.ba03.Student">
        <constructor-arg value="张三"/>
        <constructor-arg value="21"/>
        <constructor-arg ref="mySchool"/>
    </bean>

基于注解的DI

创建对象

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

  • 属性: value就是对象的名称,也就是bean的id值,value的值是唯一的,创建的对象在整个spring中就一个
  • 位置:在类的上面

@Component(value="myStudent")等同于 <bean id="myStudent" class="com.ba01.Student"/>

如果不指定对象名称,由spring提供默认名称:类名的首字母小写,即student

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

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

以上三个注解的使用语法和@Component一样的。都能创建对象,但是这三个注解还有额外的功能。
@Repository , @Service , @Controller是给项目的对象分层的。

在applicationContext.xml加入类所在路径,例如:

<context:component-scan base-package="com.ba06"/>

component-scan标签,声明组件扫描器,组件就是java对象,加入这个标签后,配置文件的变化:

  1. 加入了新的约束文件:spring-context.xsd
  2. 给这个新的约束文件起个命名空间的名称
    xmlns:context=“http://www.springframework.org/schema/context”
    http://www.springframework.org/schema/context
    https://www.springframework.org/schema/context/spring-context.xsd

一个标签只能加载一个包,如果有多个包,要使用下面这种方式:

	<!--指定多个包的三种方式-->
    <!--第一种方式:使用多次组件扫描器,指定不同的包-->
    <context:component-scan base-package="com.ba01"/>
    <context:component-scan base-package="com.ba02"/>
    <!--第二种方式:使用分隔符(;或,)分隔多个包名-->
    <context:component-scan base-package="com.ba01; com.ba02"/>
    <!--第三种方式:指定父包-->
    <context:component-scan base-package="com"/>
给属性赋值

@ VaLue:简单类型的属性赋值
属性:value是String类型的,表示简单类型的属性值

位置:

  1. 在属性定义的上面,无需set方法,推荐使用。
  2. 在set方法的上面

例如:

	@Value("张飞")
    private String name;
    @Value("23")
    private Integer age;

上面是给简单类型,那么如何给引用类型赋值呢?

我现在有个Student类,其中有个School属性,如何实现对School的赋值操作呢?

我们需要用到另一个注解@Autowired

@ Autowired:Spring框架提供的注解,实现引用类型的赋值。
Spring中通过注解给引用类型赋值,使用的是自动注入原理,支持byNamebyType

@ Autowired:默认使用的是byType自动注入。

位置:

  1. 在属性定义的上面,无需set方法,推荐使用
  2. 在set方法的上面

如果要使用byName方式,需要做的是:

1.在属性上面加入@Autowired

2.在属性上面加入@Qualifier(value="bean的id"):表示使用指定名称的bean完成赋值

例如,我们先给School赋值
在这里插入图片描述

然后再对Student中的School进行操作
在这里插入图片描述
此时就完成了对引用数据类型的赋值了

注意: 当使用byName,如果 注解中的值和属性的id不一样时 会出现下面的情况:

在这里插入图片描述
@Autowired还有一个属性叫required返回boolean类型,默认为true

  • required=true :表示引用类型赋值失败,程序报错,并终止执行。
  • required=false :引用类型如果赋值失败,程序正常执行,引用类型是null

除了@Autowired注解外,还可以用@Resource给引用类型赋值

@Resource是jdk中的注解,默认是byName :先使用byName自动注入,如果byName赋值失败,再使用byType

如果要只使用byName,则应该写@Resource(name="mySchool")

使用方式:
在这里插入图片描述

注解与 XML 的对比

注解优点是:

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

弊端也显而易见:以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码的

XML 方式优点是:

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

xml 的缺点是:编写麻烦,效率低,大型项目过于复杂

总结:经常修改就用xml,无需修改就用注解

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值