在Java Spring框架中使用的設(shè)計(jì)模式有哪些
1 簡(jiǎn)單工廠模式
當(dāng)A對(duì)象需要調(diào)用B對(duì)象的方法時(shí),我們需要在A中new一個(gè)B的實(shí)例,我們把這種方式叫作硬編碼耦合,缺點(diǎn)是一旦需求發(fā)生變化,比如需要使用C類來代替B時(shí),就要改寫A類的方法。
假如應(yīng)用中有上千個(gè)類以硬編碼的方式耦合了B,改就很頭疼。
于是有了簡(jiǎn)單工廠模式,又叫靜態(tài)工廠方法,就是由一個(gè)工廠類根據(jù)傳入?yún)?shù),動(dòng)態(tài)決定應(yīng)該創(chuàng)建哪個(gè)產(chǎn)品類。
Spring中的BeanFactory就是簡(jiǎn)單工廠模式的體現(xiàn),BeanFactory是Spring IOC容器中的一個(gè)核心接口,它的定義如下:
可以通過它的具體實(shí)現(xiàn)類(如ClassPathXmlApplicationContext)獲取Bean:
BeanFactory bf = new ClassPathXmlApplicationContext("spring.xml"); User userBean = (User) bf.getBean("userBean");
使用者無需自己new,而是通過工廠類的方法getBean獲取對(duì)象實(shí)例,這就是簡(jiǎn)單工廠模式,只不過Spring是用反射創(chuàng)建Bean。
2 工廠方法模式
簡(jiǎn)單工廠中,由工廠類進(jìn)行所有的邏輯判斷、實(shí)例創(chuàng)建。
如果不想在工廠類中進(jìn)行判斷,可為不同產(chǎn)品提供不同工廠,不同工廠生產(chǎn)不同產(chǎn)品,每個(gè)工廠都只對(duì)應(yīng)一個(gè)相應(yīng)對(duì)象,這就是工廠方法模式。
Spring FactoryBean,工廠Bean
定義一個(gè)類UserFactoryBean實(shí)現(xiàn)FactoryBean接口,主要是在getObject方法里new一個(gè)User對(duì)象。
這樣通過getBean(id) 獲得的是該工廠所產(chǎn)生的User實(shí)例,而非UserFactoryBean本身實(shí)例:
BeanFactory bf = new ClassPathXmlApplicationContext("user.xml"); User userBean = (User) bf.getBean("userFactoryBean");
3 單例模式
一個(gè)類在整個(gè)系統(tǒng)運(yùn)行過程中,只允許產(chǎn)生一個(gè)實(shí)例。
Spring Bean默認(rèn)是單例模式。Spring 通過單例注冊(cè)表(HashMap)方式:
public class DefaultSingletonBeanRegistry { // 使用 ConcurrentHashMap 保存各種單實(shí)例對(duì)象 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>; protected Object getSingleton(String beanName) { // 先到 Map 中拿Object Object singletonObject = singletonObjects.get(beanName); // 若沒拿到通過反射創(chuàng)建一個(gè)對(duì)象實(shí)例,并添加到HashMap中 if (singletonObject == null) { singletonObjects.put(beanName, Class.forName(beanName).newInstance()); } // 返回對(duì)象實(shí)例 return singletonObjects.get(beanName); } }
4 代理模式
它與被代理對(duì)象實(shí)現(xiàn)相同接口,客戶端必須通過代理才能與被代理的目標(biāo)類進(jìn)行交互,而代理一般在交互的過程中(交互前后),進(jìn)行某些特定處理,比如在調(diào)用這個(gè)方法前做前置處理,調(diào)用這個(gè)方法后做后置處理。
好處
可以在目標(biāo)對(duì)象業(yè)務(wù)功能的基礎(chǔ)上添加一些公共的邏輯,比如我們想給目標(biāo)對(duì)象加入日志、權(quán)限管理和事務(wù)控制等功能,我們就可以使用代理類來完成,而沒必要修改目標(biāo)類,從而使得目標(biāo)類保持穩(wěn)定。
符合開閉原則,不要隨意修改別人寫好的代碼或方法。
代理又分為
靜態(tài)代理
需要定義接口,被代理對(duì)象(目標(biāo)對(duì)象)與代理對(duì)象(Proxy)一起實(shí)現(xiàn)相同接口:
// 抽象接口 public interface IStudentDao { void save(); } // 目標(biāo)對(duì)象 public class StudentDao implements IStudentDao { public void save() { System.out.println("保存成功"); } } // 代理對(duì)象 public class StudentDaoProxy implements IStudentDao{ //持有目標(biāo)對(duì)象的引用 private IStudentDao target; public StudentDaoProxy(IStudentDao target){ this.target = target; } //在目標(biāo)功能對(duì)象方法的前后加入事務(wù)控制 public void save() { System.out.println("開始事務(wù)"); target.save();//執(zhí)行目標(biāo)對(duì)象的方法 System.out.println("提交事務(wù)"); } } public static void main(String[] args) { //創(chuàng)建目標(biāo)對(duì)象 StudentDao target = new StudentDao(); //創(chuàng)建代理對(duì)象,把目標(biāo)對(duì)象傳給代理對(duì)象,建立代理關(guān)系 StudentDaoProxy proxy = new StudentDaoProxy(target); //執(zhí)行的是代理的方法 proxy.save(); }
動(dòng)態(tài)代理
Spring AOP采用動(dòng)態(tài)代理,即代理類在程序運(yùn)行時(shí)由JVM動(dòng)態(tài)創(chuàng)建。
靜態(tài)代理的例子中,代理類(StudentDaoProxy)是自定義的,在程序運(yùn)行之前就已經(jīng)編譯完成。
而動(dòng)態(tài)代理,代理類并不是在Java代碼中定義,而是在運(yùn)行時(shí)根據(jù)我們?cè)贘ava代碼中的“指示”動(dòng)態(tài)生成的。
怎么“指示”JDK去動(dòng)態(tài)地生成代理類呢?
在Java的java.lang.reflect包里提供了一個(gè)Proxy類和一個(gè)InvocationHandler接口,通過這個(gè)類和這個(gè)接口可以生成動(dòng)態(tài)代理對(duì)象:
1.定義一個(gè)InvocationHandler類,將需要擴(kuò)展的邏輯集中放到這個(gè)類中。
比如下面的例子模擬了添加事務(wù)控制:
public class MyInvocationHandler implements InvocationHandler { private Object obj; public MyInvocationHandler(Object obj){ this.obj=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("開始事務(wù)"); Object result = method.invoke(obj, args); System.out.println("開始事務(wù)"); return result; } }
2.使用 Proxy#newProxyInstance 動(dòng)態(tài)創(chuàng)建代理對(duì)象
public static void main(String[] args) { //創(chuàng)建目標(biāo)對(duì)象StudentDao IStudentDao stuDAO = new StudentDao(); //創(chuàng)建MyInvocationHandler對(duì)象 InvocationHandler handler = new MyInvocationHandler(stuDAO); //使用Proxy.newProxyInstance動(dòng)態(tài)的創(chuàng)建代理對(duì)象stuProxy IStudentDao stuProxy = (IStudentDao) Proxy.newProxyInstance(stuDAO.getClass().getClassLoader(), stuDAO.getClass().getInterfaces(), handler); //動(dòng)用代理對(duì)象的方法 stuProxy.save(); }
動(dòng)態(tài)代理的優(yōu)勢(shì)在于可以很方便地對(duì)代理類的函數(shù)進(jìn)行統(tǒng)一的處理,而不用修改每個(gè)代理類中的方法。
Spring實(shí)現(xiàn)了通過動(dòng)態(tài)代理對(duì)類進(jìn)行方法級(jí)別的切面增強(qiáng),即動(dòng)態(tài)生成目標(biāo)對(duì)象的代理類,并在代理類的方法中設(shè)置攔截器,通過執(zhí)行攔截器中的邏輯增強(qiáng)了代理方法的功能,從而實(shí)現(xiàn)AOP。
到此這篇關(guān)于在Java Spring框架中使用的設(shè)計(jì)模式有哪些的文章就介紹到這了,更多相關(guān)Java Spring 設(shè)計(jì)模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring?boot?mybatis日志輸出到控制臺(tái)的方法實(shí)踐
在開發(fā)過程中我們往往需要打印出SQL語句,這樣就方便我們監(jiān)控問題,本文主要介紹了spring?boot?mybatis日志輸出到控制臺(tái)的方法實(shí)踐,具有一定的參考價(jià)值,感興趣的可以了解一下2024-05-05詳解Springboot之Logback的使用學(xué)習(xí)
Logback是SpringBoot內(nèi)置的日志處理框架,你會(huì)發(fā)現(xiàn)spring-boot-starter其中包含了spring-boot-starter-logging,該依賴內(nèi)容就是Spring Boot默認(rèn)的日志框架logback,本文詳細(xì)介紹了該框架 ,需要的朋友可以參考下2021-05-05Java發(fā)送http請(qǐng)求的示例(get與post方法請(qǐng)求)
這篇文章主要介紹了Java發(fā)送http請(qǐng)求的示例(get與post方法請(qǐng)求),幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2021-01-01springcloud Zuul動(dòng)態(tài)路由的實(shí)現(xiàn)
這篇文章主要介紹了springcloud Zuul動(dòng)態(tài)路由的實(shí)現(xiàn),詳細(xì)的介紹了什么是Zuu及其動(dòng)態(tài)路由的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-11-11Springmvc conver實(shí)現(xiàn)原理及用法解析
這篇文章主要介紹了Springmvc conver實(shí)現(xiàn)原理及用法解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10java 讀取網(wǎng)頁(yè)內(nèi)容的實(shí)例詳解
這篇文章主要介紹了java 讀取網(wǎng)頁(yè)內(nèi)容的實(shí)例詳解的相關(guān)資料,希望通過本文能幫助到大家,讓大家學(xué)習(xí)理解這部分內(nèi)容,需要的朋友可以參考下2017-09-09java中Hutool工具類的常見使用場(chǎng)景詳解
在日常開發(fā)中,我們會(huì)使用很多工具類來提升項(xiàng)目開發(fā)的速度,而國(guó)內(nèi)用的比較多的 Hutool 框架,就是其中之一,本文我們就來介紹一下Hutool的具體使用吧2023-12-12Spring中的@RestController注解詳細(xì)解析
這篇文章主要介紹了Spring中的@RestController注解詳細(xì)解析,@RestController 是 Spring Framework 中的一個(gè)注解,用于標(biāo)識(shí)一個(gè)類為 RESTful Web 服務(wù)的控制器(Controller),處理 HTTP 請(qǐng)求并返回相應(yīng)的數(shù)據(jù),2024-01-01SpringBoot利用限速器RateLimiter實(shí)現(xiàn)單機(jī)限流的示例代碼
本文主要介紹了SpringBoot利用限速器RateLimiter實(shí)現(xiàn)單機(jī)限流的示例代碼,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01