SpringIOC-解决层与层对象之间的高耦合问题

本文详细介绍了SpringIOC的作用,如何通过构造器、属性注入和工厂模式创建对象,以及依赖注入DI的概念和实现,旨在解决层与层之间的高耦合问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、SpringIOC 的介绍与学习

1.SpringIOC的介绍

问题:
在使用MVC的结构体系来完成后台功能代码的声明时,在一定程度上降低了代码的冗余,但是层与层之间的耦合性过高,造成代码升级维护特别麻烦,比如,某天业务层某个类文件需要替换为新的类文件,那么,控制层所有调用该业务类的代码需要全部修改为调用新的业务类.
解决:
将层与层对象之间的关系进行解耦,由直接变为间接.
实现:
SpringIOC.作用:实现了代码层与层之间的解耦.

2.SpringIOC的原理

在这里插入图片描述

3. SpringIOC的使用

1. 作用:
IOC将耦合性非常高的对象进行解耦.
2. 时机:
什么时候使用IOC对对象进行解耦是一个主观问题,应当根据代码的结构以及功能的需求进行分析,然后决定哪些对象之间需要使用IOC解耦.一般情况下,在MVC代码结构中,会将Servlet和Service之间解耦,Service和mapper之间解耦.
3. 使用流程:
①创建Maven的war项目然后配置web的相关依赖以及项目结构的配置
注意:
如果我们使用Idea重新创建一个新的工作空间,则需要重新完成Maven的 集成。集成步骤参照Maven的知识。


在这里插入图片描述

②在pom.xml文件中配置SpringIOC的依赖


在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.bjsxt</groupId>
  <artifactId>01_SpringIOC_BaseUse</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>
  <!--配置版本号-->
  <properties>
    <servlet-version>3.1.0</servlet-version>
    <jsp-version>2.2</jsp-version>
    <jstl-version>1.2</jstl-version>
  </properties>

 <!--配置依赖-->
    <dependencies>
      <!--配置SpringIOC的依赖-->
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.11.RELEASE</version>
      </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.3</version>
        </dependency>
        <!--配置web开发相关的依赖-->
      <!--servlet的资源坐标-->
      <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>${servlet-version}</version>
        <scope>provided</scope>
      </dependency>
      <!--jsp的资源坐标-->
      <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>${jsp-version}</version>
        <scope>provided</scope>
      </dependency>
      <!--jstl的资源坐标-->
      <dependency>
        <groupId>jstl</groupId>
        <artifactId>jstl</artifactId>
        <version>${jstl-version}</version>
      </dependency>

    </dependencies>
  <!--配置tomcat插件-->
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <port>8080</port><!--配置tomcat启动的端口号-->
          <path>/ioc</path><!--配置项目的访问名称-->
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

③在resources下创建并配置applicationcontext.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">
    <!--配置要让Spring容器对象通过反射创建的对象的权限定路径:业务层对象-->
    <bean id="us" class="com.bjsxt.service.impl.UserServiceImpl2"></bean>
</beans>

④在业务层中创建UserService接口及其实现类
UserService接口:

package com.bjsxt.service;
public interface UserService {
    //声明功能方法
    String testIOCService();
}

UserServiceImpl实现类:

package com.bjsxt.service.impl;
import com.bjsxt.service.UserService;
public class UserServiceImpl implements UserService {
    //测试IOC
    @Override
    public String testIOCService() {
        return "SpringIOC  Study";
    }
}

⑤在项目中创建MVC的包结构,并创建IOCServlet,并在Service方法中获取Spring的容器对象,并从容器对象中获取业务层对象,完成业务操作。

package com.bjsxt.controller;
import com.bjsxt.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/ioc")
public class IOCServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置请求编码格式
        //设置响应编码格式
        //获取请求信息

        //处理请求
            //创建Spring的容器对象
            ApplicationContext ac=new ClassPathXmlApplicationContext("applicationcontext.xml");
            //获取容器中的业务层对象
            UserService us = (UserService) ac.getBean("us");
            //处理请求
            String s = us.testIOCService();
        //响应结果
            resp.getWriter().write(s);
    }
}

二、SpringIOC创建对象的三种方式

1. 问题及解决

问题:
在学习了SpringIOC的基本使用流程后,我们使用IOC解耦层与层之间的逻辑关系,但是我们发现,对象由以前我们自己根据需求在代码中直接new创建,变为从Spring容器中获取,也就说对象的创建由Spring容器来创建,我们直接获取使用即可.那么,如果我们需要一个带有指定的初始化数据的对象,如何让Spring容器对象帮我们创建呢?
解决:
在applicationcontext.xml配置文件中,配置对象的创建方式以及初始化的方式.

2. 通过构造器方式

①无参数构造器(创建一个没有初始化数据的对象)
②有参 数构造器(创建一个带有初始化数据的对象)
applicationcontext.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对象-->
    <!--构造器方式-->
    <!--
    无参构造器 
    特点:Spring容器默认使用无参构造方式创建对象
    使用:在配置文件中直接使用bean标签配置即可,无需过多声明
    -->
    <bean id="stu" class="com.bjsxt.pojo.Student"></bean>
    <!--有参数的构造器
    特点:Spring容器对根据配置调用的有参构造器创建一个带有初始化数据的对象
    使用:constructor-arg:使用bean的字标签来声明调用的构造器的形参的个数
    一个字标签表示一个参数
    属性:index:参数的下标
          type:参数的类型,全限定路径
          name:参数的形参名
          value:参数要给的值
    -->
    <bean id="stu2" class="com.bjsxt.pojo.Student">
        <constructor-arg index="0" type="java.lang.Integer" name="sid" value="1"></constructor-arg>
        <constructor-arg index="1" type="java.lang.String" name="sname" value="张三"></constructor-arg>
    </bean>  
</beans>

TestObject代码示例:

package com.bjsxt.controller;
import com.bjsxt.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class testStu {
    public static void main(String[] args) {
        //创建容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext.xml");
        //获取容器中的对象
        //无参构造器方式
        Student student = (Student) ac.getBean("stu");
        System.out.println("无参构造:"+student);
        //有参构造器
        Student student1= (Student) ac.getBean("stu2");
        System.out.println("有参构造:"+student1); 
    }
}

3.通过属性注入(get/set)

先通过空构造器创建一个对象,然后再使用set方法进行初始化赋值.
applicationContext.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对象-->
    <!--
    属性注入方式
    特点:相当于创建一个空对象然后使用set方法赋值
    使用:
    property:在bean标签下使用子标签property,表示调用set方法给某个属性赋值
    属性:name:要赋值的属性名
          value:值
    -->
    <bean id="stu3" class="com.bjsxt.pojo.Student">
        <property name="sid" value="2"></property>
        <property name="sname" value="李四"></property>
    </bean>
</beans>

TestObject代码示例:

package com.bjsxt.controller;
import com.bjsxt.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * @author wuyw2020
 * @date 2020/1/8 15:16
 */
public class testStu {
    public static void main(String[] args) {
        //创建容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext.xml");
        //获取容器中的对象
        //属性注入方式
        Student student = (Student) ac.getBean("stu3");
        System.out.println("属性注入方式"+student);
    }
}

4. 通过工厂模式

问题:
我们在使用Java代码处理某个问题的时候,需要创建A对象,调用 A对象中的某个方法,但是A对象的创建依赖B对象,而B对象的创建又依赖于C对象,C对象的创建又依赖于D对象…,如下:
D d=new D();
C c=new C(d);
B b=new B©;
A a=new A(b);
这样造成,代码的阅读性极差
解决:
将对象的创建过程进行封装,直接返回创建好的对象使用.
实现:
工厂设计模式
本质:
就是封装对象的创建过程的一种代码的编程思想
静态工厂:
生产对象的方法是静态方法

public class AFactory{
	public static A newInstance(){
	D d=new D();
	C c=new C(d);
	B b=new B(c);
	A a=new A(b);
	return a;
	}
}

动态工厂:
生产对象的方法是非静态方法

public class AFactory{
	public A newInstance(){
	D d=new D();
	C c=new C(d);
	B b=new B(c);
	A a=new A(b);
	return a;
	}
}

SpringIOC使用工厂创建对象:
传统方案:
我们自己创建工厂,然后调用工厂生产对象的方法,获取生产的对象,然后使用生产的对象完成功能开发.
IOC方案:
Spring容器创建工厂,并自动调用其创建的工厂的生产对象的方法,生产的对象直接存储在Spring容器中,我们直接从Spring容器中获取对象,完成功能开发.
①动态工厂模式
②静态工厂模式

applicationcontext.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对象-->
    <!--工厂设计模式-->
    <!--动态工厂-->
        <bean id="factory" class="com.bjsxt.pojo.StudentFactory"></bean>
        <!--生产Student对象-->
        <bean id="stu4" factory-bean="factory" factory-method="newIntance"></bean>
    <!--静态工厂-->
    <!--可以理解为静态方法直接用类名调用-->
        <bean id="stu5" class="com.bjsxt.pojo.StudentFactory2" factory-method="newIntance"></bean>
</beans>

TestObject示例:

package com.bjsxt.controller;
import com.bjsxt.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class testStu { 
    public static void main(String[] args) {
        //创建容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext.xml");
        //获取容器中的对象
        //工厂设计模式     
            //动态工厂
            Student student = (Student) ac.getBean("stu4");
            System.out.println("动态工厂:"+student);
            //静态工厂
            Student student1 = (Student) ac.getBean("stu5");
            System.out.println("静态工厂:"+student1);
    }
}

三、IOC的依赖注入DI

1. 依赖注入DI的介绍

问题:
在学习了使用IOC创建对象的三种方式后,可以根据需求在applicationcontext.xml文件中配置对象的创建方式.但是目前不管是属性注入方式,还是构造器方式,创建对象的时候,赋值赋予的都是基本类型的数据.但是对象中还有引用类型的属性,比如A对象中有属性B,我希望从Spring容器中获取一个B属性有值的A对象,怎么办?
对象之间的依赖关系:
我们在设计类对象时,会在类中声明其他类类型的属性,来调用其他类的资源完成当前类的功能处理,比如A类中声明B属性,在A类中就可以直接调用B类的资源完成A类的功能开发,但是A 对象被创建时,其B属性必须有值,否则空指针异常,我们将此种也就是A和B的关系称为对象之间的依赖关系(A依赖B).
依赖链:
对象之间项目依赖形成的一条链式依赖关系.
D d=new D();
C c=new C(d);
B b=new B©;
A a=new A(b);
A<—B<----C<----D
解决:
让Spring容器根据对象之间的依赖关系,将依赖责任连上的所有的对象全部配置为Bean对象.并且根据依赖关系完成对象之间的组装.将组装好的对象返回给用户使用.
概念:
DI依赖注入:就是Spring容器根据对象之间的依赖关系完成对象的创建以及组装的过程.

2… DI依赖注入的代码实现

  1. applicationcontext.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">
<!--
DI依赖的使用流程
①将依赖责任链上的所有的对象都配置为bean
②根据依赖关系完成对象之间的组装配置
     通过构造器方式:
         i.必须在类中声明对应的构造器
         ii.在bean标签下使用constructor-arg子标签完成以来注入
               使用constructor-arg的属性ref,ref的值为要注入的bean的ID
     通过set方法方式
          i.必须在类中声明引用属性对应的set方法
          ii.在bean标签下使用property子标签完成以来注入
               在property子标签中使用ref属性,属性值为要被注入的bean的ID
-->
    <!--配置学生bean对象-->
    <bean id="stu" class="com.bjsxt.pojo.Student">
        <!--构造器方式-->
        <!--<constructor-arg index="0" name="teacher" type="com.bjsxt.pojo.Teacher" ref="tea" ></constructor-arg>-->
        <!--set方式-->
        <property name="teacher" ref="tea"></property>
        <property name="sname" value="张三"></property>
        <property name="sid" value="1"></property>
    </bean>
    <bean id="tea" class="com.bjsxt.pojo.Teacher">
        <property name="tid" value="2"></property>
        <property name="tname" value="刘老师"></property>
    </bean>
</beans>
  1. TestIocDI代码示例
package com.bjsxt.contorller;
import com.bjsxt.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * @author wuyw2020
 * @date 2020/1/8 20:04
 */
public class TestIocDI {
    public static void main(String[] args) {
        //获取spring对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext.xml");
        Student stu = (Student) ac.getBean("stu");
        System.out.println(stu);
        stu.testStu();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值