【Spring01】入门:IOC控制反转详解(XML和注解方式)

IoC 控制反转

概述

控制反转,是一个概念,一种思想。

就是将对象的创建、赋值、管理,交给代码之外的容器来实现。

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

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

正转:由开发人员在代码中,new出一个对象,主动管理对象。

容器:是一个软件、容器。spring就是这么一个容器。

Why IoC?:减少对代码的改动,也能实现不同的功能。解耦。

IoC的技术实现:DI: 依赖注入(Dependency Injection,简称DI) :只需要在程序内部提供要使用的对象名称就可以。

依赖注入:

当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在 传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者 实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为\注入。

依赖注入有两种:设值注入、构造注入

所谓依赖注入**,指程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部的注入。Spring的依赖注入对调用者和被调用者几乎没有任何要求,完全支持对POJO之间**依赖关系的管理。

spring是使用的di实现的控制反转,底层通过反射机制来创建对象。

创建对象

1、引入依赖

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.5.RELEASE</version>
</dependency>

2、创建一个接口和其实现类

3、在resources创建spring配置文件

在这里插入图片描述

4、在配置文件中 配置创建对象

<?xml version="1.0" encoding="UTF-8"?>
<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通过id找到对象
       class:类的权限定名称,不能是接口,因为spring是通过反射机制创建的对象

       此时spring就会完成创建操作:
       SomeService someService = new SomeServiceImpl();
       spring是将创建好的对象放入到map集合中,方便存取,spring有专门一个map是存放对象的
       例如:springMap.put("someService", new SomeServiceImpl());

        一个bean标签声明一个对象。
    -->
    <bean id="someService" class="com.wm.service.impl.SomeServiceImpl"></bean>
</beans>
<!--
        beans:根标签,bean即为一个java对象
        spring-beans.xsd:xml约束文件
-->

5、编写代码创建对象

@Test
public void testDoSome(){
	
    //指定spring的配置文件路径、名称
    String config = "beans.xml";
    /*
            创建spring的容器对象ApplicationContext,通过它就能获取java对象了
            ApplicationContext是一个接口,
            ClassPathXmlApplicationContext是常用的一个其实现类
                表示从类路径中加载配置文件
    * */
    ApplicationContext appContext = new ClassPathXmlApplicationContext(config);
    /*
    	从容器中获取对象
    	getBean( 配置文件中,bean的id值 );
    **/
    SomeServiceImpl someService = (SomeServiceImpl) appContext.getBean("someService");
    someService.doSome();
}

6、创建对象的时间:在创建spring的容器时,就会创建配置文件中配置的所有对象

ApplicationContext appContext = new ClassPathXmlApplicationContext(config);执行时,就已经创建好对象了。

而之后的getBean()都是从容器中取 已经创建好的对象

7、创建非自定义类的对象

如:Date对象、String对象…

同创建自定义对象的方法一样。

查看容器中对象的信息

@Test
public void test01(){
    String config = "beans.xml";
    ApplicationContext appContext = new ClassPathXmlApplicationContext(config);

    //获取容器中对象的数量
    int count = appContext.getBeanDefinitionCount();
    System.out.println("对象数量"+count);
    //获取容器中所有对象的名称
    String[] names = appContext.getBeanDefinitionNames();
    for (String name : names) {
        System.out.println("对象名称"+name);
    }
}

给对象赋值

(DI:依赖注入)

XML方式

set注入

spring通过调用对象的set方法给其属性赋值

简单类型

通过配置文件中bean标签中的property标签进行配置,name就是对象的属性名,value就是赋的值

<bean id="student" class="com.wm.ba01.Student">
    <property name="name" value="张三"/>
    <property name="age" value="20"/>
</bean>
@Test
public void test01(){
    String config = "ba01/applicationContext.xml";
    ApplicationContext appContext = new ClassPathXmlApplicationContext(config);
    Student student = (Student) appContext.getBean("student");
    System.out.println(student);
}
}

执行结果:

Student{name='张三', age=20}
引用类型

配置文件:

<!--
        di:给属性赋值
        1、set注入:spring调用对象的set方法给其赋值
            引用类型:
                通过 ref 来确定
                这个ref的值就是自定义的bean的id
-->
<bean id="school" class="com.wm.ba02.School">
    <property name="name" value="第一小学"/>
</bean>
<bean id="student" class="com.wm.ba02.Student">
    <property name="name" value="张三"/>
    <property name="age" value="20"/>
    <property name="school" ref="school"/><!-- 这里通过ref来给赋值 -->
</bean>
@Test
public void test01(){
    String config = "ba02/applicationContext.xml";
    ApplicationContext appContext = new ClassPathXmlApplicationContext(config);
    Student student = (Student) appContext.getBean("student");
    System.out.println(student);
}

执行结果为:

Student{name='张三', age=20, school=School{name='第一小学'}}
构造注入

通过有参构造方法赋值

    public Student(String name, int age, School school) {
        System.out.println("有参构造执行");
        this.name = name;
        this.age = age;
        this.school = school;
    }
    <!--
        di:给属性赋值
        2、构造注入:spring调用有参数构造方法给其赋值
            通过<constructor-arg>标签实现。
            一个<constructor-arg>标签表示构造方法的一个参数
            <constructor-arg name="" index="" value="" ref="">
            name:表示形参名
            index:表示形参的位置,从0开始
            value:简单类型的参数值
            ref:引用类型
		如果是按照形参顺序从上到下给index 0-n 的参数赋值,则index可以省略
    -->
    <bean id="student" class="com.wm.ba03.Student">
        <constructor-arg name="name" value="张三"/>
        <constructor-arg name="age" value="12"/>
        <constructor-arg name="school" ref="school"/>
    </bean>
    <bean id="school" class="com.wm.ba03.School">
        <property name="name" value="第一小学"/>
    </bean>
@Test
public void test02(){
String config = "ba03/applicationContext.xml";
ApplicationContext appContext = new ClassPathXmlApplicationContext(config);
Student student = (Student) appContext.getBean("student");
System.out.println(student);
}

执行结果

有参构造执行
Student{name='张三', age=12, school=School{name='第一小学'}}
自动注入引用类型
ByName

要求配置文件中 bean的id,和java实体类中的引用类型的属性名一致,且数据类型一致,这样spring能够自动为其赋值

<bean id="student" class="com.wm.ba04.Student" autowire="byName">
    <property name="name" value="张三"/>
    <property name="age" value="12"/>
</bean>
<bean id="school" class="com.wm.ba04.School">
    <property name="name" value="第一小学"/>
</bean>
ByType

要求配置文件中bean的class的值和java实体类的属性是同一类型(包括父子、接口实现类关系)。

<bean id="student" class="com.wm.ba04.Student" autowire="byType">
    <property name="name" value="张三"/>
    <property name="age" value="12"/>
</bean>
<bean id="school" class="com.wm.ba04.School">
    <property name="name" value="第一小学"/>
</bean>
多个配置文件

按模块:如登录模块一个、查询成绩一个…

按功能:如操作数据库的一个、做service的一个,做事务的一个…

每个模块的配置文件只定义这个模块的对象,所以此时则需要一个主配置文件将它们串联起来

<?xml version="1.0" encoding="UTF-8"?>
<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">
    <!--
        主配置文件:一般不定义对象,只需将模块配置文件引入即可
        classpath:ba05/spring_student.xml
        classpath表示类路径,即编译后target/class下的路径
	-->
    <import resource="classpath:ba05/spring_student.xml"/>
    <import resource="classpath:ba05/spring_school.xml"/>
</beans>

注解方式

@Component

、@Respotory、@Service、@Controller

创建对象

/*
* @Component:创建对象的。相当于<bean>标签
* value:对象名,相当于<bean>的id
* value值是唯一的,创建的对象在容器中只有一个
* 相当于:<bean id="student" class="com.wm.ba01.Student">
* spring中和@Component一样创建对象的还有
* @Repository:用在dao类上面(持久层
* @Service:用在service类上面(业务逻辑层
* @Controller:用在controller类上面(控制器层
* 这三个对象是给项目分层的。
* 这个类不是以上三种类,且需要创建对象的时候,使用@Component注解
* */
@Component(value = "student")
public class Student {
    
}
<!--
        声明组件扫描器component-scan:组件就是java对象
        base-package:指定注解在你项目中的包名
        之后,spring会扫描你指定包和其子包中的所有类,找到注解,创建对象或者赋值
-->
<context:component-scan base-package="com.wm.ba01"/>
<!--
	扫描多个包的方式:
	1、创建多个标签
	2、包之间用;或,分隔
	3、扫描他们的父包
-->
@Value

简单类型赋值

/*
* @Value:简单类型的属性赋值
* value:赋的值,“value=”可以省略,只需写赋的值即可@Value("张三")
* 位置:1、在属性上方:无需set方法,推荐使用
* 2、在set方法上方
* */
@Component(value = "student")
public class Student {

    @Value("张三")
    String name;
    @Value("12")
    int age;
}
@Autowired
@Component(value = "student")
public class Student {

    @Value("张三")
    String name;
    @Value("12")
    int age;
    /*
    * @Autowired:给引用数据类型赋值
    * 和xml中的自动注入相同原理,默认是byType方式
    * 位置:在属性上方,无需set方法,推荐使用。或在set方法上方。
    *    @Autowired(required = true):required默认为true:表示如果赋值失败就终止执行并报错
    *   (比如,@Qualifier(value = "")的value写错)
    *   若为false:表示如果赋值失败,则继续执行,赋值为null
    *   推荐使用true,bug尽早暴露,方便修改
    * 使用byName的方式:需要在属性上方加入@Qualifier(value = "")
    *   value的值是bean的id值,即@Component(value = "")的value值。
    * */
    @Autowired(required = true)
    @Qualifier(value = "school")
    School school;
}
@Component("school")
public class School {
    @Value("第二小学")
    String name;
}

@Resource

是jdk中的注解,spring保留了对其的支持。使用的也是自动注入的原理。

放在属性上方,无需set方法,推荐使用。或在set方法上方。

默认方式是byName:若byName赋值失败,则会继续使用byType。

只想使用byName的话:@Resource(name = " ")name的值为bean的id

两种方式的比较

xml的对象创建、赋值是和代码分离的,注解还需在类中编写,各有优缺点,因此:

若对象需要经常修改,则使用xml,若不经常修改则使用注解。

不过,现在的开发大多使用注解方式。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值