暑期自学 Day 15 | Spring (一)

  • 两个内核:反转控制 IoC (Inverse of Control),面向切面编程 AOP (Aspect Oriented Programming)
  • 优势:
    • 方便程序解耦,简化开发过程
    • AOP 编程支持(解决 OOP 实现不了的功能)
    • 声明式事务支持
    • 方便程序测试
    • 方便集成各种框架
    • 降低 JavaEE API 使用难度

解耦

  • 降低耦合

    耦合

  • 程序间的依赖关系
    • 类之间
    • 方法之间
代码解释程序间的耦合

一个模拟存储账户的应用

持久层接口: spring/selflearning/dao/IAccountDao.java

package spring.selflearning.dao;
/*
持久层
 */
public interface IAccountDao {
    /*
        模拟保存账户
     */
    void saveAccount();
}

持久层实现类: spring/selflearning/dao/impl/AccountDaoImpl.java

package spring.selflearning.dao.impl;

import spring.selflearning.dao.IAccountDao;

/*
账户持久层实现类
 */
public class AccountDaoImpl implements IAccountDao {

    public void saveAccount() {
        System.out.println("保存了账户");
    }
}

业务层接口: spring/selflearning/service/IAccountService.java

package spring.selflearning.service;
public interface IAccountService {
 /*
  业务层接口
 */
 void saveAccount();
}

业务层实现类: spring/selflearning/service/impl/AccountServiceImpl.java
此处由于需要通过新建对象的方式调用持久层,所以与持久层有依赖关系,一旦持久层被更改,程序将报错。

package spring.selflearning.service.impl;

import spring.selflearning.dao.IAccountDao;
import spring.selflearning.dao.impl.AccountDaoImpl;
import spring.selflearning.service.IAccountService;

/*
账户业务层实现类
 */
public class AccountServiceImpl implements IAccountService {

    // 业务层调用持久层
    private IAccountDao accountDao = new AccountDaoImpl(); // 业务层由于new了持久层实现类,具有强耦合性

    public void saveAccount() {
        accountDao.saveAccount();
    }
}

表现层: spring/selflearning/ui/Client.java
表现层也需要新建业务层对象,所以有依赖关系。

package spring.selflearning.ui;

import spring.selflearning.dao.IAccountDao;
import spring.selflearning.service.IAccountService;
import spring.selflearning.service.impl.AccountServiceImpl;

/*
模拟表现层,用于调用业务层
 */
public class Client {
    public static void main(String[] args) {
        IAccountService as = new AccountServiceImpl(); // 表现层由于new了业务层实现类,具有强耦合性
        as.saveAccount();
    }
}

解耦的思路

  • 用反射创建对象,避免使用 new 关键字
  • 读取配置文件获取要创建的对象全限定类名 (方便更改依赖包)
使用工厂模式解耦
  • 工厂模式做了什么?
    • 为了解耦,我们使用一个创建 Bean 对象的工厂
    • Bean 是可重用组件,持久层可以被业务层重用,业务层可以被表现层重用,因此在上面的代码示例中可以创建业务层和持久层对象
      • 步骤:使用一个配置文件配置service和dao,然后通过读取配置文件内容反射创建对象。配置文件(.xml 或 .properties)的内容是 service 和 dao 的全限定类名。

利用工厂模式读取配置代码示例: spring/selflearning/factory/BeanFactory.java
这段代码利用 BeanFactory 读取配置文件,并自定义了获取可重用组件对象的方法。

package spring.selflearning.factory;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

// Bean: 可重用组件
public class BeanFactory {
    private static Properties props;

    // 为 props 对象赋值
    static {
        props = new Properties(); // 实例化对象
        InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"); // 不使用 new 创建流对象而使用getClassLoader()是为了防止配置文件位置的更改。
        try {
            props.load(in);
        } catch (IOException e) {
            throw new ExceptionInInitializerError("初始化Properties失败!");
        }
    }

    // 根据 Bean 的名称获取 Bean 对象
    public 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;
    }
}

配置文件: resources/bean.properties

accountService=spring.selflearning.service.impl.AccountServiceImpl
accountDao=spring.selflearning.dao.impl.AccountDaoImpl

表现层解耦: spring/selflearning/ui/Client.java

package spring.selflearning.ui;

//import spring.selflearning.dao.IAccountDao;
import spring.selflearning.factory.BeanFactory;
import spring.selflearning.service.IAccountService;
//import spring.selflearning.service.impl.AccountServiceImpl;

/*
模拟表现层,用于调用业务层
 */
public class Client {
    public static void main(String[] args) {
//        IAccountService as = new AccountServiceImpl(); // 表现层由于new了业务层实现类,具有强耦合性
        IAccountService as = (IAccountService) BeanFactory.getBean("accountService"); // 解耦,将getBean()得到的Object类强转为所需类型
        as.saveAccount();
    }
}

业务层解耦: spring/selflearning/service/impl/AccountServiceImpl.java

package spring.selflearning.service.impl;

import spring.selflearning.dao.IAccountDao;
//import spring.selflearning.dao.impl.AccountDaoImpl;
import spring.selflearning.factory.BeanFactory;
import spring.selflearning.service.IAccountService;

/*
账户业务层实现类
 */
public class AccountServiceImpl implements IAccountService {

    // 业务层调用持久层
//    private IAccountDao accountDao = new AccountDaoImpl(); // 业务层由于new了持久层实现类,具有强耦合性
    private IAccountDao accountDao = (IAccountDao) BeanFactory.getBean("accountDao"); // 解耦,将getBean()得到的Object类强转为所需类型
    public void saveAccount() {
        accountDao.saveAccount();
    }
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 2

有点6,但是一行代码没有感觉就在天上 还有spring mvc 自己瞎几把 new 代码真的不好改,无奈啊

3年前 评论
Borris (楼主) 3年前

这个写得也太少了。最好能够来点代码实例啥的。我也想写spring这一块的东西,我先把书看完嘿嘿。

3年前 评论
Borris (楼主) 3年前
HOHD 3年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!