【旧】G001Spring学习笔记-Spring框架概述和程序间耦合

目录

一、Spring框架概述

1、简介

2、优势

3、Spring的体系结构

二、程序间耦合

1、编写JDBC的工程代码用于分析程序的耦合

正常运行的代码:

说明:

程序的耦合:

注册驱动的另一种方法:

2、曾经代码中的问题

代码示例:

说明:

3、编写工厂类和配置文件

4、分析工厂模式中的问题并改造

分析问题:

打印结果:

说明:

改造:


一、Spring框架概述

1、简介

Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。

Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式)轻量级开源框架。

 

2、优势

方便解耦,简化开发;

AOP编程的支持;

声明式事务的支持;

方便程序的测试;

方便集成各种优秀框架;

降低JavaEE API的使用难度;

 

3、Spring的体系结构

 

二、程序间耦合

1、编写JDBC的工程代码用于分析程序的耦合

正常运行的代码:

package com.zibo.jdbc;

import java.sql.*;

/**
 * 程序的耦合
 * 耦合:简单地认为是程序间的依赖关系;
 *  包括:
 *      类之间的依赖;
 *      方法之间的依赖;
 *  说明:我们不可能完全消除程序之间的依赖关系,但我们可以降低,这就是解耦;
 *  实际开发中:
 *      应做到编译期不依赖,运行期依赖;
 *  解耦的思路:
 *      第一步:使用反射来创建对象,而避免使用new关键字;
 *      第二步:通过读取配置文件来获取要创建的对象权限的类名;
 *      
 */
public class JdbcDemo1 {
    public static void main(String[] args) throws Exception {
        //1、注册驱动-问题:在没有这个com.mysql.cj.jdbc.Driver包的时候程序是不能正常编译的,
        //编译期异常,
        //这就是程序的耦合(可以简单地认为就是程序间的依赖关系)
        DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
        //以前的解决方法
//        Class.forName("com.mysql.cj.jdbc.Driver");
        //2、获取连接
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/zibo?serverTimezone=UTC","root","zibo15239417242");
        //3、获取操作数据库的预处理对象
        PreparedStatement preparedStatement = connection.prepareStatement("select * from account");
        //4、执行SQL,得到结果集
        ResultSet resultSet = preparedStatement.executeQuery();
        //5、遍历结果集
        while (resultSet.next()){
            System.out.println(resultSet.getString("name"));
        }
        //6、释放资源
        resultSet.close();
        preparedStatement.close();
        connection.close();
    }
}

说明:

当我们将程序包注释的时候,程序编译就会报错,体现了程序之间相互依赖(即程序之间的耦合性),如图:

程序的耦合:

耦合:(简单认为)程序间的依赖关系;

包括:类之间的依赖,方法之间的依赖;

解耦:降低程序间的依赖关系;

实际开发中:编译器不依赖,运行时才依赖;

解耦的思路:
1、使用反射来创建对象,而避免使用New关键字;
2、通过读取配置文件来获取要创建的对象全限定类名;

注册驱动的另一种方法:

Class.forName("com.mysql.cj.jdbc.Driver");

//说明:这种方式虽然也不能运行,但是这种情况出现的错误是运行时异常,而不是编译器异常;

//但是,这种写法把数据库写死了,可以通过读取配置文件的方式读取要创建的对象的全限定类名;

 

2、曾经代码中的问题

代码示例:

IAccountDao接口:

package com.zibo.dao;

public interface IAccountDao {
    void saveAccount();
}

IAccountDaoImpl接口实现类:

package com.zibo.dao.impl;

import com.zibo.dao.IAccountDao;

public class IAccountDaoImpl implements IAccountDao {
    @Override
    public void saveAccount() {
        System.out.println("保存了账户");
    }
}

IAccountService接口:

package com.zibo.services;

/**
 * 业务层接口
 */
public interface IAccountService {
    /**
     * 模拟保存账户
     */
    void saveAccount();
}

IAccountServiceImpl接口是实现类:

package com.zibo.services.impl;

import com.zibo.dao.IAccountDao;
import com.zibo.dao.impl.IAccountDaoImpl;
import com.zibo.services.IAccountService;

/**
 * 账户的业务层实现类
 */
public class IAccountServiceImpl implements IAccountService {
    private IAccountDao iAccountDao = new IAccountDaoImpl();
    @Override
    public void saveAccount() {
        iAccountDao.saveAccount();
    }
}

Client类:

package com.zibo.ui;

import com.zibo.services.IAccountService;
import com.zibo.services.impl.IAccountServiceImpl;

/**
 * 模拟表现层,调用业务层
 */
public class Client {
    public static void main(String[] args) {
        IAccountService service = new IAccountServiceImpl();
        service.saveAccount();
    }
}

各文件位置:

说明:

本示例中各程序之间有着严重的依赖关系,一旦某个程序出错会导致整个程序编译失败!那该怎么解决这个问题呢?

编写工厂类和配置文件!

 

3、编写工厂类和配置文件

BeanFactory工厂类:

package com.zibo.factory;

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

/**
 * 创建Bean对象的工厂:
 * 创建我们的service和dao对象;
 * 如何创建:
 * 1、需要一个配置文件来配置service和dao;
 * 配置内容:唯一标识=全限定类名(key=value)
 * 2、通过服务配置文件中的内容,反射创建对象;
 * 配置文件可以是xml也可以是properties;
 *
 * Bean:在计算机英语中,有可重用组件的含义;
 * JavaBean不等于实体类,是用Java语言编写的可重用组件;
 *
 *
 */
public class BeanFactory {
    //定义一个Properties对象
    private static Properties properties;

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

    public static Object getBean(String beanName){
        Object bean = null;
        String property = properties.getProperty(beanName);
        System.out.println(property);
        try {
            bean = Class.forName(property).getDeclaredConstructor().newInstance();
        } catch (Exception e){
            e.printStackTrace();
        }
        return bean;
    }
}

bean.properties配置配置文件:

accountService=com.zibo.services.impl.IAccountServiceImpl
accountDao=com.zibo.dao.impl.IAccountDaoImpl

使用工厂类进行解耦:

//改写IAccountServiceImpl代码:
//    private IAccountDao iAccountDao = new IAccountDaoImpl();
    private IAccountDao iAccountDao = (IAccountDao)BeanFactory.getBean("AccountDao");

//改写Client代码:
//        IAccountService service = new IAccountServiceImpl();
        IAccountService service = (IAccountService)BeanFactory.getBean("AccountService");

运行结果(成功):

 

4、分析工厂模式中的问题并改造

分析问题:

打印一下IAccountService对象:

for (int i = 0; i <5 ; i++) {
            IAccountService service = (IAccountService)BeanFactory.getBean("accountService");
            System.out.println(service);
        }

打印结果:

说明:

可见,这个程序是多例模式,程序的运行创建了多个对象,单例模式中对象智慧被创建一次,而类中的成员也只会被初始化一次;

多例模式中,由于对象被创建多次,运行效率没有单例模式高,但是单例模式存在线程问题;

改造:

思想:将创建对象的方法写在静态代码块中,类加载的时候只执行一次,创建的对象存起来,以遍重复使用;

改造后的代码:

package com.zibo.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对象的工厂:
 * 创建我们的service和dao对象;
 * 如何创建:
 * 1、需要一个配置文件来配置service和dao;
 * 配置内容:唯一标识=全限定类名(key=value)
 * 2、通过服务配置文件中的内容,反射创建对象;
 * 配置文件可以是xml也可以是properties;
 *
 * Bean:在计算机英语中,有可重用组件的含义;
 * JavaBean不等于实体类,是用Java语言编写的可重用组件;
 *
 *
 */
public class BeanFactory {
    //定义一个Properties对象
    private static Properties properties;

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

    //使用静态代码块为properties赋值
    static {//静态代码块只在类加载的时候执行一次
        //实例化对象
        properties = new Properties();
        //获取properties文件的流对象
        InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
        try {
            properties.load(in);
            //实例化容器
            beans = new HashMap<>();
            //去除配置文件中所有的key
            Enumeration<Object> keys = properties.keys();
            //遍历枚举
            while (keys.hasMoreElements()){
                //取出每个key
                String key = keys.nextElement().toString();
                //根据key获取value
                String property = properties.getProperty(key);
                //反射创建对象
                Object value = Class.forName(property).getDeclaredConstructor().newInstance();//newInstance表明每次都会调用默认构造函数创建对象
                //把key和value存入容器中
                beans.put(key,value);
            }
        } catch (Exception e) {
           throw new ExceptionInInitializerError("初始化properties失败!");
        }
    }

    public static Object getBean(String beanName){
        return beans.get(beanName);
//        Object bean = null;
//        String property = properties.getProperty(beanName);
        System.out.println(property);
//        try {
//            bean = Class.forName(property).getDeclaredConstructor().newInstance();//newInstance表明每次都会调用默认构造函数创建对象
//        } catch (Exception e){
//            e.printStackTrace();
//        }
//        return bean;
    }
}

运行结果:

注意:无论是业务层还是持久层很少包含可以修改的类成员(因为对象是一个,在多线程的情况下容易出错,变量可声明在方法中);

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值