G001Spring學習筆記-Spring框架概述和程序間耦合

一、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.*;

public class MyJdbc {
    public static void main(String[] args) throws SQLException {
        //1、註冊驅動-問題:在沒有這個com.mysql.jdbc.Driver包的時候程序是不能正常編譯的,
        //這就是程序的耦合(可以簡單德認爲就是程序間的依賴關係)
        DriverManager.registerDriver(new com.mysql.jdbc.Driver());
        //2、獲取連接
        Connection connection = DriverManager.getConnection("jdbc:mysql://rm-wz94daz94uktn3x7x4o.mysql.rds.aliyuncs.com/zibo?useUnicode=true&characterEncoding=UTF-8","root","zibo@709570094");
        //3、獲取操作數據庫的預處理對象
        PreparedStatement preparedStatement = connection.prepareStatement("select * from student");
        //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.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;
    }
}

運行結果:

注意:無論是業務層還是持久層很少包含可以修改的類成員(因爲對象是一個,在多線程的情況下容易出錯,變量可聲明在方法中);

 

 

 

 

 

 

 

發佈了143 篇原創文章 · 獲贊 24 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章