spring框架搭建第一天
文章目錄
- 1. 從jdbc的標準代碼了解程序的耦合性
- 簡單理解耦合:程序之間的依賴關系
- 2. 基本的三層
- dao層
- service層
- 模擬的controller層(servlet)
- 存在的問題
- 3. 使用工廠模式解決代碼耦合性問題
- 什么是簡單工廠模式
- 簡單工廠模式如何解耦(后續有待深究)
- 使用工廠模式解決代碼耦合
- 4. 使用單例模式調對象復用性
- 讓工廠不僅負責實例化對象還管理對象
- 修改BeanFactory
- 什么是單例模式
- 5. 開始Spring框架
- 5.1 控制反轉IOC
- 5.2 創建一個spring工程
- 5.3 Spring是如何加載配置文件(Spring是什么時候實例化對象的)
- 6. Spring對bean的管理
- 6.1 創建bean的三種方式
- 6.1.1 使用默認構造函數創建bean
- 6.1.2 使用普通工廠中的方法創建對象
- 6.1.3 使用工廠中的靜態方法創建對象
- 6.2 bean的作用范圍
- 6.3 bean的生命周期
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)
解耦的思路:
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();} }存在的問題
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
4. 使用單例模式調對象復用性
前面已經使用簡單工廠模式降低了Client對AccountServiceImpl的耦合性,但是代碼仍然存在一個問題,那就是每次調用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包
創建配置文件bean.xml
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的三個實現類:
5.3 Spring是如何加載配置文件(Spring是什么時候實例化對象的)
前面說過,Spring的IOC指的是Spring代替Application管理我們的JavaBean。那么他是什么時候實例化這些JavaBean的呢?
一般有兩種情況
- 一次性創建所有的對象,就是說Spring一次性實例化所有的對象
- 按需要加載對象,就是說需要哪個對象,Spring再來幫我們實例化它
這就對應著Spring核心容器的兩個接口,ApplicationContext和 BeanFactory。其中
- ApplicationContext:構建核心容器時,創建對象采取的策略是立即加載的方式。讀完配置文件就創建配置文件中的對象。
- BeanFactory:構建核心容器時,創建對象采取的策略是延遲加載的方式。什么時候根據id獲取對象,什么時候創建對象。
實驗代碼
對應的AccountServiceImpl代碼
public class AccountServiceImpl implements IAccountService {private IAccountDao accountDao = new AccountDao();//重寫構造器,看看該對象是什么時候創建的public AccountServiceImpl(){System.out.println("AccountServiceImpl被實例化了!");}public void saveAccount(){accountDao.saveAccount();} }6. Spring對bean的管理
6.1 創建bean的三種方式
6.1.1 使用默認構造函數創建bean
在spring的配置文件中使用<bean></bean>標簽,配以id和class屬性,并且標簽中沒有其他屬性的時候。采用的就是默認類的構造函數創建bean對象。
<bean id="accountService" class="com.ssm.service.impl.AccountServiceImpl" ></bean>此時如果AccountServiceImpl沒有默認構造函數(構造函數被重寫了),則無法創建對象。
報錯,沒有發現默認的構造器。
6.1.2 使用普通工廠中的方法創建對象
假設一個情景
如果我們現在要用第三方jar包中的某個類,但是這個類的構造函數被重寫了。那么我們該如何實例化這個類?
比如上面的AccountServiceImpl沒有默認的構造函數,如何實例化它呢?
此時需要借助一個工廠類InstanceFactory,通過它來實例化我們的對象。
package com.ssm.factory;import com.ssm.service.IAccountService; import com.ssm.service.impl.AccountServiceImpl;public class InstanceFactory {public IAccountService getAccountService(){return new AccountServiceImpl("用工廠實例化AccountServiceImpl");} } <bean id="instanceFactory" class="com.ssm.factory.InstanceFactory"></bean><bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>過程是先實例化instanceFactory,再調用instanceFactory中的getAccountService方法。
6.1.3 使用工廠中的靜態方法創建對象
與上面的類似,只是不需要實例化工廠類了。直接調用工廠類中的靜態方法。具體如下
<!--使用工廠中的靜態方法創建對象--><bean id="accountService" class="com.ssm.factory.StaticFactory" factory-method="getAccountService"></bean> package com.ssm.factory;import com.ssm.service.IAccountService; import com.ssm.service.impl.AccountServiceImpl;public class StaticFactory {public static IAccountService getAccountService(){return new AccountServiceImpl("使用靜態方法實例化AccountServiceImpl");} }可以在沒有實例化StaticFactory情況下,使用它創建一個AccountServiceImpl對象。
回顧下static的知識 在Java類中,有六種成員:屬性、方法、構造器、初始化塊、內部類和枚舉類,其中static可以修飾屬性、方法、初始化塊、內部類和枚舉類。 以static修飾的的成員就是類成員。類成員屬于整個類,而不是單個對象。所以上面可以無需實例化StaticFactory 來創建AccountServiceImpl。因為類方法在類加載到jvm的時候就可以用了。6.2 bean的作用范圍
bean標簽有一個scope屬性:用于指定bean的作用范圍。
| singleton | 單例(默認值) |
| prototype | 多例 |
| request | 作用于web應用的請求范圍 |
| session | 作用于web應用的會話范圍 |
| global-session | 作用于集群環境的會話范圍(全局會話范圍),當不是集群環境時,等價于session |
6.3 bean的生命周期
單例對象:我與容器共生死!!!
多例對象:
出生:使用對象時,由spring框架為我們創建
或者:只要是使用,就一直活著
死亡:長時間不用,且沒有別的對象引用,有GC負責回收
實驗,單例對象
<bean id="accountService" class="com.ssm.service.impl.AccountServiceImpl" scope="singleton" init-method="init" destroy-method="destory"></bean> public class AccountServiceImpl implements IAccountService {//private IAccountDao accountDao = new AccountDao();public AccountServiceImpl(){System.out.println("AccountServiceImpl被實例化了!");}public void saveAccount(){System.out.println("保存賬戶成功!");//accountDao.saveAccount();}public void init(){System.out.println("AccountServiceImpl對象創建了");}public void destory(){System.out.println("AccountServiceImpl對象銷毀了");} }Client片段public static void main(String[] args) throws Exception{ClassPathXmlApplicationContext applicationContext = null; // applicationContext = new FileSystemXmlApplicationContext(""); // applicationContext = new AnnotationConfigApplicationContext("");applicationContext = new ClassPathXmlApplicationContext("bean.xml");//兩種獲取實例的方式IAccountService as = (IAccountService) applicationContext.getBean("accountService");System.out.println(as);as.saveAccount();//手動關閉容器applicationContext.close();Thread.sleep(3000);}結果:
spring創建時,先調用構造器,在調用init-method對應的方法,摧毀時調用destroy-method對應的方法
總結
以上是生活随笔為你收集整理的spring框架搭建第一天的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: log4j2使用笔记
- 下一篇: spring框架搭建第二天