Spring框架2:程序解耦和控制反转(IOC)

本系列笔记均是对b站教程https://www.bilibili.com/video/av47952931 的学习笔记,非本人原创

SpringMVC是表现层的框架,MyBatis是持久层框架

Spring是EE开发的一站式框架:有EE开发每一层的解决方案。以IOC(反转控制)和AOP(面向切面编程)为内核,同时提供了展现层Spring MVC赫尔持久层Spring JDBC等企业级应用技术,是使用最多的JAVA EE开源框架

  • WEB:SpringMVC
  • Service:Bean管理,Spring声明式管理
  • DAO层:Jdbc模板、ORM模块

Spring的优点:

  • 轻量,方便解耦,简化开发
  • 控制反转(Ioc)
  • 面向切面 (AOP)
  • 声明式事务的支持
  • 方便程序的测试
  • 可以集成其他框架
  • 降低Java EE API使用难度(封装了)

Spring:

  • docs:开发规范与API
  • libs:SPring的开放.jar包和源码
  • Schema:配置文件的约束

core container:是spring的IOC部分,所有的spring应用都要基于这个核心容器

程序间的耦合和解耦

用一个例子来说明程序的耦合

package com.jiading.jdbc;

import java.sql.*;

public class JDBCDemo1 {
    /*
    用JDBC来讲解程序的耦合
    这里举的是程序间的依赖关系的例子(类之间的依赖、方法间的依赖)
     解耦:降低程序间的依赖关系
     */
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        //1.注册驱动
        //在编译期就要依赖其他的程序,它的依赖性是很差的
        //实际开发时,应该做到:编译期不依赖,运行期才依赖
        //解决思路:
        /*
        使用反射来创建对象,避免使用new关键词
        读取配置文件来获取要创建的对象全限定类名
         */
        //DriverManager.registerDriver(new com.mysql.jdbc.Driver());
        Class.forName("com.mysql.jdbc.Driver");
        //2. 获取连接
        Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/jd_learning","root","<密码>");
        //3. 获取操作数据库的预处理对象
        PreparedStatement pstm=conn.prepareStatement("select * from account");
        //4. 执行SQL,得到结果集合
        ResultSet rest=pstm.executeQuery();
        //5. 遍历结果集合
        while(rest.next()){
            System.out.println(rest.getString("name"));
        }
        //6. 释放资源
        rest.close();
        pstm.close();
        conn.close();
    }
}

使用工厂设计模式进行解耦

这是标准的工厂设计模式模板,接口和实现类分开,可以参考下:
IAccountDAO:

package com.jiading.dao;
/*
账户的持久层接口
 */
public interface IAccountDAO {
    /*
    模拟保存账户
     */
    void saveAccount();
}

AccountDAOImpl:

package com.jiading.dao.impl;

import com.jiading.dao.IAccountDAO;

public class AccountDAOImpl implements IAccountDAO {
    /*
    模拟保存
     */
    public void saveAccount() {
        System.out.println("保存了账户");
    }
}

IAccountService:

package com.jiading.service;

public interface IAccountService {
    /*
    模拟保存账户
     */
    void saveAccount();
}

AccountServiceImpl:
package com.jiading.service.impl;

import com.jiading.dao.IAccountDAO;
import com.jiading.dao.impl.AccountDAOImpl;
import com.jiading.factory.BeanFactory;
import com.jiading.service.IAccountService;

/
账户的业务层实现类
/
public class AccountServiceImpl implements IAccountService {
//new使得代码有依赖性,独立性差,需要随着依赖的对象的修改而修改
//private IAccountDAO accountDAO = new AccountDAOImpl();

//可以修改为:
private IAccountDAO accountDAO = (IAccountDAO)BeanFactory.getBean("accountDao");
public void saveAccount() {
    accountDAO.saveAccount();
}

}
Client:java
package com.jiading.ui;

import com.jiading.factory.BeanFactory;
import com.jiading.service.IAccountService;
import com.jiading.service.impl.AccountServiceImpl;

/
模拟一个表现层,用于调用业务层
/
public class Client {
public static void main(String[] args) {
//new产生了依赖关系,使得代码的独立性差
//IAccountService as=new AccountServiceImpl();

    //可以改造为:
    IAccountService as= (IAccountService)BeanFactory.getBean("accountService");
    as.saveAccount();
}

}
BeanFactory:java
package com.jiading.factory;

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/*
一个Bean对象的工厂
Bean:在计算机英语中,有可重用组件的含义
JavaBean > 实体类,javabean是用java语言编写的可重用组件
它就是创建我们的service和dao对象的

  1. 需要一个配置文件来配置service和dao
    配置的内容:全限定类名和对应的唯一标志
    配置文件可以是xml或者是properties
  2. 通过读取配置文件中配置的内容,反射创建bean对象
    */
    public class BeanFactory {
    //定义一个Properties对象
    private static Properties props;

    //定义一个Map,用于存放我们要创建的对象,我们把它称之为容器
    private static Map<String,Object> beans;

    //使用静态代码块为Properties对象赋值
    static {
    //还是用了new关键字,但是这次依赖的是Java中的模块而不是我们自己写的了,这就是进步
    //依赖只能降低而不能消除,不能在编程时候一个new关键字不用

     try {
         //1.实例化对象
         props = new Properties();
         //获取properties文件的流对象
         //在resources下的文件在部署时会被放置在根路径下,所以不需要写包名
         InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
         props.load(in);
    
         beans=new HashMap<String, Object>();
         Enumeration keys = props.keys();
         //遍历枚举
         while(keys.hasMoreElements()){
             String key=keys.nextElement().toString();
             //根据key获取value
             String beanPath=props.getProperty(key);
             //反射创建对象(也就是在初始化环节中在容器中分别创建一个对象以供之后调用,也就是单例模式
             Object value=Class.forName(beanPath).newInstance();
             //存入容器,以供调用
             beans.put(key,value);
         }
    
     } catch (IOException e) {
         throw new ExceptionInInitializerError("初始化properties失败");
     } catch (IllegalAccessException e) {
         e.printStackTrace();
     } catch (InstantiationException e) {
         e.printStackTrace();
     } catch (ClassNotFoundException e) {
         e.printStackTrace();
     }

    }

    /
    根据Bean的名称获取bean对象
    /
    public static Object getBean(String beanName) {
    /Object bean=null;
    try {
    String beanPath = props.getProperty(beanName);
    bean = Class.forName(beanPath).newInstance();
    }catch (Exception e){
    e.printStackTrace();
    }
    /
    //有了容器后,就有了更方便的getBean方法

     return beans.get(beanName);

    }
    }
    bean.properties:properties
    accountService=com.jiading.service.impl.AccountServiceImpl
    accountDao=com.jiading.dao.impl.AccountDAOImpl
    ```
    现在我们正式使用spring框架,由spring创建框架。这里的配置文件就选择xml

    IOC

    控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

pom.xml

<?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>org.example</groupId>
    <artifactId>spring_day01_xmlSpring</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
    </dependencies>
</project>

Client:

package com.jiading.ui;

import com.jiading.dao.IAccountDAO;
import com.jiading.service.IAccountService;
import com.jiading.service.impl.AccountServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/*
模拟一个表现层,用于调用业务层
 */
public class Client {
    /*
    获取spring的IOC核心容器,并根据ID获取对象
     */
    public static void main(String[] args) {
        //1. 获取核心容器对象
        ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");
        //2.根据id获取bean对象
        IAccountService as=(IAccountService)ac.getBean("accountService");
        //除了获取Object对象自己再强制转换,也可以直接在getBean的时候就传入类型
        IAccountDAO adao=ac.getBean("accountDAO",IAccountDAO.class);
        System.out.println(as);
        System.out.println(adao);
        //这样获取的对象是单例的
        //as.saveAccount();
    }
}

bean.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标签表示 -->
    <bean id="accountService" class="com.jiading.service.impl.AccountServiceImpl"></bean>
    <bean id="accountDAO" class="com.jiading.dao.impl.AccountDAOImpl"></bean>
</beans>

创建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">
    <!--把对象的创建交给spring来管理,每一项由一个bean标签表示 -->
    <bean id="accountService1" class="com.jiading.service.impl.AccountServiceImpl"></bean>
    <!-- spring对bean的管理细节
     1. 创建bean的三种方式
        1. 使用默认构造函数创建:
            在配置文件中使用bean标签,配以id和class属性后,且没有其他属性和标签时,采用的就是默认构造函数创建
            此时如果类中没有默认的、无参的构造函数,则无法创建
        2. 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象并存入spring容器)
            有时候要引用一个jar包中的类,我们无法修改原有的默认构造函数,而我们想获取的不是这个类本身(往往这样的类只是个工厂类,我们需要的是工厂的商品)
        3. 使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)

     2. bean对象的作用范围
     3. bean对象的生命周期
     -->
    <!-- 2. 使用普通工厂中的方法创建对象-->
    <bean id="InstanceFactory" class="com.jiading.factory.InstanceFactory"></bean>
    <bean id="accountService" factory-bean="InstanceFactory" factory-method="getInstanceFactory"></bean>
    <!-- 一目了然,是吧-->
    <!-- 使用工厂中的静态方法创建对象-->
    <bean id="accountService2" class="com.jiading.factory.StaticFactory" factory-method="getInstanceFactory"></bean>
    <!-- Bean的作用范围调整
        bean标签的scope属性:用于指定bean的作用范围
        取值:
            singleton:单例,也是默认值,常用
            prototype:多例,常用
            request:作用于web应用的请求范围
            session:作用于web应用的会话范围
            global-session:作用于集群环境的会话范围(全局会话范围),如果不是集群的话和session等效
    -->
    <!-- Bean对象的生命周期
        在类中添加init()和destory()方法,然后在bean标签中加上init-method和destory-method,就实现了由框架调用对象的构造函数和析构函数
        单例对象:在配置文件解析完、容器创建后就创建,一直保存在容器存在时,随着容器销毁而销毁
            但是如果是在main函数直接调用、不手动使用close()关闭容器的话,对象会因为程序执行完成而被自动回收内存,不能调用销毁函数。所以要销毁的话,需要手动调用clsoe方法来关闭容器
            但是ApplicationContext类是没有close方法的,要销毁容器的话需要直接创建子类ClassPathXmlApplicationContext的对象,也即:
            ClassPathXmlApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");
        多例对象:
            对象只要在使用过程中就一直存活,而当对象长时间没有使用且没有别的对象引用该对象时,由java的垃圾回收器回收
    -->
</beans>

原文地址:https://www.cnblogs.com/jiading/p/12368638.html

时间: 2024-11-07 23:50:27

Spring框架2:程序解耦和控制反转(IOC)的相关文章

依赖耦合、解耦、控制反转(IOC)、依赖注入

随着net的深入学习,出现了很多概念性的东西需要理解,现在统一记录一下. 1.依赖:现阶段在任何一个有请求作用的系统,都会出现A类调用B类的情况,这时候A类就依赖于B类,A类和B类存在依赖关系. 2.耦合.解耦:A类依赖于B类,这时对B类调用,一般通过A a=new B();的形式,不过这个时候如果B类重构(例如:增加了一个参数param1),要保证A类的正确使用,则必须重新new:A a=new B(param1); 则此时A类和B类就是耦合关系.不过带来了很多的不方便之处,如果B类频繁变动,

Spring.NET 控制反转(IoC)和环境配置

using System; using System.Collections.Generic; using System.Linq; using System.Text; using Spring.Context; using Spring.Context.Support; using Common.Logging; namespace Test2 { /// <summary> /// 在学习Spring.NET这个控制反转(IoC)和面向切面(AOP)的容器框架之前,我们先来看一下什么是控

[ASP.NET Core 3框架揭秘] 依赖注入:控制反转

ASP.NET Core框架建立在一些核心的基础框架之上,这些基础框架包括依赖注入.文件系统.配置选项和诊断日志等.这些框架不仅仅是支撑ASP.NET Core框架的基础,我们在进行应用开发的时候同样会频繁地使用到它们.对于这里提到的这几个基础框架,依赖注入尤为重要.ASP.NET Core应用在启动以及后续针对请求的处理过程中,它会依赖各种的组件提供服务.为了便于定制,这些组件一般会以接口的形式进行"标准化",我们将这些标准化的组件统一称为"服务(Service)"

控制反转IOC与依赖注入DI

1. IoC理论的背景我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑. 图1:软件系统中耦合的对象 如果我们打开机械式手表的后盖,就会看到与上面类似的情形,各个齿轮分别带动时针.分针和秒针顺时针旋转,从而在表盘上产生正确的时间.图1中描述的就是这样的一个齿轮组,它拥有多个独立的齿轮,这些齿轮相互啮合在一起,协同工作,共同完成某项任务.我们可以看到,在这样的齿轮组中,如果有一个齿轮出了问题,就可能会影响到整个齿轮组

控制反转IOC与依赖注入DI - 理论篇

学无止境,精益求精 十年河东十年河西,莫欺少年穷 昨天是五一小长假归来上班的第一天,身体疲劳,毫无工作热情.于是就看看新闻,喝喝茶,荒废了一天 也就在昨天,康美同事张晶童鞋让我学习下IOC的理论及实现,毕竟是之前的好同事,好朋友,我也就抽时间百度了很多资料 在查阅网上资料的过程中,我发现大多技术篇幅都是IOC的代码实现,并没有一篇介绍IOC理论的篇幅!这显然不是我想要的. 我知道要想搞明白IOC,就必须要弄明白什么是IOC(控制反转)?为什么叫IOC(控制反转)?为什么之后又可以称为DI(依赖注

【串线篇】依赖注入DI与控制反转IOC

DI&IOC 在spring框架中DI与IOC说的其实是一回事 一句话:本来我接受各种参数来构造一个对象,现在只接受一个参数——已经实例化的对象. 也就是说我对对象的『依赖』是注入进来的,而和它的构造方式解耦了.构造它这个『控制』操作也交给了第三方,也就是控制反转IOC. 优势:在应用程序中的组件需要获取资源时,传统的方式是组件主动的从容器中获取所需要的资源,在这样的模式下开发人员往往需要知道在具体容器中特定资源的获取方式,增加了学习成本,同时降低了开发效率.反转控制的思想完全颠覆了应用程序组件

什么是控制反转IOC

1.IOC 是什么 IOC- Inversion of Control , 即"控制反转" ,不是一个技术,而是一个设计思想,在java 开发中,IOC意味着将你设计好的Java 对象交个容器控制,而不是传统的在你的对象内部直接控制,想要理解好IOC ,关键是要明确" 谁控制谁,控制什么,为何是反转,什么反转了?" * 谁控制谁,控制什么: 在传统的 Java SE 设计中,我们直接在java 对象的内部通过new 进行创建对象,是程序自动的去创建对象,而 IOC

【Java_Spring】控制反转IoC(Inversion of Control)

1. IOC的概念 控制反转IoC(Inversion of Control)是一种设计思想,而DI(依赖注入)是实现IoC的一种方法.在没有使用IOC的程序中,对象间的依赖关系是靠硬编码的方式实现的.引入IOC后对象的创建由程序自己控制的,控制反转即将对象的创建交给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了. IoC是Spring框架的核心内容,在IOC容器中一切对象皆为Bean组件.IOC容器通过读取XML配置文件中的Bean信息,产生每个Bean实例.使用多种方式完美的实现

C#依赖注入控制反转IOC实现详解

原文:C#依赖注入控制反转IOC实现详解 IOC的基本概念是:不创建对象,但是描述创建它们的方式.在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务.容器负责将这些联系在一起. 举个例子,组件A中有类ClassA,组件B中有接口IB和其对应的实现类B1和B2. 那么,现在ClassA需要利用IB接口来做一些事情,例如: public class ClassA { public void DoSomething() { IB b = ??? b.DoWork(); }} 现