手写Spring中的IOC过程

本文探讨了程序耦合的概念,包括类与方法间的依赖,以及如何通过解耦合降低这种依赖,特别是在实际开发中采用编译期不依赖,运行时才依赖的策略。文章还详细介绍了使用反射和配置文件来提高代码灵活性的方法,并通过手写Spring的IOC过程展示了如何在控制层、DAO层和V层实现解耦。

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


程序的耦合和解耦合

1、程序的耦合:程序间的依赖关系

2、分类:

  • 类之间的依赖
  • 方法间的依赖

3、解耦合:降低程序间的依赖关系

实际开发中应该做到:编译期不依赖,运行时才依赖。

这里给大家举个例子,我们之前学习的JDBC的过程。OK,看图。

在这里插入图片描述

  • 过程1:如果用过程1这种方式创建驱动,那么必须拥有com.mysql.cj.jdbc这个实体类,如果你不写,那编译你都通过不了,编译器会直接告诉你错误。这个就是在编译期依赖
  • 过程2:用过程2这种方式,你只需要给类加载器提供一个字段而已,即使你写错了,随便写的,编译的时候也可以过,只不过是运行时期给你抛出异常,但是这个是运行时异常,只在运行时依赖

解决方式:

​第一步:使用反射创建对象,而避免使用new关键字,上面两者的区别,一个依赖具体的驱动类,一个只是依赖字符串而已,就算运行不了也是包没有导入的原因。

第二步:通过读取配置文件来获取要创建的对象的全限定类名,因为像上面这样子写,直接就写死了,后期如果想换其他数据库就不能更改,所以用配置文件来会更加的灵活。



手写Spring的IOC过程

1、控制层

①控制层接口

/**
 * 控制层的接口
 * */
 public interface IAccountService {

    /**
     * 模拟保存账户
     * */
    void saveAccount();
 }

②控制层实现类

import com.itheima.dao.IAccountDao;
import com.itheima.factory.BeanFactory;
import com.itheima.service.IAccountService;

//账户的控制层实现类
public class AccountServiceImpl implements IAccountService {
	//创建Dao层的对象
    private IAccountDao accountDao = (IAccountDao) BeanFactory.getBean("accountDao");		

    public void saveAccount() {
    //调用Dao层对象的具体操作方法
        accountDao.saveAccount();
    }
}

2、Dao层

①Dao层接口

package com.itheima.dao;

//账户Dao层接口
public interface IAccountDao {
    void saveAccount();
}

②Dao层实现类

import com.itheima.dao.IAccountDao;

//账户的Dao层实现类
public class AccountDaoImpl implements IAccountDao {
	
	//模拟保存账户,Dao层的具体方法,将来被控制层调用
    public void saveAccount() {
        System.out.println("保存了账户");
    }
}

3、V层

V层实现类

import com.itheima.factory.BeanFactory;
import com.itheima.service.IAccountService;

//模拟一个表现层,用于调用控制层       V层
public class Client {

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            IAccountService as = (IAccountService)BeanFactory.getBean("accountService");
            System.out.println(as);
        }
    }
}

4、配置文件

这里我用的配置文件是properties

accountService=com.itheima.service.impl.AccountServiceImpl
accountDao=com.itheima.dao.impl.AccountDaoImpl

5、BeanFactory

/**
 * 是一个创建Bean对象的工厂
 * Bean:可重用组件
 * JavaBean:Java语言编写可重用组件
 * JavaBean  > 实体类
 * Bean工厂就是创建我们的service和dao对象的
 *
 * */
public class BeanFactory {

    //定义一个Properties对象
    private static Properties props;
    
    //使用静态代码块为Properties对象赋值
    static {
        try {
            //实例化对象
            props = new Properties();
            //获取properties文件的流对象
            InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
            props.load(in);
			}
        } catch(Exception e) {
            throw new ExceptionInInitializerError("初始化properties失败");
        }
    }

    /**
     *  根据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();
        }
        return bean;
    }
}

打印结果

com.itheima.service.impl.AccountServiceImpl@74a14482
com.itheima.service.impl.AccountServiceImpl@1540e19d
com.itheima.service.impl.AccountServiceImpl@677327b6
com.itheima.service.impl.AccountServiceImpl@14ae5a5
com.itheima.service.impl.AccountServiceImpl@7f31245a

这里我们拿到的对象都是多例的,而实际中我们想要单例对象,这里我们这样修改。

6、单例模式下的BeanFactory

/**
 * 是一个创建Bean对象的工厂
 * Bean:可重用组件
 * JavaBean:Java语言编写可重用组件
 * JavaBean  > 实体类
 * Bean工厂就是创建我们的service和dao对象的
 *
 * */
public class BeanFactory {

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

    //使用静态代码块为Properties对象赋值
    static {
        try {
            //实例化对象
            props = new Properties();
            //获取properties文件的流对象
            InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
            props.load(in);
            //实例化我们的容器
            beans = new HashMap<String, Object>();
            //取出配置文件中所有的key
            Enumeration keys = props.keys();
            //遍历枚举
            while(keys.hasMoreElements()) {
                //取出每个key
                String key = keys.nextElement().toString();
                //根据key获取value
                String beanPath = props.getProperty(key);
                //反射创建对象
                Object value = Class.forName(beanPath).newInstance();
                //把key和value存入容器中
                beans.put(key,value);
            }
        } catch(Exception e) {
            throw new ExceptionInInitializerError("初始化properties失败");
        }
    }

    /**
     * 根据名称获取对象
     * */
    public static Object getBean(String beanName) {
        return beans.get(beanName);
    }

}

打印结果

com.itheima.service.impl.AccountServiceImpl@74a14482
com.itheima.service.impl.AccountServiceImpl@74a14482
com.itheima.service.impl.AccountServiceImpl@74a14482
com.itheima.service.impl.AccountServiceImpl@74a14482
com.itheima.service.impl.AccountServiceImpl@74a14482

这样我们就拿到了单例对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值