spring框架搭建第一天

1. 從jdbc的標準代碼瞭解程序的耦合性

import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

public class JdbcDemo1 {
    public static void main(String[] args) throws Exception{
        //Class.forName("com.mysql.jdbc.Driver");
        DriverManager.registerDriver(new com.mysql.jdbc.Driver());
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?characterEncoding=utf-8", "root", "123456");
        PreparedStatement ps = conn.prepareStatement("insert into account(name, money) values(?,?)");
        ps.setString(1,"bbb");
        ps.setFloat(2,2000);
        ps.executeUpdate();
        ps.close();
        conn.close();
    }
}

程序執行過程,

  • 註冊驅動
  • 獲取鏈接
  • 獲取操作數據庫的預處理對象
  • 執行sql語句,得到結果集(本例是新增操作,故沒有結果集)
  • 遍歷結果集
  • 依次關閉結果集,預處理對象,連接。
    當我們把相關jar包去掉
    在這裏插入圖片描述
    可以發現,沒有myql的驅動,將無法編譯。此時可以理解爲程序的耦合。

簡單理解耦合:程序之間的依賴關係

耦合包括:

  • 類之間的依賴關係
  • 方法之間的依賴關係

如何解耦
降低程序之間的依賴

  • 編譯期間不依賴,運行時才依賴(典型例子:DriverManager.registerDriver()轉化爲用反射來加載驅動Class.forName)

解耦的思路:

  1. 使用反射來創建對象,避免使用new關鍵字。
  2. 通過讀取配置文件來獲取要創建的對象全限定類名。

2. 基本的三層

dao層

package com.ssm.dao.impl;

import com.ssm.dao.IAccountDao;

public class AccountDao implements IAccountDao {
    public void saveAccount() {
        System.out.println("賬戶已保存!");
    }
}
package com.ssm.dao;
/**
 * 賬戶的持久層接口
 */
public interface IAccountDao {

    //模擬保存賬戶
    void saveAccount();
}

service層

package com.ssm.service.impl;

import com.ssm.dao.IAccountDao;
import com.ssm.dao.impl.AccountDao;
import com.ssm.factory.BeanFactory;
import com.ssm.service.IAccountService;

import java.util.PriorityQueue;

public class AccountServiceImpl implements IAccountService {

    private IAccountDao accountDao = new AccountDao();

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

package com.ssm.service;

/**
 * 賬戶業務層
 */
public interface IAccountService {
    //保存賬戶
    void saveAccount();
}

模擬的controller層(servlet)

package com.ssm.ul;

import com.ssm.factory.BeanFactory;
import com.ssm.service.IAccountService;
import com.ssm.service.impl.AccountServiceImpl;
/**
 模擬表現層
 */
public class Client {
    public static void main(String[] args){
        IAccountService as = new AccountServiceImpl();
        as.saveAccount();
    }
}

存在的問題

  1. controller層調用service層使用了new關鍵字,如果AccountServiceImpl.java不存在,則會編譯不通過。代碼耦合性太強。
  2. 假如有多次調用controller(main()多次執行),每次執行都會new一個AccountServiceImpl,AccountDao。假如執行5次controller,就會有10個service和dao對象在內存中。在高併發下性能不好

3. 使用工廠模式解決代碼耦合性問題

什麼是簡單工廠模式

簡單工廠模式又稱爲靜態工廠模式,它屬於創建型模式,但非23種設計模式之一。它可以根據傳入的參數來返回不同類的實例。簡單工廠模式專門定義一個類來負責創建其他類的實例,被創建的實例通常都具有共同的父類。

角色 作用
工廠角色(Creator) 是簡單工廠模式的核心,它負責實現創建所有具體產品類的實例。工廠類可以被外界直接調用,創建所需的產品對象。
抽象產品角色(Product) 是所有具體產品角色的父類,它負責描述所有實例所共有的公共接口。
具體產品角色(Concrete Product) 繼承自抽象產品角色,一般爲多個,是簡單工廠模式的創建目標。工廠類返回的都是該角色的某一具體產品。

簡單工廠模式如何解耦(後續有待深究)

直接new一個對象是最簡單的創建對象的方式。但是它也加強了兩個對象A和B之間的耦合性。使用簡單工廠模式,在A想使用B對象的時候,可以向工廠角色(Creator)請求創建一個實例對象,這樣就避免了直接實例化B對象。降低了耦合性。

使用工廠模式解決代碼耦合

package com.ssm.factory;


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

/**
 * 創建一個bean對象的工廠
 */
public class BeanFactory {
    private static Properties props;

    static {
        try {
            props = new Properties();
            //getResourceAsStream(String path):默認則是從ClassPath根下獲取,path不能以’/'開頭,最終是由ClassLoader獲取資源。
            InputStream in  = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
            System.out.println(in);
            props.load(in);
        } catch (IOException e) {
            e.printStackTrace();
            throw new ExceptionInInitializerError("初始化properties失敗!");
        }
    }

    /**
     * 根據Bean名稱獲取Bean對象
     * @param beanName
     * @return
     */
    public static Object getBean(String beanName){
        Object bean = null;
        try {
            String beanPath = props.getProperty(beanName);
            System.out.println("beanPath:"+beanPath);
            bean = Class.forName(beanPath).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return bean;
    }
}

工廠讀取的配置文件

accountService=com.ssm.service.impl.AccountServiceImpl
accuountDao=com.ssm.dao.impl.AccountDao

修改各處的對象實例化方式
比如controller

        //IAccountService as = new AccountServiceImpl();
        IAccountService as  = (IAccountService) BeanFactory.getBean("accountService");

4. 使用單例模式調對象複用性

前面已經使用簡單工廠模式降低了ClientAccountServiceImpl的耦合性,但是代碼仍然存在一個問題,那就是每次調用main()都會讓BeanFactory.getBean()實例化一個對象,多次調用就會有多個實例對象產生,從而影響代碼性能。那麼如何讓程序在運行中只讓一個類只實例化一個對象呢?

讓工廠不僅負責實例化對象還管理對象

前面實例化對象的工作是交給BeanFactory的,每次有實例化對象的請求過來,它就是實例化一個請求。那麼能不能讓BeanFactory先實例化所有對象,把它們管理起來。每次有實例化請求過來,就返回需要實例化對象的引用。這樣就能保證內存中IAccountService只有一個實例化對象。

修改BeanFactory

修改靜態代碼塊

    static {
        try {
            props = new Properties();
            //getResourceAsStream(String path):默認則是從ClassPath根下獲取,path不能以’/'開頭,最終是由ClassLoader獲取資源。
            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();
                String keyPath = props.getProperty(key);
                Object bean = Class.forName(keyPath).newInstance();
                beans.put(key,bean);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExceptionInInitializerError("初始化properties失敗!");
        }
    }

此時,BeanFactory中已經有所需要的對象實例了,那麼獲取bean的方法也要改

    public  static Object getBean(String beanName){
        return beans.get(beanName);
    }

什麼是單例模式

單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。與前面說的簡單工廠模式一樣,這種類型的設計模式也屬於創建型模式,它提供了一種創建對象的最佳方式。

這種模式涉及到一個單一的類,該類負責創建自己的對象,同時確保只有單個對象被創建。這個類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的對象。

5. 開始Spring框架

抽象前面的模型
更改前的
在這裏插入圖片描述
更改後的
在這裏插入圖片描述

5.1 控制反轉IOC

百度詞條解釋
在這裏插入圖片描述
作用:降低程序代碼的耦合(解除代碼間的依賴關係)

5.2 創建一個spring工程

首先,創建一個基本的maven工程。
配置pom文件,導入jar包

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.0.RELEASE</version>
        </dependency>

創建配置文件bean.xml

  1. 創建配置文件
  2. 導約束
  3. 把對象的創建交給spring來管理
<?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 id="accountService" class="com.ssm.service.impl.AccountServiceImpl" ></bean>

    <bean id="accuountDao" class="com.ssm.dao.impl.AccountDao"></bean>
    
</beans>

Client的配置

public class Client {
    public static void main(String[] args){
        ApplicationContext applicationContext = null;
        applicationContext = new ClassPathXmlApplicationContext("bean.xml");

        //兩種獲取實例的方式
        IAccountService as = (IAccountService) applicationContext.getBean("accountService");
        IAccountDao accountDao = applicationContext.getBean("accuountDao",IAccountDao.class);

        System.out.println(as);
        System.out.println(accountDao);
    }
}

ApplicationContext的三個實現類:

  1. ClassPathXmlApplicationContext:加載類路徑下的配置文件,要求配置文件必須在類路徑下。否則加載不了。
  2. FileSystemXmlApplicationContext:加載磁盤任意路徑下的配置文件(必須要有訪問權限)
  3. AnnotationConfigApplicationContext:用於讀取註解創建容器。
    核心容器的兩個接口引發
    ApplicationContext
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章