1. 程式人生 > >spring原始碼分析之spring-jdbc模組詳解

spring原始碼分析之spring-jdbc模組詳解

0 概述

Spring將替我們完成所有使用JDBC API進行開發的單調乏味的、底層細節處理工作。下表描述了哪些是spring幫助我們做好的,哪些是我們要做的。

Action  Spring  You
Define connection parameters.  X
Open the connection.  X
Specify the SQL statement.  X
Declare parameters and provide parameter values X
Prepare and execute the statement. X
Set up the loop to iterate through the results (if any). X
Do the work for each iteration. X
Process any exception.  X
Handle transactions.  X
Close the connection,statement and resultset. X

工作模式 
使用Spring進行基本的JDBC訪問資料庫有多種選擇。Spring至少提供了三種不同的工作模式:JdbcTemplate, 一個在Spring2.5中新提供的SimpleJdbc類能夠更好的處理資料庫元資料; 還有一種稱之為RDBMS Object的風格的面向物件封裝方式, 有點類似於JDO的查詢設計。 我們在這裡簡要列舉你採取某一種工作方式的主要理由. 不過請注意, 即使你選擇了其中的一種工作模式, 你依然可以在你的程式碼中混用其他任何一種模式以獲取其帶來的好處和優勢。 所有的工作模式都必須要求JDBC 2.0以上的資料庫驅動的支援, 其中一些高階的功能可能需要JDBC 3.0以上的資料庫驅動支援。 

JdbcTemplate - 這是經典的也是最常用的Spring對於JDBC訪問的方案。這也是最低級別的封裝, 其他的工作模式事實上在底層使用了JdbcTemplate作為其底層的實現基礎。JdbcTemplate在JDK 1.4以上的環境上工作得很好。 

NamedParameterJdbcTemplate - 對JdbcTemplate做了封裝,提供了更加便捷的基於命名引數的使用方式而不是傳統的JDBC所使用的“?”作為引數的佔位符。這種方式在你需要為某個SQL指定許多個引數時,顯得更加直觀而易用。該特性必須工作在JDK 1.4以上。 

SimpleJdbcTemplate - 這個類結合了JdbcTemplate和NamedParameterJdbcTemplate的最常用的功能,同時它也利用了一些Java 5的特性所帶來的優勢,例如泛型、varargs和autoboxing等,從而提供了更加簡便的API訪問方式。需要工作在Java 5以上的環境中。 

SimpleJdbcInsert 和 SimpleJdbcCall - 這兩個類可以充分利用資料庫元資料的特性來簡化配置。通過使用這兩個類進行程式設計,你可以僅僅提供資料庫表名或者儲存過程的名稱以及一個Map作為引數。其中Map的key需要與資料庫表中的欄位保持一致。這兩個類通常和SimpleJdbcTemplate配合使用。這兩個類需要工作在JDK 5以上,同時資料庫需要提供足夠的元資料資訊。 

RDBMS 物件包括MappingSqlQuery, SqlUpdate and StoredProcedure - 這種方式允許你在初始化你的資料訪問層時建立可重用並且執行緒安全的物件。該物件在你定義了你的查詢語句,宣告查詢引數並編譯相應的Query之後被模型化。一旦模型化完成,任何執行函式就可以傳入不同的引數對之進行多次呼叫。這種方式需要工作在JDK 1.4以上。

1. 異常處理

   異常結構如下:

 SQLExceptionTranslator是一個介面,如果你需要在 SQLException和org.springframework.dao.DataAccessException之間作轉換,那麼必須實現該介面。 轉換器類的實現可以採用一般通用的做法(比如使用JDBC的SQLState code),如果為了使轉換更準確,也可以進行定製(比如使用Oracle的error code)。 

SQLErrorCodeSQLExceptionTranslator是SQLExceptionTranslator的預設實現。 該實現使用指定資料庫廠商的error code,比採用SQLState更精確。轉換過程基於一個JavaBean(型別為SQLErrorCodes)中的error code。 這個JavaBean由SQLErrorCodesFactory工廠類建立,其中的內容來自於 “sql-error-codes.xml”配置檔案。該檔案中的資料庫廠商程式碼基於 Database MetaData 資訊中的DatabaseProductName,從而配合當前資料庫的使用。 

SQLErrorCodeSQLExceptionTranslator使用以下的匹配規則: 

首先檢查是否存在完成定製轉換的子類實現。通常SQLErrorCodeSQLExceptionTranslator 這個類可以作為一個具體類使用,不需要進行定製,那麼這個規則將不適用。 

接著將SQLException的error code與錯誤程式碼集中的error code進行匹配。 預設情況下錯誤程式碼集將從SQLErrorCodesFactory取得。 錯誤程式碼集來自classpath下的sql-error-codes.xml檔案,它們將與資料庫metadata資訊中的database name進行對映。 

使用fallback翻譯器。SQLStateSQLExceptionTranslator類是預設的fallback翻譯器。

2. config模組

  NamespaceHandler介面,DefaultBeanDefinitionDocumentReader使用該介面來處理在spring xml配置檔案中自定義的名稱空間。

在jdbc模組,我們使用JdbcNamespaceHandler來處理jdbc配置的名稱空間,其程式碼如下:

public class JdbcNamespaceHandler extends NamespaceHandlerSupport {

    @Override
    public void init() {
        registerBeanDefinitionParser("embedded-database", new EmbeddedDatabaseBeanDefinitionParser());
        registerBeanDefinitionParser("initialize-database", new InitializeDatabaseBeanDefinitionParser());
    }
}

其中,

EmbeddedDatabaseBeanDefinitionParser繼承了AbstractBeanDefinitionParser,解析<embedded-database>元素,並使用EmbeddedDatabaseFactoryBean建立一個BeanDefinition。順便介紹一下用到的軟體包 org.w3c.dom。

軟體包 org.w3c.dom:為文件物件模型 (DOM) 提供介面,該模型是 Java API for XML Processing 的元件 API。該 Document Object Model Level 2 Core API 允許程式動態訪問和更新文件的內容和結構。

Attr:Attr 介面表示 Element 物件中的屬性。
CDATASection: CDATA 節用於轉義文字塊,該文字塊包含的字元如果不轉義則會被視為標記。
CharacterData: CharacterData 介面使用屬性集合和用於訪問 DOM 中字元資料的方法擴充套件節點。
Comment: 此介面繼承自 CharacterData 表示註釋的內容,即起始 '<!--' 和結束 '-->' 之間的所有字元。
Document: Document 介面表示整個 HTML 或 XML 文件。
DocumentFragment: DocumentFragment 是“輕量級”或“最小”Document 物件。
DocumentType: 每個 Document 都有 doctype 屬性,該屬性的值可以為 null,也可以為 DocumentType 物件。
DOMConfiguration: 該 DOMConfiguration 介面表示文件的配置,並維護一個可識別的引數表。
DOMError: DOMError 是一個描述錯誤的介面。
DOMErrorHandler: DOMErrorHandler 是在報告處理 XML 資料時發生的錯誤或在進行某些其他處理(如驗證文件)時 DOM 實現可以呼叫的回撥介面。
DOMImplementation: DOMImplementation 介面為執行獨立於文件物件模型的任何特定例項的操作提供了許多方法。
DOMImplementationList: DOMImplementationList 介面提供對 DOM 實現的有序集合的抽象,沒有定義或約束如何實現此集合。
DOMImplementationSource: 此介面允許 DOM 實現程式根據請求的功能和版本提供一個或多個實現,如下所述。
DOMLocator: DOMLocator 是一個描述位置(如發生錯誤的位置)的介面。
DOMStringList: DOMStringList 介面提供對 DOMString 值的有序集合的抽象,沒有定義或約束此集合是如何實現的。
Element: Element 介面表示 HTML 或 XML 文件中的一個元素。
Entity: 此介面表示在 XML 文件中解析和未解析的已知實體。
EntityReference: EntityReference 節點可以用來在樹中表示實體引用。
NamedNodeMap: 實現 NamedNodeMap 介面的物件用於表示可以通過名稱訪問的節點的集合。
NameList NameList 介面提供對並行的名稱和名稱空間值對(可以為 null 值)的有序集合的抽象,無需定義或約束如何實現此集合。
Node: 該 Node 介面是整個文件物件模型的主要資料型別。
NodeList: NodeList 介面提供對節點的有序集合的抽象,沒有定義或約束如何實現此集合。
Notation: 此介面表示在 DTD 中宣告的表示法。
ProcessingInstruction: ProcessingInstruction 介面表示“處理指令”,該指令作為一種在文件的文字中保持特定於處理器的資訊的方法在 XML 中使用。
Text: 該 Text 介面繼承自 CharacterData,並且表示 Element 或 Attr 的文字內容(在 XML 中稱為 字元資料)。
TypeInfo: TypeInfo 介面表示從 Element 或 Attr 節點引用的型別,用與文件相關的模式指定。
UserDataHandler: 當使用 Node.setUserData() 將一個物件與節點上的鍵相關聯時,當克隆、匯入或重新命名該物件關聯的節點時應用程式可以提供呼叫的處理程式。

 3. core模組

     3.1 NativeJdbcExtractor 從執行緒池中的封裝的物件中提取出本地的jdbc物件,其結構如下:

其實現原理如下(以c3po為例):

    /**
     * Retrieve the Connection via C3P0's {@code rawConnectionOperation} API,
     * using the {@code getRawConnection} as callback to get access to the
     * raw Connection (which is otherwise not directly supported by C3P0).
     * @see #getRawConnection
     */
    @Override
    protected Connection doGetNativeConnection(Connection con) throws SQLException {
        if (con instanceof C3P0ProxyConnection) {
            C3P0ProxyConnection cpCon = (C3P0ProxyConnection) con;
            try {
                return (Connection) cpCon.rawConnectionOperation(
                        this.getRawConnectionMethod, null, new Object[] {C3P0ProxyConnection.RAW_CONNECTION});
            }
            catch (SQLException ex) {
                throw ex;
            }
            catch (Exception ex) {
                ReflectionUtils.handleReflectionException(ex);
            }
        }
        return con;
    }

上述程式碼通過呼叫C3P0的rawConnectionOperation api來獲取Connection,使用getRawConnection的回撥方法來獲取原生的Connection(C3P0不直接支援原生的Connection)。

NativeJdbcExtractorAdapter是NativeJdbcExtractor的一個簡單實現,它的getNativeConnection()方法檢查ConnectionProxy鏈,並且代理doGetNativeConnection方法。Spring的TransactionAwareDataSourceProxy和LazyConnectionDataSourceProxy使用ConnectionProxy。目標Connection置於本地連線池中,被子類實現的doGetNativeConnection的方法去掉封裝獲取到原生的Connection。其實現如下:

@Override
    public Connection getNativeConnection(Connection con) throws SQLException {
        if (con == null) {
            return null;
        }
        Connection targetCon = DataSourceUtils.getTargetConnection(con);
        Connection nativeCon = doGetNativeConnection(targetCon);
        if (nativeCon == targetCon) {
            // We haven't received a different Connection, so we'll assume that there's
            // some additional proxying going on. Let's check whether we get something
            // different back from the DatabaseMetaData.getConnection() call.
            DatabaseMetaData metaData = targetCon.getMetaData();
            // The following check is only really there for mock Connections
            // which might not carry a DatabaseMetaData instance.
            if (metaData != null) {
                Connection metaCon = metaData.getConnection();
                if (metaCon != null && metaCon != targetCon) {
                    // We've received a different Connection there:
                    // Let's retry the native extraction process with it.
                    nativeCon = doGetNativeConnection(metaCon);
                }
            }
        }
        return nativeCon;
    }

  3.2 RowMapper

3.3 元資料metaData模組

本節中spring應用到工廠模式,結合程式碼可以更具體瞭解。

CallMetaDataProviderFactory建立CallMetaDataProvider的工廠類,其程式碼如下:

/** List of supported database products for procedure calls */
    public static final List<String> supportedDatabaseProductsForProcedures = Arrays.asList(
            "Apache Derby",
            "DB2",
            "MySQL",
            "Microsoft SQL Server",
            "Oracle",
            "PostgreSQL",
            "Sybase"
        );
    /** List of supported database products for function calls */
    public static final List<String> supportedDatabaseProductsForFunctions = Arrays.asList(
            "MySQL",
            "Microsoft SQL Server",
            "Oracle",
            "PostgreSQL"
        );

    /**
     * Create a CallMetaDataProvider based on the database metadata
     * @param dataSource used to retrieve metadata
     * @param context the class that holds configuration and metadata
     * @return instance of the CallMetaDataProvider implementation to be used
     */
    static public CallMetaDataProvider createMetaDataProvider(DataSource dataSource, final CallMetaDataContext context) {
        try {
            return (CallMetaDataProvider) JdbcUtils.extractDatabaseMetaData(dataSource, new DatabaseMetaDataCallback() {
                @Override
                public Object processMetaData(DatabaseMetaData databaseMetaData) throws SQLException, MetaDataAccessException {
                    String databaseProductName = JdbcUtils.commonDatabaseName(databaseMetaData.getDatabaseProductName());
                    boolean accessProcedureColumnMetaData = context.isAccessCallParameterMetaData();
                    if (context.isFunction()) {
                        if (!supportedDatabaseProductsForFunctions.contains(databaseProductName)) {
                            if (logger.isWarnEnabled()) {
                                logger.warn(databaseProductName + " is not one of the databases fully supported for function calls " +
                                        "-- supported are: " + supportedDatabaseProductsForFunctions);
                            }
                            if (accessProcedureColumnMetaData) {
                                logger.warn("Metadata processing disabled - you must specify all parameters explicitly");
                                accessProcedureColumnMetaData = false;
                            }
                        }
                    }
                    else {
                        if (!supportedDatabaseProductsForProcedures.contains(databaseProductName)) {
                            if (logger.isWarnEnabled()) {
                                logger.warn(databaseProductName + " is not one of the databases fully supported for procedure calls " +
                                        "-- supported are: " + supportedDatabaseProductsForProcedures);
                            }
                            if (accessProcedureColumnMetaData) {
                                logger.warn("Metadata processing disabled - you must specify all parameters explicitly");
                                accessProcedureColumnMetaData = false;
                            }
                        }
                    }

                    CallMetaDataProvider provider;
                    if ("Oracle".equals(databaseProductName)) {
                        provider = new OracleCallMetaDataProvider(databaseMetaData);
                    }
                    else if ("DB2".equals(databaseProductName)) {
                        provider = new Db2CallMetaDataProvider((databaseMetaData));
                    }
                    else if ("Apache Derby".equals(databaseProductName)) {
                        provider = new DerbyCallMetaDataProvider((databaseMetaData));
                    }
                    else if ("PostgreSQL".equals(databaseProductName)) {
                        provider = new PostgresCallMetaDataProvider((databaseMetaData));
                    }
                    else if ("Sybase".equals(databaseProductName)) {
                        provider = new SybaseCallMetaDataProvider((databaseMetaData));
                    }
                    else if ("Microsoft SQL Server".equals(databaseProductName)) {
                        provider = new SqlServerCallMetaDataProvider((databaseMetaData));
                    }
                    else {
                        provider = new GenericCallMetaDataProvider(databaseMetaData);
                    }
                    if (logger.isDebugEnabled()) {
                        logger.debug("Using " + provider.getClass().getName());
                    }
                    provider.initializeWithMetaData(databaseMetaData);
                    if (accessProcedureColumnMetaData) {
                        provider.initializeWithProcedureColumnMetaData(
                                databaseMetaData, context.getCatalogName(), context.getSchemaName(), context.getProcedureName());
                    }
                    return provider;
                }
            });
        }
        catch (MetaDataAccessException ex) {
            throw new DataAccessResourceFailureException("Error retreiving database metadata", ex);
        }

    }

TableMetaDataProviderFactory建立TableMetaDataProvider工廠類,其建立過程如下:

/**
     * Create a TableMetaDataProvider based on the database metedata
     * @param dataSource used to retrieve metedata
     * @param context the class that holds configuration and metedata
     * @param nativeJdbcExtractor the NativeJdbcExtractor to be used
     * @return instance of the TableMetaDataProvider implementation to be used
     */
    public static TableMetaDataProvider createMetaDataProvider(DataSource dataSource,
                final TableMetaDataContext context, final NativeJdbcExtractor nativeJdbcExtractor) {
        try {
            return (TableMetaDataProvider) JdbcUtils.extractDatabaseMetaData(dataSource,
                    new DatabaseMetaDataCallback() {
                        @Override
                        public Object processMetaData(DatabaseMetaData databaseMetaData) throws SQLException {
                            String databaseProductName =
                                    JdbcUtils.commonDatabaseName(databaseMetaData.getDatabaseProductName());
                            boolean accessTableColumnMetaData = context.isAccessTableColumnMetaData();
                            TableMetaDataProvider provider;
                            if ("Oracle".equals(databaseProductName)) {
                                provider = new OracleTableMetaDataProvider(databaseMetaData,
                                        context.isOverrideIncludeSynonymsDefault());
                            }
                            else if ("HSQL Database Engine".equals(databaseProductName)) {
                                provider = new HsqlTableMetaDataProvider(databaseMetaData);
                            }
                            else if ("PostgreSQL".equals(databaseProductName)) {
                                provider = new PostgresTableMetaDataProvider(databaseMetaData);
                            }
                            else if ("Apache Derby".equals(databaseProductName)) {
                                provider = new DerbyTableMetaDataProvider(databaseMetaData);
                            }
                            else {
                                provider = new GenericTableMetaDataProvider(databaseMetaData);
                            }
                            if (nativeJdbcExtractor != null) {
                                provider.setNativeJdbcExtractor(nativeJdbcExtractor);
                            }
                            if (logger.isDebugEnabled()) {
                                logger.debug("Using " + provider.getClass().getSimpleName());
                            }
                            provider.initializeWithMetaData(databaseMetaData);
                            if (accessTableColumnMetaData) {
                                provider.initializeWithTableColumnMetaData(databaseMetaData, context.getCatalogName(),
                                        context.getSchemaName(), context.getTableName());
                            }
                            return provider;
                        }
                    });
        }
        catch (MetaDataAccessException ex) {
            throw new DataAccessResourceFailureException("Error retrieving database metadata", ex);
        }
    }

 3.4 使用SqlParameterSource提供引數值 
使用Map來指定引數值有時候工作得非常好,但是這並不是最簡單的使用方式。Spring提供了一些其他的SqlParameterSource實現類來指定引數值。 我們首先可以看看BeanPropertySqlParameterSource類,這是一個非常簡便的指定引數的實現類,只要你有一個符合JavaBean規範的類就行了。它將使用其中的getter方法來獲取引數值。

SqlParameter 封裝了定義sql 引數的物件。

CallableStateMentCallback,PrePareStateMentCallback,StateMentCallback,ConnectionCallback回撥類分別對應JdbcTemplate中的不同處理方法。

3.5 simple實現

4. DataSource

      spring通過DataSource獲取資料庫的連線。Datasource是jdbc 規範的一部分,它通過ConnectionFactory獲取。一個容器和框架可以在應用程式碼層中隱藏連線池和事務管理。

     當使用spring的jdbc層,你可以通過JNDI來獲取DataSource,也可以通過你自己配置的第三方連線池實現來獲取。流行的第三方實現由apache Jakarta Commons dbcp和c3p0.

TransactionAwareDataSourceProxy作為目標DataSource的一個代理, 在對目標DataSource包裝的同時,還增加了Spring的事務管理能力, 在這一點上,這個類的功能非常像J2EE伺服器所提供的事務化的JNDI DataSource。 

Note 
該類幾乎很少被用到,除非現有程式碼在被呼叫的時候需要一個標準的 JDBC DataSource介面實現作為引數。 這種情況下,這個類可以使現有程式碼參與Spring的事務管理。通常最好的做法是使用更高層的抽象 來對資料來源進行管理,比如JdbcTemplate和DataSourceUtils等等。

注意:DriverManagerDataSource僅限於測試使用,因為它沒有提供池的功能,這會導致在多個請求獲取連線時效能很差。

5. object模組

6. JdbcTemplate是core包的核心類。

它替我們完成了資源的建立以及釋放工作,從而簡化了我們對JDBC的使用。 它還可以幫助我們避免一些常見的錯誤,比如忘記關閉資料庫連線。 JdbcTemplate將完成JDBC核心處理流程,比如SQL語句的建立、執行,而把SQL語句的生成以及查詢結果的提取工作留給我們的應用程式碼。 它可以完成SQL查詢、更新以及呼叫儲存過程,可以對ResultSet進行遍歷並加以提取。 它還可以捕獲JDBC異常並將其轉換成org.springframework.dao包中定義的,通用的,資訊更豐富的異常。 

使用JdbcTemplate進行編碼只需要根據明確定義的一組契約來實現回撥介面。 PreparedStatementCreator回撥介面通過給定的Connection建立一個PreparedStatement,包含SQL和任何相關的引數。 CallableStatementCreateor實現同樣的處理,只不過它建立的是CallableStatement。 RowCallbackHandler介面則從資料集的每一行中提取值。 

我們可以在DAO實現類中通過傳遞一個DataSource引用來完成JdbcTemplate的例項化,也可以在Spring的IoC容器中配置一個JdbcTemplate的bean並賦予DAO實現類作為一個例項。 需要注意的是DataSource在Spring的IoC容器中總是配製成一個bean,第一種情況下,DataSource bean將傳遞給service,第二種情況下DataSource bean傳遞給JdbcTemplate bean。

7. NamedParameterJdbcTemplate類為JDBC操作增加了命名引數的特性支援,而不是傳統的使用('?')作為引數的佔位符。NamedParameterJdbcTemplate類對JdbcTemplate類進行了封裝, 在底層,JdbcTemplate完成了多數的工作。

小結:

傳統的JDBC對資料庫的操作,有很多重複的程式碼,這樣給程式設計師帶來了很多額外的工作量,Spring提供了JDBC模板很好的解決了這個問題,由於傳統的方法比較簡單,在這裡不介紹了,直接說模板吧。 使用JDBC模板:     Spring的JDBC框架能夠承擔資源管理和異常處理的工作。對於JDBC來說,Spring提供了3個模板類
  • JdbcTemplate:Spring裡最基本的JDBC模板,利用JDBC和簡單的索引引數查詢提供對資料庫的簡單訪問。
  • NamedParameterJdbcTemplate:能夠在執行查詢時把值繫結到SQL裡的命名引數,而不是使用索引引數。
  • SimpleJdbcTemplate:利用Java 5 的特性,比如自動裝箱、通用(generic)和可變引數類表來簡化JDBC模板的使用。

 參考文獻:

http://www.360doc.com/content/14/0625/22/834950_389749909.shtml

http://www.360doc.com/content/14/0625/23/834950_389759601.shtml

相關推薦

spring原始碼分析spring-jdbc模組

0 概述 Spring將替我們完成所有使用JDBC API進行開發的單調乏味的、底層細節處理工作。下表描述了哪些是spring幫助我們做好的,哪些是我們要做的。 Action  Spring  You Define connection parameters.  X

spring原始碼分析spring-messaging模組

0 概述 spring-messaging模組為整合messaging api和訊息協議提供支援。 其程式碼結構為: 其中base定義了訊息Message(MessageHeader和body)、訊息處理MessageHandler、傳送訊息MessageChann

Spring原始碼分析Spring MVCHanderMapping請求對映處理

AbstractHandlerMappig呼叫getHandler() /** * Look up a handler for the given request, falling back to the default * handler if no speci

netty原始碼分析-SimpleChannelInboundHandler與ChannelInboundHandlerAdapter(6)

每一個Handler都一定會處理出站或者入站(也可能兩者都處理)資料,例如對於入站的Handler可能會繼承SimpleChannelInboundHandler或者ChannelInboundHandlerAdapter,而SimpleChannelIn

MyBatis原始碼分析@SelectProvider註解使用

MyBatis原始碼分析之@SelectProvider註解使用詳解 之前講了MyBatis的配置、plugin、Select查詢,還有@MapKey註解的使用與原理,還有返回@ResultMap等等,我原想直接從MyBatis的快取開始說起,但是想想還是得說一下MyBatis中的@

jQuery原始碼分析jQuery(selector,context)

首先我們給出下面的HTML程式碼: <div id="parent" class="parent"> <div class="child"> child1 </div> <div class="child">

Spring原始碼分析Bean的建立過程

前文傳送門: 1. [Spring原始碼分析之預啟動流程](https://mp.weixin.qq.com/s/bfbPJOlYo2Vz2UTSMWRGkw) 2. [Spring原始碼分析之BeanFactory體系結構](https://mp.weixin.qq.com/s/FDx0hmCp7dEfw

Spring5原始碼分析Spring

前言 因為本人打算仿照Spring寫個小型Spring–TinySpring,所以要閱讀Spring原始碼,在閱讀原始碼過程中的發現就記錄於此,如果有什麼錯誤,歡迎指出,我會及時更正。 正文 Disp

Spring原始碼分析ProxyFactoryBean方式實現Aop功能的分析

實現Aop功能有兩種方式, 1. ProxyFactoryBean方式: 這種方式是通過配置實現 2. ProxyFactory方式:這種方式是通過程式設計實現 這裡只說ProxyFactoryBean方式 首先說下具體的配置,一個例子如下: <bean id="t

Spring 3.1新特性二:@Enable*註解的原始碼,spring原始碼分析定時任務Scheduled註解

分析SpringBoot的自動化配置原理的時候,可以觀察下這些@Enable*註解的原始碼,可以發現所有的註解都有一個@Import註解。@Import註解是用來匯入配置類的,這也就是說這些自動開啟的實現其實是匯入了一些自動配置的Bean。 如:freemarker的自動化配置類FreeMarkerAuto

spring原始碼分析@ImportSelector、@Import、ImportResource工作原理分析

/** * Apply processing and build a complete {@link ConfigurationClass} by reading the * annotations, members and methods from the source class.

Mybatis原始碼分析Spring與Mybatis整合MapperScannerConfigurer處理過程原始碼分析

        前面文章分析了這麼多關於Mybatis原始碼解析,但是我們最終使用的卻不是以前面文章的方式,編寫自己mybatis_config.xml,而是最終將配置融合在spring的配置檔案中。有了前面幾篇部落格的分析,相信這裡會容易理解些關於Mybatis的初始化及

Spring原始碼分析IOC(五)

前面已經分析ObtainFreshBeanfactory()這個方法是解析和註冊bean,例項化IOC容器的。 重新看一下refresh()方法 @Override public void refresh() throws BeansExcept

Spring原始碼分析IOC(七)

前面分析了finishBeanFactoryInitialization();留一下了doGetBean()這個方法,由於這個方法是Spring IOC的例項化真正工作的方法,所以特地拿出來單獨來說。 doGetBean()方法太長,下面截圖按照順序剪下來的話

Spring原始碼分析BeanPostProcessor介面和BeanFactoryPostProcessor介面方法不執行原因分析

首先下面是我的Bean /* * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License

Spring原始碼分析事務

Spring提供一流的事務管理,分為宣告式事務和程式設計式事務。 1 Spring的事務 事務是一組任務組成的工作單元,執行的結果是要麼全部執行,要麼都不執行。 Spring事務的優點:  提供統一的程式設計模式  提供更簡單,更易用的事務管理   支援宣告事務    整合

Spring原始碼分析容器初始化

AnnotationConfigApplicationContext 核心類,BeanDefinition註冊器,所有的BeanD

Springboot原始碼分析Spring迴圈依賴揭祕

摘要: 若你是一個有經驗的程式設計師,那你在開發中必然碰到過這種現象:事務不生效。或許剛說到這,有的小夥伴就會大驚失色了。Spring不是解決了迴圈依賴問題嗎,它是怎麼又會發生迴圈依賴的呢?,接下來就讓我們一起揭祕Spring迴圈依賴的最本質原因。 Spring迴圈依賴流程圖 Spring迴圈依賴發生原因

Spring原始碼分析-載入IOC容器

本文接上一篇文章 SpringIOC 原始碼,控制反轉前的處理(https://mp.weixin.qq.com/s/9RbVP2ZQVx9-vKngqndW1w) 繼續進行下面的分析 首先貼出 Spring bean容器的重新整理的核心 11個步驟進行祭拜(一定要讓我學會了...阿門) // 完成IoC容

Spring原始碼分析IOC的三種常見用法及原始碼實現(二)

Spring原始碼分析之IOC的三種常見用法及原始碼實現(二) 回顧上文 我們研究的是 AnnotationConfigApplicationContext annotationConfigApplication = new AnnotationConfigApplicationContext