Spring解析(上篇)IOC解析

本文深入介绍了Spring框架,包括其作为轻量级容器的特性,核心模块如IOC和AOP,以及如何通过配置文件管理Bean。通过示例展示了如何使用Spring实现Bean的依赖注入,配置有参构造方法,复杂属性注入,以及多模块配置。Spring通过降低组件间的耦合,提供事务管理等服务,成为企业级应用的常用框架。
摘要由CSDN通过智能技术生成

Spring解析


一、Spring是什么?

关于这个问题,咱们不妨先看看百度中如何描述:

Spring框架是一个开放源代码的J2EE应用程序框架,由Rod Johnson发起,是针对bean的生命周期进行管理的轻量级容器(lightweight container)。 Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强大IOC、AOP及Web MVC等功能。Spring可以单独应用于构筑应用程序,也可以和Struts、Webwork、Tapestry等众多Web框架组合使用,并且可以与 Swing等桌面应用程序AP组合。因此, Spring不仅仅能应用于J2EE应用程序之中,也可以应用于桌面应用程序以及小应用程序之中。Spring框架主要由七部分组成,分别是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 Spring Web MVC。

由上我们可以得知:

  • Spring是一个开源框架。并且是在2002年被一个名叫Rod Johnson的人创建的。创建的目的呢,就是是为了解决企业级开发的复杂性。

  • Spring是一个针对与Baen(组件)进行管理的一个轻量级容器。

  • Spring能够使用基本的JavaBaen来完成以前只能由EJB所完成的事情。

  • 同时呢,Spring还提供了IOC、AOP及Web MVC等强大的功能

  • Spring不仅可以单独应用于构筑应用程序,还可以于其他的框架组合使用

  • Spring由七个部分组成,分别是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 Spring Web MVC。

Spring框架七个组成部分的图解
在这里插入图片描述

在看过百度上的描述后,咱们再来对它进行一些补充


1.Spring的描述

Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架。
在解释这句话之前,咱们先看上面Spring的模块图解,Spring一共具有七个模块,其中最为重要的即是Spring Core,也就是Spring的核心容器,在Spring当中所有模块都是基于Spring的核心容器之上的,所以Spring被称之为容器框架。而IOC与AOP呢,分别是Spring框架中避免依赖的关键技术,也是Spring当中最大的特色,在下文会对这两个技术进行分析。

在Spring当中提供着一种贯穿始终的解决方案,贯穿了视图层,业务逻辑层,甚至到数据访问层,但Spring的核心目的却并不是想着去替代那些专用的框架,而是去整合它们。拿SSM(Spring+SpringMVC+Mybatis)打个比方,Spring在其中的角色就像是一个集成主板,用于将其他的专用框架集成,集成为一个整体。ssh,ssh2等等,都需要使用到Spring框架进行集成。

2.Spring的特点

  • 对主流框架提供了集成支持,如(Mybatis,hibernate,JPA, Struts等)。
  • 降低了Baen之间的耦合度,实现了软件各个层的解耦。
  • 提供了事务管理,消息管理等服务。
  • 将“针对接口编程”的成本降到了最低。
  • Spring大小与开发都是轻量级的。
  • 配件灵活且统一,便于单元测试。

二、Spring核心容器

1.运行时图解

以下是Spring运行时结构图解

在这里插入图片描述

2.核心容器解析

Spring核心容器中包含四个模块:Beans、Core、Context、SpEL

1.Core和Beans提供了整个框架最基础的部分,包括了IoC(控制反转)和DI(依赖注入)。
2.Conetext也就是上下文,它建立在Core和Beans模块提供的基础之上,它提供了框架式访问对象的方式
3.Core、Beans、Context三个模块构成了Spring的骨架
4.SpEL:提供了一种强大的运用于在运行时操作对象的表达式语音。

3.IOC控制反转

IOC(Inversion of Control)控制反转,就是将创建对象的权利,及对象生命周期的管理的过程交给Spring来处理。在之后的开发过程中就不再需要关注对象的创建和生命周期的管理,而是在需要的时候由Spring框架提供。

简单来说就是将原来需要开发人员完成的一个操作,反转过来,交给Spring框架来完成,这个过程呢,就叫做控制反转。

IOC还有一种描述:因为当初对控制反转的概念比较含糊,只能让人联想到通过容器控制对象这一说法,却很难想到到底由谁来维护这个对象的关系,于是便有人提出了DI(Dependency Injection)依赖注入,即由容器动态的将某种依赖关系注入到组件之中。

4.IOC使用示例

示例一

1.使用Maben创建一个Web工程,并将web版本改至3.0或3.1即可。

2.在pom文件中导入Spring框架所需要的依赖
以下是Spring所需的所有依赖

 <!-- ********************** spring依赖 ********************** -->
	<!-- 版本号 -->
	<spring.version>5.0.2.RELEASE</spring.version>


    <!--1)spring核心依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <!--spring ioc依赖 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <!--spring 扩展依赖 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <!--2)spring dao层依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <!--3)aop相关依赖 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <!--4)spring web相关依赖 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <!--5) spring test相关依赖 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>${spring.version}</version>
    </dependency>

3.创建包,用于存放相关的类,详情如下。在这里插入图片描述

4.在resources目录下创建一个spring.xml的配置文件,进行spring的配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">


	
</beans>

5.在model层中创建一个例子的实体类。

代码如下(示例):

public class Example {
    private int eid;

    private Spring ename;

    public int getEid() {
        return eid;
    }

    public void setEid(int eid) {
        this.eid = eid;
    }

    public Spring getEname() {
        return ename;
    }

    public void setEname(Spring ename) {
        this.ename = ename;
    }

    @Override
    public String toString() {
        return "Example{" +
                "eid=" + eid +
                ", ename=" + ename +
                '}';
    }
}

6.在dao层实现一个interface接口,并在接口中写一个List方法,然后再写一个实现类,用于实现这个方法。
代码如下

public interface IExampleDao {

    List<Example> getExample(Example example);

}

由于还未与Mybatis进行集成,在这里先使用模拟数据

public class ExampleDao implements IExampleDao {
    @Override
    public List<Example> getExample(Example example) {
        List<Example> list=new ArrayList<>();

        //模拟数据
        Example exmp = new Example();
        exmp.setEid(1);
        exmp.setEname("例子");

        list.add(exmp);

        return list;
    }
}

7.在service层中调用已经定义的dao层接口,并进行实现。
与实现dao接口没有太多的差异,只要改写下后缀名即可。

public interface IExampleService {

    List<Example> getExample(Example example);

}

实现方法

public class ExampleService implements IExampleService {
    
    private ExampleDao exampleDao;

    public void setExampleDao(ExampleDao exampleDao) {
        this.exampleDao = exampleDao;
    }

    @Override
    public List<Example> getExample(Example example) {
        return exampleDao.getExample(example);
    }
}

在还没有使用Spring之前,使用最原始的方式获取的dao层中已经定义的方法的话,不利于代码的修改,所以就得创建一个Factory工厂类,从而来获取dao层中已经定义的方法,需要修改时直接在工厂中进行修改即可,这样可以降低代码的一个耦合度。

但是在我们使用Spring框架之后,这一步就变得简单起来,直接在service层中声明一个变量即可,因为所谓依赖注入,即是通过外部文件进行注入,外部文件指的则是先前配置的Spring.xml。

8.在Spring配置文件中进行配置,也就是在Spring容器中,获取到需要关系的bean

	<!--获取到dao层已经定义方法的类-->
    <bean id="exampleDao" class="com.spring.dao.ExampleDao">
    </bean>
    
    <!----------------------------------------------------->
	
	 <!--将上边获取到的dao层方法注入到service层中-->
    <bean id="IExampleService" class="com.spring.service.ExampleService">
        <property name="exampleDao">
            <ref bean="exampleDao"></ref>
        </property>
    </bean>	
  • id:在容器中查找Bean的id,不可重复。
  • class:bean的完整类名。
  • name:在容器中bean的名字,不可重复。

在以上代码中,可以看到在代码的中间有一个分隔符,这是为了方便能更通俗的去解释,就是将上边的那个bean注入到下边的那个bean里边。

在没使用Spring框架之前呢,是创建一个Factory工厂在service层中获取dao层中已经定义的方法。而在使用Spring之后呢,就是将这一步交给Spring的配置文件,也就是在Spring上下文(容器)中,在Spring容器之中进行一个注入。

9.随后写一个测试类,通过ApplicationContext获取到Bean,进行测试

public class Test {
    public static void main(String[] args) {
        //获取Spring的配置文件,也就是获取Spring的上下文(容器)
        ApplicationContext ctx= new ClassPathXmlApplicationContext("spring.xml");

        IExampleService iExampleService =(IExampleService) ctx.getBean("IExampleService");
        List<Example> list= iExampleService.getExample(null);

        //Lambda表达式
        list.forEach(t-> System.out.println(t));

    }
}

10.结果

在这里插入图片描述

示例二

在Spring容器之中配置继承关系。

1.创建实体类,在这里咱们先创建两个继承类,一个学生类,和一个人类,由学生类来继承我们的人类。
人类中只需要一个性别即可

public class Person{
    
    private String sex;

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "Student{" +
                "sex='" + sex + '\'' +
                '}';
    }
}

学生类继承人类,并在toString中返回人类中的性别。

public class Student extends Person{

    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                "sex='" + this.getSex() + '\'' +
                '}';
    }
}

3.在创建好两个类之后,咱们开始配置Spring配置文件。

    <bean id="person" class="com.spring.model.Person">
        <!--获取属性民称,进行赋值-->
        <property name="sex">
            <value></value>
        </property>
    </bean>
    
    <bean id="student" class="com.spring.model.Student" parent="person">
        <property name="name">
            <value>张三</value>
        </property>
    </bean>

在这段代码中,可以看到,有两个bean,这两个bean是继承关系,parent是表示父类,第二个bean中标记的则是表示它的父类是parent。

4.进行测试
同样还是通过ApplicationContext获取到bean,进行测试。

ApplicationContext ctx= new ClassPathXmlApplicationContext("spring.xml");
Student student =(Student) ctx.getBean("student");
System.out.println(student);

得出打印结果:
在这里插入图片描述

示例三

1.使用有参的构造方法创建bean。

根据上边的基础,咱们在Student类中加一个有参的方法

    public Student(String name) {
        this.name = name;
    }

接下来就是在Spring中配置他,如果继续使用原来的方式获取bean的话,就会显示报错。
如下图所示
在这里插入图片描述

在这里,我们就需要换一种方式,不再使用property获取name,而是使用constructor-arg获取。
代码如下

    <bean id="student" class="com.spring.model.Student" parent="person">
        <constructor-arg name="name">
            <value>张三</value>
        </constructor-arg>
    </bean>
2.init-method:指定bean的初始化方法。

在方才创建的Student类中加一个init方法

    private void init(){
        System.out.println("------bean的初始化方法------");
    }

在Spring配置文件中,所需要指定初始化方法的bean那里加上init-method,并指定方法。

   <bean id="student" class="com.spring.model.Student" parent="person" init-method="init">
        <constructor-arg name="name">
            <value>张三</value>
        </constructor-arg>
    </bean>

随后便可测试打印即可,还是获取到ApplicationContext中的bean进行测试。
结果如下
在这里插入图片描述

3.复杂属性的配置

1.自定义属性JavaBean属性注入。
在这里咱们需要在方才的基础上再新建一个site地址的实体类。

public class Site {

    private String in;

    public String getIn() {
        return in;
    }

    public void setIn(String in) {
        this.in = in;
    }
}

我们先在上个示例中创建的Student类中添加一个新的属性,属性名与先前创建实体类名一致。这个属性不再是Java中的简单定义类型,而是我们自定义的类型,定义完之后,再生成他的Get与Set方法,并在它的toString方法中加入这个Site中的方法。
以下代码为Student类中所有代码

public class Student extends Person{

    private String name;

    private Site site;

    public Site getSite() {
        return site;
    }

    public void setSite(Site site) {
        this.site = site;
    }

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                "sex='" + this.getSex() + '\'' +
                "in='" + this.site.getIn() + '\'' +
                '}';
    }

    private void init(){
        System.out.println("------bean的初始化方法------");
    }

咱们新建的这个属性的对象需要进行依赖注入,所以肯定得交给Spring来托管,代码如下

    <bean id="site" class="com.spring.model.Site">
        <property name="in">
            <value>长沙</value>
        </property>
    </bean>
   
    <bean id="student" class="com.spring.model.Student" parent="person" init-method="init">
        <constructor-arg name="name">
            <value>张三</value>
        </constructor-arg>
        <property name="site">
            <ref bean="site"/>
        </property>
    </bean>

在Spring容器里面获取到Site里的方法,并给他赋值,然后再放到Student中,打印结果如下。
在这里插入图片描述
2.List或数组的注入。
声明属性,并生成Get与Set方法。

public class Demo {
    private int[] arr;

    private List list;

    public int[] getArr() {
        return arr;
    }

    public void setArr(int[] arr) {
        this.arr = arr;
    }

    public List getList() {
        return list;
    }

    public void setList(List list) {
        this.list = list;
    }
}

在这里咱们是新建了一个demo类,之后便是在Spring容器中通过bean的方式获取到,然后进行配置。

    <bean id="demo" class="com.spring.model.Demo">
        <property name="list">
            <list>
                <value>111</value>
                <value>222</value>
                <value>333</value>
                <value>444</value>
            </list>
        </property>
    </bean>

在Spring容器中通过List标签对它进行赋值,随后便可进行测试。测试数组只需要在获取属性名称将list改为arr即可进行测试。

        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
        Demo demo =(Demo) ctx.getBean("demo");
		//List方法测试
        demo.getList().forEach(t-> System.out.println(t));
            //数组测试
        int[] arr = demo.getArr();
        for (int a:arr){
            System.out.println(a);
        }
    }

3.Map的注入,Spring配置如下。

    <bean id="demo" class="com.spring.model.Demo">
        <property name="map">
            <map>
                <entry key="aa" value="bb"/>
                <entry key="cc" value="dd"/>
                <entry key="ee" value="ff"/>
            </map>
        </property>
    </bean>
4.多模块配置文件

在版本控制软件中也为了减少冲突,系统一般会被分成多个模块,可以为每个模块配置一个配置文件,以便于管理。以下咱们有两个配置文件。

配置文件spring-a.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" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

    <bean id="demo" class="com.spring.model.Demo">
        <property name="map">
            <map>
                <entry key="aa" value="bb"/>
                <entry key="cc" value="dd"/>
                <entry key="ee" value="ff"/>
            </map>
        </property>
    </bean>
</beans>

总配置文件spring.xml,我们只需要在这个总的配置文件中引入上边的分模块即可,在需要使用Spring时,直接获取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" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

	<import resource="spring-a.xml"/>

</beans>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值