欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring?Framework六種常見設計模式

 更新時間:2023年06月26日 10:27:57   作者:江帥帥  
設計模式是軟件開發(fā)的重要組成部分,本文借助spring來講解這個框架的設計模式,通過本文我們探討了spring如何利用這些模式來提供這些豐富的功能,對本文感興趣的朋友跟隨小編一起看看吧

在實際開發(fā)工作中,我們每天都在自己的工作中依賴了別人的代碼。包括了你正在用的編程語言、你正在構(gòu)建的框架,或者一些很前沿的開源產(chǎn)品。

它們都做得很好,用起來真的很爽,但你自己有沒有想過自己也要去實現(xiàn)它?哈哈,可能大概率是沒想過的,是吧?

如果你沒有嘗試過自己去實現(xiàn)類似的功能,或者是深挖過這些優(yōu)秀三方框架的話,對技術(shù)人來說,其實是隱含相當大一個風險的。

如果運氣很不好,當你在生產(chǎn)中碰到了分崩離析的事情,出現(xiàn)了生產(chǎn)事故,又不得不去調(diào)試您不熟悉的第三方庫的實現(xiàn)時,對你來說至少可以說是相當棘手的,毫無頭緒的,搞不好真的就是想原地提離職……

推薦一個 Lightrun,它是一種新型的調(diào)試器。

它是專門針對現(xiàn)實生活中的生產(chǎn)環(huán)境。使用 Lightrun,您可以向下鉆取到正在運行的應用程序,包括第三方依賴項,以及實時日志、快照和指標。

這不是重點,重點是我們借助 Spring 來聊聊這個如此受歡迎的框架的設計模式,以此打開你研究三方框架的道路。

1、簡介

設計模式是軟件開發(fā)的重要組成部分。這些解決方案不僅可以解決反復出現(xiàn)的問題,還可以通過識別常見模式來幫助開發(fā)人員了解框架的設計。

接下來呢,我們將介紹 Spring 框架中使用的四種最常見的設計模式:

  • Singleton pattern 單例模式
  • Factory Method pattern 工廠方法模式
  • Proxy pattern 代理模式
  • Template pattern 模板模式

我們還將研究 Spring 如何使用這些模式來減輕開發(fā)人員的負擔并幫助用戶快速執(zhí)行繁瑣的任務。

2、單例模式(Singleton Pattern)

單一實例模式是一種機制,可確保每個應用程序僅存在對象的一個實例。在管理共享資源或提供橫切服務(如日志記錄)時,此模式非常有用。

2.1 單例 Beans(Singleton Beans)

通常,單例對于應用程序是全局唯一的,但在 Spring 中,此約束是寬松的。相反,Spring 將單個實例限制為每個 Spring IoC 容器一個對象。在實踐中,這意味著 Spring 只會為每個應用程序上下文的每種類型創(chuàng)建一個 bean。

Spring 的方法與單例的嚴格定義不同,因為一個應用程序可以有多個 Spring 容器。因此,如果我們有多個容器,則同一類的多個對象可以存在于單個應用程序中。

Singleton

默認情況下,Spring 將所有 bean 創(chuàng)建為單例。

2.2 自動注入單例(Autowired Singletons)

例如,我們可以在單個應用程序上下文中創(chuàng)建兩個控制器,并將相同類型的 bean 注入到每個控制器中。

首先,我們創(chuàng)建一個 BookRepository 來管理我們的 Book 域?qū)ο蟆?/p>

接下來,我們創(chuàng)建 LibraryController,它使用 BookRepository 返回庫中的書籍數(shù)量:

@RestController
public class LibraryController {
    @Autowired
    private BookRepository repository;
    @GetMapping("/count")
    public Long findCount() {
        System.out.println(repository);
        return repository.count();
    }
}

最后,我們創(chuàng)建一個 BookController,它專注于特定于書籍的操作,例如按 ID 查找書籍:

@RestController
public class BookController {
    @Autowired
    private BookRepository repository;
    @GetMapping("/book/{id}")
    public Book findById(@PathVariable long id) {
        System.out.println(repository);
        return repository.findById(id).get();
    }
}

然后我們啟動這個應用程序,并對 /count 和 /book/1 執(zhí)行 GET 請求訪問:

curl -X GET http://localhost:8080/count
curl -X GET http://localhost:8080/book/1

在應用程序輸出中,我們看到兩個 BookRepository 對象具有相同的對象 ID:

com.baeldung.spring.patterns.singleton.BookRepository@3ea9524f
com.baeldung.spring.patterns.singleton.BookRepository@3ea9524f

LibraryController 和 BookController 中的 BookRepository 對象 ID 是相同的,這證明 Spring 將相同的 bean 注入到兩個控制器中。

我們可以通過使用 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 注釋將 bean 范圍從單例更改為原型來創(chuàng)建 BookRepository bean 的單獨實例。

這樣做會指示 Spring 為它創(chuàng)建的每個 BookRepository bean 創(chuàng)建單獨的對象。因此,如果我們再次檢查每個控制器中 BookRepository 的對象 ID,我們會發(fā)現(xiàn)它們不再相同。

3、工廠方法模式(Factory Method Pattern)

工廠方法模式需要一個工廠類,其中包含用于創(chuàng)建所需對象的抽象方法。

通常,我們希望根據(jù)特定的上下文創(chuàng)建不同的對象。

例如,我們的應用程序可能需要車輛對象。在航海環(huán)境中,我們想制造船只,但在航空航天環(huán)境中,我們想制造飛機:

Factory pattern

為此,我們可以為每個所需對象創(chuàng)建一個工廠實現(xiàn),并從具體的工廠方法返回所需的對象。

3.1 應用上下文(Application Context)

Spring 在其依賴注入(DI)框架的根中使用這種技術(shù)。

從根本上說,Spring 將 Bean 容器視為生產(chǎn) Beans 的工廠。

因此,Spring 將 BeanFactory 接口定義為 bean 容器的抽象:

public interface BeanFactory {
    getBean(Class<T> requiredType);
    getBean(Class<T> requiredType, Object... args);
    getBean(String name);
    // ...
}

每個 getBean 方法都被視為工廠方法,它返回與提供給該方法的條件匹配的 Bean,例如 Bean 的類型和名稱。

然后,Spring 使用 ApplicationContext 接口擴展了 BeanFactory,該接口引入了額外的應用程序配置。Spring 使用此配置根據(jù)某些外部配置(例如 XML 文件或 Java 注釋)啟動 Bean 容器。

使用 ApplicationContext 類實現(xiàn)(如 AnnotationConfigApplicationContext),我們可以通過從 BeanFactory 接口繼承的各種工廠方法創(chuàng)建 bean。

首先,我們創(chuàng)建一個簡單的應用程序配置:

@Configuration
@ComponentScan(basePackageClasses = ApplicationConfig.class)
public class ApplicationConfig {
}

接下來,我們創(chuàng)建一個簡單的類 Foo,它不接受構(gòu)造函數(shù)參數(shù):

@Component
public class Foo {
}

然后創(chuàng)建另一個接受單個構(gòu)造函數(shù)參數(shù)的類 Bar:

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Bar {
    private String name;
    public Bar(String name) {
        this.name = name;
    }
    // Getter ...
}

最后,我們通過 ApplicationContext 的 AnnotationConfigApplicationContext 實現(xiàn)創(chuàng)建我們的 bean:

@Test
public void whenGetSimpleBean_thenReturnConstructedBean() {
    ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
    Foo foo = context.getBean(Foo.class);
    assertNotNull(foo);
}
@Test
public void whenGetPrototypeBean_thenReturnConstructedBean() {
    String expectedName = "Some name";
    ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
    Bar bar = context.getBean(Bar.class, expectedName);
    assertNotNull(bar);
    assertThat(bar.getName(), is(expectedName));
}

使用 getBean 工廠方法,我們可以僅使用類類型和(在 Bar 的情況下)構(gòu)造函數(shù)參數(shù)來創(chuàng)建配置的 bean。

3.2 外部配置(External Configuration)

此模式是通用的,因為我們可以根據(jù)外部配置完全更改應用程序的行為。

如果我們希望更改應用程序中自動連線對象的實現(xiàn),我們可以調(diào)整我們使用的 ApplicationContext 實現(xiàn)。

Factory 1

例如,我們可以將 AnnotationConfigApplicationContext 更改為基于 XML 的配置類,例如 ClassPathXmlApplicationContext:

@Test 
public void givenXmlConfiguration_whenGetPrototypeBean_thenReturnConstructedBean() { 
    String expectedName = "Some name";
    ApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
    // Same test as before ...
}

4、代理模式(Proxy Pattern)

代理在我們的數(shù)字世界中是一種方便的工具,我們經(jīng)常在軟件(例如網(wǎng)絡代理)之外使用它們。在代碼中,代理模式是一種技術(shù),它允許一個對象(代理)控制對另一個對象(主體或服務)的訪問。

Proxy class diagram

4.1 事務

為了創(chuàng)建代理,我們創(chuàng)建一個對象,該對象實現(xiàn)與我們的主題相同的接口,并包含對主題的引用。

然后,我們可以使用代理代替主題。

在 Spring 里,bean 被代理以控制對底層 bean 的訪問。我們在使用事務時看到這種方法:

@Service
public class BookManager {
    @Autowired
    private BookRepository repository;
    @Transactional
    public Book create(String author) {
        System.out.println(repository.getClass().getName());
        return repository.create(author);
    }
}

在我們的 BookManager 類中,我們使用 @Transactional 注釋注釋創(chuàng)建方法。這個注釋指示 Spring 原子地執(zhí)行我們的創(chuàng)建方法。如果沒有代理,Spring 將無法控制對 BookRepository bean 的訪問并確保其事務一致性。

4.2 CGLib 代理(CGLib Proxies)

相反,Spring 創(chuàng)建了一個代理來包裝我們的 BookRepository bean,并檢測我們的 bean 以原子方式執(zhí)行我們的 create 方法。

當我們調(diào)用 BookManager#create 方法時,我們可以看到輸出:

com.baeldung.patterns.proxy.BookRepository$$EnhancerBySpringCGLIB$$3dc2b55c

通常,我們希望看到一個標準的 BookRepository 對象 ID;相反,我們看到一個 EnhancerBySpringCGLIB 對象 ID。

在底層,Spring 將我們的 BookRepository 對象包裝在里面作為 EnhancerBySpringCGLIB 對象。因此,Spring 控制了對 BookRepository 對象的訪問(確保事務一致性)。

Proxy

通常,Spring 使用兩種類型的代理:

  • CGLib 代理 – 在代理類時使用;
  • JDK 動態(tài)代理 – 在代理接口時使用

雖然我們使用事務來公開底層代理,但 Spring 將在必須控制對 bean 的訪問的任何場景中使用代理。

5、模版方法模式(Template Method Pattern)

在許多框架中,代碼的很大一部分是樣板代碼。

例如,在數(shù)據(jù)庫上執(zhí)行查詢時,必須完成相同的一系列步驟:

  • Establish a connection 建立連接
  • Execute query 執(zhí)行查詢
  • Perform cleanup 執(zhí)行清理
  • Close the connection 關(guān)閉連接

這些步驟是模板方法模式的理想方案。

5.1 模版和回調(diào)(Templates & Callbacks)

模板方法模式是一種技術(shù),用于定義某些操作所需的步驟,實現(xiàn)樣板步驟,并將可自定義的步驟保留為抽象。然后,子類可以實現(xiàn)此抽象類,并為缺少的步驟提供具體的實現(xiàn)。

我們可以在數(shù)據(jù)庫查詢的情況下創(chuàng)建一個模板:

public abstract DatabaseQuery {
    public void execute() {
        Connection connection = createConnection();
        executeQuery(connection);
        closeConnection(connection);
    } 
    protected Connection createConnection() {
        // Connect to database...
    }
    protected void closeConnection(Connection connection) {
        // Close connection...
    }
    protected abstract void executeQuery(Connection connection);
}

或者,我們可以通過提供回調(diào)方法來提供缺失的步驟。

回調(diào)方法是一種方法,它允許主體向客戶端發(fā)出信號,表明某些所需的操作已完成。

在某些情況下,主體可以使用此回調(diào)來執(zhí)行操作,例如映射結(jié)果。

Template

例如,我們可以為執(zhí)行方法提供一個查詢字符串和一個回調(diào)方法來處理結(jié)果,而不是一個 executeQuery 方法。

首先,我們創(chuàng)建一個回調(diào)方法,該方法采用 Result 對象并將其映射到 T 類型的對象:

public interface ResultsMapper<T> {
    public T map(Results results);
}

然后我們更改我們的 DatabaseQuery 類以利用此回調(diào):

public abstract DatabaseQuery {
    public <T> T execute(String query, ResultsMapper<T> mapper) {
        Connection connection = createConnection();
        Results results = executeQuery(connection, query);
        closeConnection(connection);
        return mapper.map(results);
    ]
    protected Results executeQuery(Connection connection, String query) {
        // Perform query...
    }
}

這種回調(diào)機制正是 Spring 在 JdbcTemplate 類中使用的方法。

5.2 JDBC 模版(JdbcTemplates)

JdbcTemplate 類提供查詢方法,該方法接受查詢字符串和 ResultSetExtractor 對象:

public class JdbcTemplate {
    public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {
        // Execute query...
    }
    // Other methods...
}

ResultSetExtractor 將 ResultSet 對象(表示查詢結(jié)果)轉(zhuǎn)換為類型 T 的域?qū)ο螅?/p>

@FunctionalInterface
public interface ResultSetExtractor<T> {
    T extractData(ResultSet rs) throws SQLException, DataAccessException;
}

Spring 通過創(chuàng)建更具體的回調(diào)接口進一步減少了樣板代碼。

例如,RowMapper 接口用于將單行 SQL 數(shù)據(jù)轉(zhuǎn)換為 T 類型的域?qū)ο蟆?/p>

@FunctionalInterface
public interface RowMapper<T> {
    T mapRow(ResultSet rs, int rowNum) throws SQLException;
}

為了使 RowMapper 接口適應預期的 ResultSetExtractor,Spring 創(chuàng)建了 RowMapperResultSetExtractor 類:

public class JdbcTemplate {
    public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException {
        return result(query(sql, new RowMapperResultSetExtractor<>(rowMapper)));
    }
    // Other methods...
}

我們可以提供如何轉(zhuǎn)換單個行的邏輯,而不是提供轉(zhuǎn)換整個 ResultSet 對象的邏輯,包括對行的迭代:

public class BookRowMapper implements RowMapper<Book> {
    @Override
    public Book mapRow(ResultSet rs, int rowNum) throws SQLException {
        Book book = new Book();
        book.setId(rs.getLong("id"));
        book.setTitle(rs.getString("title"));
        book.setAuthor(rs.getString("author"));
        return book;
    }
}

使用此轉(zhuǎn)換器,我們可以使用 JdbcTemplate 查詢數(shù)據(jù)庫并映射每個結(jié)果行:

JdbcTemplate template = // create template...
template.query("SELECT * FROM books", new BookRowMapper());

除了JDBC數(shù)據(jù)庫管理之外,Spring 還使用模板:

  • Java Message Service (JMS)
  • Java Persistence API (JPA)
  • Hibernate(現(xiàn)已棄用)
  • Transactions 事務

6、結(jié)論

上面,我們研究了 Spring 框架中應用的四種最常見的設計模式。

我們還探討了Spring如何利用這些模式來提供豐富的功能,同時減輕開發(fā)人員的負擔。

到此這篇關(guān)于Spring Framework六種常見設計模式的文章就介紹到這了,更多相關(guān)Spring設計模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Windows?10卸載JDK1.8超詳細圖文教程

    Windows?10卸載JDK1.8超詳細圖文教程

    這篇文章主要介紹了Windows?10卸載JDK1.8超詳細圖文教程,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-03-03
  • MyBatis高級映射ResultMap解決屬性問題

    MyBatis高級映射ResultMap解決屬性問題

    對于數(shù)據(jù)庫中對表的增刪改查操作,我們知道增刪改都涉及的是單表,而只有查詢操作既可以設計到單表操作又可以涉及到多表操作,所以對于輸入映射parameterType而言是沒有所謂的高級映射的,也就是說高級映射只針對于輸出映射
    2023-02-02
  • Json字符串轉(zhuǎn)Java對象和List代碼實例

    Json字符串轉(zhuǎn)Java對象和List代碼實例

    這篇文章主要介紹了Json字符串轉(zhuǎn)Java對象和List代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06
  • Java整合Jackson實現(xiàn)反序列化器流程

    Java整合Jackson實現(xiàn)反序列化器流程

    Jackson是一個開源的Java序列化和反序列化工具,可以將Java對象序列化為XML或JSON格式的字符串,以及將XML或JSON格式的字符串反序列化為Java對象。由于其使用簡單,速度較快,且不依靠除JDK外的其他庫,被眾多用戶所使用
    2023-01-01
  • IDEA無法創(chuàng)建JDK1.8版本的Springboot項目問題解決(2種方法)

    IDEA無法創(chuàng)建JDK1.8版本的Springboot項目問題解決(2種方法)

    本文主要介紹了IDEA無法創(chuàng)建JDK1.8版本的Springboot項目問題解決,包含兩種解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-07-07
  • Springboot常用注解及配置文件加載順序詳解

    Springboot常用注解及配置文件加載順序詳解

    這篇文章主要介紹了Springboot常用注解及配置文件加載順序,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-11-11
  • ThreadLocal內(nèi)存泄漏常見要點解析

    ThreadLocal內(nèi)存泄漏常見要點解析

    這篇文章主要介紹了ThreadLocal內(nèi)存泄漏常見要點,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-11-11
  • SpringBoot導入Druid運行失敗問題

    SpringBoot導入Druid運行失敗問題

    這篇文章主要介紹了SpringBoot導入Druid運行失敗,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • SpringBoot利用ThreadPoolTaskExecutor批量插入百萬級數(shù)據(jù)

    SpringBoot利用ThreadPoolTaskExecutor批量插入百萬級數(shù)據(jù)

    在處理大量數(shù)據(jù)時,為了提高效率和性能,通常需要采用批量插入的方式,本文主要介紹了SpringBoot利用ThreadPoolTaskExecutor批量插入百萬級數(shù)據(jù),具有一定的參考價值,感興趣的可以了解一下
    2024-03-03
  • SpringBoot 統(tǒng)一請求返回的實現(xiàn)

    SpringBoot 統(tǒng)一請求返回的實現(xiàn)

    這篇文章主要介紹了SpringBoot 統(tǒng)一請求返回的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07

最新評論