专栏首页趣谈编程深入浅出Spring IOC(一)

深入浅出Spring IOC(一)

前言:

Spring是一个企业级开发框架,为解决企业级项目开发过于复杂而创建的,框架的主要优势之一就是分层架构,允许开发者自主选择组件。

Spring的两大核心机制是IOC(控制反转)和AOP(面向切面编程),

从开发的角度讲,我们使用Spring框架就是用它的IOC和AOP。

IOC是典型的工厂模式,通过工厂去注入对象。

AOP则是代理模式的体现。

今天我们来详细了解IOC,IOC是Spring框架的灵魂,非常重要,理解了IOC才能掌握Spring框架如何使用。

IOC也叫控制反转,首先从字面意思理解,什么叫控制反转?反转的是什么?

在传统的程序开发中,需要调用对象时,通常由调用者来创建被调用者的实例,即对象是由调用者主动new出来的。

但在Spring框架中创建对象的工作不再由调用者来完成,而是交给IOC容器来创建,再推送给调用者,整个流程完成反转,所以是控制反转。

举个例子:超市购物。

传统方式:你去超市买东西,需要自己拿着袋子去超市选择商品,然后自己把袋子提回来。

IOC:你只需要把袋子放在家门口,然后超市会自动在袋子里装满你需要的商品,打开袋子直接用就可以了。

代码:

我们通过创建一个Student对象来解释IOC的使用。

传统方式

1.创建Student类。

public class Student {
    private int id;
    private String name;
    private int age;

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

2.测试方法中调用构造函数创建对象。

public class Test {
    public static void main(String[] args) {
        Student student = new Student();
        System.out.println(student);
    }
}

通过IOC容器来创建对象

准备工作:

1.添加Spring相关jar包。

2.创建配置文件,可以自定义文件名spring.xml。

3.调用API。

程序思路:

1.在spring.xml中配置bean标签,IOC容器通过加载bean标签来创建对象。

2.调用API获取IOC创建的对象。

代码:

IOC容器可以调用无参构造或者有参构造来创建对象,我们先来看无参构造的方式。

无参构造:

<?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">

     <!-- 配置student对象-->
     <bean id="stu" class="com.hzit.entity.Student"></bean>

</beans>

1.配置一个bean标签:

id:对象名。

class:对象的模板类。

2.调用API获取对象

Spring提供了两种方式来获取对象:id或者运行时类。

1.通过id获取对象

public class Test {
    public static void main(String[] args) {
        //1.加载spring.xml配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        //2.通过id值获取对象
        Student stu = (Student) applicationContext.getBean("stu");
        System.out.println(stu);
    }
}

第一步:加载spring.xml配置文件,生成ApplicationContext对象。

第二步:调用ApplicationContext的getBean方法获取对象,参数为配置文件中的id值。

程序在加载spring.xml时创建stu对象,通过反射机制调用无参构造函数,所有要求交给IOC容器管理的类必须有无参构造函数。

可以看到,此时stu对象的属性全部为空,因为调用无参构造只会创建对象而不会进行赋值,如何赋值呢?只需要在spring.xml中进行相关配置即可。

<?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">

     <!-- 配置student对象 -->
     <bean id="stu" class="com.southwind.entity.Student">
        <property name="id" value="1"></property>
        <property name="name" value="张三"></property>
        <property name="age" value="23"></property>
     </bean>

</beans>

添加property标签:name对应属性名,value是属性的值。

若包含特殊字符,比如name="<张三>",使用<![CDATA[<张三>]]>进行配置。

<?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">

     <!-- 配置student对象 -->
     <bean id="stu" class="com.southwind.entity.Student">
        <property name="id" value="1"></property>
        <property name="name">
            <value><![CDATA[<张三>]]></value>
        </property>
        <property name="age" value="23"></property>
     </bean>

</beans>

Spring通过调用每个属性的setter方法来完成属性的赋值。所以实体类必须有setter方法,否则加载时报错,getter方法可省略。

2.通过运行时类获取对象

public class Test {
    public static void main(String[] args) {
        //1.加载spring.xml配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        //2.通过运行时类获取对象
        Student stu = applicationContext.getBean(Student.class);
        System.out.println(stu);
    }
}

此方法有一个弊端,当spring.xml中配置两个Student的bean时程序报错,因为此时两个bean都是由Student类生成的,IOC容器无法将两个bean都返回,必须指定一个唯一的bean。

<?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 id="stu" class="com.hzit.entity.Student">
        <property name="id" value="1"></property>
        <property name="name">
            <value><![CDATA[<张三>]]></value>
        </property>
        <property name="age" value="23"></property>
     </bean>

     <bean id="stu2" class="com.hzit.entity.Student">
        <property name="id" value="1"></property>
        <property name="name" value="李四"></property>
        <property name="age" value="23"></property>
     </bean>

</beans>

以上是IOC容器通过无参构造创建对象的方式,同时IOC容器也可以调用有参构造来创建对象。

有参构造:

首先在实体类中创建有参构造。

public Student(int id, String name, int age) {
        super();
        this.id = id;
        this.name = name;
        this.age = age;
    }

spring.xml中进行配置。

<?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 id="stu3" class="com.hzit.entity.Student">
        <constructor-arg name="id" value="3"></constructor-arg>
        <constructor-arg name="name" value="小明"></constructor-arg>
        <constructor-arg name="age" value="22"></constructor-arg>
     </bean>

</beans>

此时IOC容器会根据constructor-arg标签去加载对应的有参构造函数,创建对象并完成属性赋值。

name的值需要与有参构造的形参名对应,value是对应的值。

除了使用name对应参数外,还可以通过下标index对应。

<?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 id="stu3" class="com.hzit.entity.Student">
        <constructor-arg index="0" value="3"></constructor-arg>
        <constructor-arg index="1" value="小明"></constructor-arg>
        <constructor-arg index="2" value="22"></constructor-arg>
     </bean>

</beans>

以上是IOC容器通过有参构造创建对象的方式,获取对象同样有两种方式可以选择:id和运行时类。

如果IOC容器管理多个对象,并且对象之间有级联关系,如何实现?

创建(班级)Classes类。

public class Classes {
    private int id;
    private String name;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

在Student类中添加Classes属性。

public class Student {
    private int id;
    private String name;
    private int age;
    private Classes classes;
    public Classes getClasses() {
        return classes;
    }
    public void setClasses(Classes classes) {
        this.classes = classes;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

spring.xml中配置classes对象,然后将该对象赋值给stu对象。

<?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">

     <!-- 创建classes对象 -->
     <bean id="classes" class="com.hzit.entity.Classes">
        <property name="id" value="1"></property>
        <property name="name" value="Java班"></property>
     </bean>

     <!-- 创建stu对象 -->
     <bean id="stu" class="com.hzit.entity.Student">
        <property name="id" value="1"></property>
        <property name="name">
            <value><![CDATA[<张三>]]></value>
        </property>
        <property name="age" value="23"></property>
        <!-- 将classes对象赋给stu对象 -->
        <property name="classes" ref="classes"></property>
     </bean>

</beans>

在spring.xml中,通过ref属性将其他bean赋给当前bean对象,这种方式叫做依赖注入(DI),是Spring非常重要的机制,DI是将不同对象进行关联的一种方式,是IOC的具体实现方式,通常DI和IOC是紧密结合在一起的,所以一般说的IOC包括DI。

如果是集合属性如何依赖注入?

Classes类中添加List<Student>属性。

public class Classes {
    private int id;
    private String name;
    private List<Student> students;

    public List<Student> getStudents() {
        return students;
    }
    public void setStudents(List<Student> students) {
        this.students = students;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

spring.xml中配置2个student对象,1个classes对象,并将2个student对象注入到classes对象中。

<?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">

     <!-- 配置classes对象 -->
     <bean id="classes" class="com.hzit.entity.Classes">
        <property name="id" value="1"></property>
        <property name="name" value="Java班"></property>
        <property name="students">
            <!-- 注入student对象 -->
            <list>
                <ref bean="stu"/>
                <ref bean="stu2"/>
            </list>
        </property>
     </bean>

     <bean id="stu" class="com.hzit.entity.Student">
        <property name="id" value="1"></property>
        <property name="name">
            <value><![CDATA[<张三>]]></value>
        </property>
        <property name="age" value="23"></property>
     </bean>

     <bean id="stu2" class="com.hzit.entity.Student">
        <property name="id" value="2"></property>
        <property name="name" value="李四"></property>
        <property name="age" value="23"></property>
     </bean>

</beans>

集合属性通过list标签和ref标签完成注入。ref的bean属性指向需要注入的bean对象。

总结:

IOC是Spring的核心,很重要。使用Spring开发项目时,控制层,业务层,DAO层都是通过IOC来完成依赖注入的。

源码:

链接: https://pan.baidu.com/s/1dvMy8Q

密码: krfc

下一篇:深入浅出Spring IOC(二)

本文分享自微信公众号 - 趣谈编程(qutanbiancheng)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-08-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • slf4j 搭配 log4j2 处理日志

    Log4j + Slf4j 的使用组合最为常见,但是我们知道 Log4j 目前已经停止更新了。Apache推出了新的 Log4j2 来代替 Log4j,Log4...

    海向
  • PowerBI 从矩阵Sparkline揭示SVG图形通用技巧

    近日,PowerBI已经更新为度量值可以支持作为图像URL来进行解析,参考:PowerBI 2018 8月更新 一键导出PDF报告集合,这使得PowerBI在显...

    BI佐罗
  • maven当中如何用SpringMVC和mybatis创建一个项目

    下部我们做一个SpringMVC+mybatis的例子,我们还是继续刚才项目的底子。参见我的mybatis那一章。这个例子的pom.xml照样可以胜任Trans...

    马克java社区
  • maven引入本地jar包的方法

    但是有些情况,比如需要引入第三方包,如快递鸟,支付宝,微信等jar包(当然有可能直接提供maven依赖)

    陈灬大灬海
  • rsync+sersync数据同步

    Author: Andrew Tridgell, Wayne Davison, and others

    胡齐
  • mycat快速搭建入门

    mycat是一个数据库中间件,在此不做多介绍,今天我们直接上入门级的搭建demo。

    GreizLiao
  • Protobuf了解一下?

    Protocol Buffers是Google公司开发的一种数据描述语言,类似于XML能够将结构化数据序列化,可用于数据存储、通信协议等方面。它不依赖于语言和平...

    我被狗咬了
  • Spring 详解(二)------- AOP关键概念以及两种实现方式

    当我们为系统做参数验证,登录权限验证或者日志操作等,为了实现代码复用,我们可能把日志处理抽离成一个新的方法。但是这样我们仍然必须手动插入这些方法,这样的话模...

    海向
  • 如何写出让同事无法维护的代码?

    原文:http://mindprod.com/jgloss/unmain.html

    Rocky0429
  • maven引入本地jar包

    但是有些情况,比如需要引入第三方包,如快递鸟,支付宝,微信等jar包(当然有可能直接提供maven依赖)

    陈灬大灬海

扫码关注云+社区

领取腾讯云代金券