1. 程式人生 > >【Spring實戰】----原始碼解析SessionFactory及Session的管理及getCurrentSession的使用

【Spring實戰】----原始碼解析SessionFactory及Session的管理及getCurrentSession的使用

在上一篇Hibernate5整合中當使用sessionFactory.getCurrentSession()時會報錯Could not obtain transaction-synchronized Session for current thread,本篇就從原始碼角度解析下sessionFactory.getCurrentSession()。

一、Contextual sessionssession上下文)

先看下hibernate官方文件對session上下文的解釋:

8.4. Contextual sessions
Most applications using Hibernate need some form of contextual session, where a given session is in effect throughout the scope of a given context. However, across applications the definition of what constitutes a context is typically different; different contexts define different scopes to the notion of current. Applications using Hibernate prior to version 3.0 tended to utilize either home-grown ThreadLocal-based contextual sessions, helper classes such as HibernateUtil, or utilized third-party frameworks, such as Spring or Pico, which provided proxy/interception-based contextual sessions.
Starting with version 3.0.1, Hibernate added the SessionFactory.getCurrentSession() method. Initially, this assumed usage of JTA transactions, where the JTA transaction defined both the scope and context of a current session. Given the maturity of the numerous stand-alone JTA TransactionManager implementations, most, if not all, applications should be using JTA transaction management, whether or not they are deployed into a J2EE container. Based on that, the JTA-based contextual sessions are all you need to use.
However, as of version 3.1, the processing behind SessionFactory.getCurrentSession() is now pluggable. To that end, a new extension interface, org.hibernate.context.spi.CurrentSessionContext, and a new configuration parameter, hibernate.current_session_context_class, have been added to allow pluggability of the scope and context of defining current sessions.
See the Javadocs for the org.hibernate.context.spi.CurrentSessionContext interface for a detailed discussion of its contract. It defines a single method, currentSession(), by which the implementation is responsible for tracking the current contextual session. Out-of-the-box, Hibernate comes with three implementations of this interface:
org.hibernate.context.internal.JTASessionContext
current sessions are tracked and scoped by a JTA transaction. The processing here is exactly the same as in the older JTA-only approach. See the Javadocs for more details.
•org.hibernate.context.internal.ThreadLocalSessionContext:current sessions are tracked by thread of execution. See the Javadocs for more details.
•org.hibernate.context.internal.ManagedSessionContext: current sessions are tracked by thread of execution. However, you are responsible to bind and unbind a Session instance with static methods on this class: it does not open, flush, or close a Session. See the Javadocs for details.
Typically, the value of this parameter would just name the implementation class to use. For the three out-of-the-box implementations, however, there are three corresponding short names: jta, thread, and managed.
The first two implementations provide a one session - one database transaction programming model. This is also known and used as session-per-request. The beginning and end of a Hibernate session is defined by the duration of a database transaction. If you use programmatic transaction demarcation in plain Java SE without JTA, you are advised to use the Hibernate Transaction API to hide the underlying transaction system from your code. If you use JTA, you can utilize the JTA interfaces to demarcate transactions. If you execute in an EJB container that supports CMT, transaction boundaries are defined declaratively and you do not need any transaction or session demarcation operations in your code. Refer to Transactions and concurrency control for more information and code examples.
The hibernate.current_session_context_class configuration parameter defines which org.hibernate.context.spi.CurrentSessionContext implementation should be used. For backwards compatibility, if this configuration parameter is not set but a org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform is configured, Hibernate will use the org.hibernate.context.internal.JTASessionContext.

篇幅較長,大概翻譯如下:

大多數應用程式使用 Hibernate 時需要某種形式的 session“ 上下文” ,一個特定的 session(會話)影響整體特定的上下文範圍。然而,跨應用程式的組建上下文是很難的;目前的觀點是:不同的上下文定義了不同的範圍。在Hibernate3 以前,應用程式使用 session 有兩種方式:一種是利用ThreadLocal(本地執行緒)加上輔助類如:HibernateUtil,建立 session(會話);另一種是使用第三方框架,如:Spring、Pico,它們提供基於上下文的,session(會話)的代理/攔截。從 Hibernate3.0.1 版開始,加 Sessionfactory.getcurrentsession()方法。最初此方法使用 JTA 的事務處理。在 JTA 自己的範圍中與當前會話中一起使用。由此可以使用很成熟的 JTA TransactionManager(JTA 事務管理)實現。但是這要求所有應用程式都用 JTA 事務管理,不管這個應用程式是否部署在 J2EE容器中,你的 session 一定要使用基於 JTA 的上下文。然而,從 Hibernate3.1 以後,SessionFactory.getCurrentSession()可以變成外掛式的,為此一個新的擴充套件介面org.hibernate.context.spi.CurrentSessionContext 與一個新的配置引數hibernate.current_session_context_class 產生了,通過這一變化,允許定
義可插拔的上下文範圍與當前會話。參考 JAVA 文件中 org.hibernate.context.spi.CurrentSessionContext 介面,其中詳細討論了這一約定。介面定義了唯一方法 currentSession(),這個方法的實現類可以跟蹤當前會話的上下文。在外部 Hibernate 允許用三種方法來實現這一介面:org.hibernate.context.internal.JTASessionContext:由 JTA 事務界定當前會話範圍與跟蹤當前會話。這種處理方式與原來版本是完全一樣。詳情見javadocs。org.hibernate.context.internal.ThreadLocalSessionContext:由執行的執行緒跟蹤當前會話。詳情見 javadocs。
org.hibernate.context.internal.ManagedSessionContext:由執行的執行緒跟蹤當前會話。然而你自己負責繫結與解綁 Session(會話)例項,這些通常在類的靜態方法中,這時 Session(會話)不能開啟,關閉,重新整理,詳情見javadocs。通常,這個引數的值將被命名為使用的實現類。當通過外部外掛來實現,這些要分別要對應三個短語:"jta","thread","managed"。前兩種實現都提供了“ one session - one database transaction(一會話,一事務)” 開發模式。這也可以稱為“session-per-request(每請求一會話)”模式。開始結束一個 Hibernate 會話都是在資料庫事務過程中定義的。如果計劃使用經典的 JSE 平臺的事務處理流程,而不使用 JTA 事務,建議在你的程式碼中用hibernateTransaction(事務)API 來代替系統底層的事務過程。如果你使用JTA,你可以利用 JTA 介面來定義事務。如果你執行在支援 CMT 的 EJB 容器中,事務以宣告的方式定義,你的程式碼中將不用處理事務與會話的操作。參考第 6 章,事務與併發控制有更多的資訊與程式碼示例。hibernate.current_session_context_class 配置引數為org.hibernate.context.spi.CurrentSessionContext。為了向後相容,如果沒有設定此引數,但是org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform 被設定,hibernate 將使用 org.hibernate.context.internal.JTASessionContext。


另外,說下openSession和getCurrentSession方法的區別:


也就是說getCurrentSession的使用是依賴事務的。在非 Spring環境下,CurrentSessionContext的實現是由 “hibernate.current_session_context_class”屬性來控制的。但是在Spring環境 下,CurrentSessionContext的實現則變成了 SpringSessionContext或者SpringJtaSessionContext 。下面看下spring整合hibernate時CurrentSessionContext為什麼是SpringSessionContext。

二、從配置檔案中的org.springframework.orm.hibernate5.LocalSessionFactoryBean說起

LocalSessionFactoryBean實現了InitializingBean介面,因此屬性配置完後會執行afterPropertiesSet方法

@Override
	public void afterPropertiesSet() throws IOException {
		LocalSessionFactoryBuilder sfb = new LocalSessionFactoryBuilder(
				this.dataSource, getResourceLoader(), getMetadataSources());

		if (this.configLocations != null) {
			for (Resource resource : this.configLocations) {
				// Load Hibernate configuration from given location.
				sfb.configure(resource.getURL());
			}
		}

		if (this.mappingResources != null) {
			// Register given Hibernate mapping definitions, contained in resource files.
			for (String mapping : this.mappingResources) {
				Resource mr = new ClassPathResource(mapping.trim(), this.resourcePatternResolver.getClassLoader());
				sfb.addInputStream(mr.getInputStream());
			}
		}

		if (this.mappingLocations != null) {
			// Register given Hibernate mapping definitions, contained in resource files.
			for (Resource resource : this.mappingLocations) {
				sfb.addInputStream(resource.getInputStream());
			}
		}

		if (this.cacheableMappingLocations != null) {
			// Register given cacheable Hibernate mapping definitions, read from the file system.
			for (Resource resource : this.cacheableMappingLocations) {
				sfb.addCacheableFile(resource.getFile());
			}
		}

		if (this.mappingJarLocations != null) {
			// Register given Hibernate mapping definitions, contained in jar files.
			for (Resource resource : this.mappingJarLocations) {
				sfb.addJar(resource.getFile());
			}
		}

		if (this.mappingDirectoryLocations != null) {
			// Register all Hibernate mapping definitions in the given directories.
			for (Resource resource : this.mappingDirectoryLocations) {
				File file = resource.getFile();
				if (!file.isDirectory()) {
					throw new IllegalArgumentException(
							"Mapping directory location [" + resource + "] does not denote a directory");
				}
				sfb.addDirectory(file);
			}
		}

		if (this.entityInterceptor != null) {
			sfb.setInterceptor(this.entityInterceptor);
		}

		if (this.implicitNamingStrategy != null) {
			sfb.setImplicitNamingStrategy(this.implicitNamingStrategy);
		}

		if (this.physicalNamingStrategy != null) {
			sfb.setPhysicalNamingStrategy(this.physicalNamingStrategy);
		}

		if (this.jtaTransactionManager != null) {
			sfb.setJtaTransactionManager(this.jtaTransactionManager);
		}

		if (this.multiTenantConnectionProvider != null) {
			sfb.setMultiTenantConnectionProvider(this.multiTenantConnectionProvider);
		}

		if (this.currentTenantIdentifierResolver != null) {
			sfb.setCurrentTenantIdentifierResolver(this.currentTenantIdentifierResolver);
		}

		if (this.entityTypeFilters != null) {
			sfb.setEntityTypeFilters(this.entityTypeFilters);
		}

		if (this.hibernateProperties != null) {
			sfb.addProperties(this.hibernateProperties);
		}

		if (this.annotatedClasses != null) {
			sfb.addAnnotatedClasses(this.annotatedClasses);
		}

		if (this.annotatedPackages != null) {
			sfb.addPackages(this.annotatedPackages);
		}

		if (this.packagesToScan != null) {
			sfb.scanPackages(this.packagesToScan);
		}

		// Build SessionFactory instance.
		this.configuration = sfb;
		this.sessionFactory = buildSessionFactory(sfb);
	}

程式碼那麼長,其實就是建立了LocalSessionFactoryBuilder,以及根據LocalSessionFactoryBuilder建立SessionFactory,buildSessionFactory。其實從這裡就可以看出spring整合hibernate時,就是將Hibernate中用到的資料來源DataSource、SessionFactory例項及事務管理器都交由Spring容器管理,由Spring向開發人員提供統一的模板化操作。這裡再熟悉下單純Hibernate的工作原理:

言歸正傳,首先看下LocalSessionFactoryBuilder,LocalSessionFactoryBuilder.java

/**
	 * Create a new LocalSessionFactoryBuilder for the given DataSource.
	 * @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
	 * (may be {@code null})
	 * @param resourceLoader the ResourceLoader to load application classes from
	 * @param metadataSources the Hibernate MetadataSources service to use (e.g. reusing an existing one)
	 * @since 4.3
	 */
	public LocalSessionFactoryBuilder(DataSource dataSource, ResourceLoader resourceLoader, MetadataSources metadataSources) {
		super(metadataSources);

		getProperties().put(Environment.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext.class.getName());              //這裡設定了SpringSessionContext
		if (dataSource != null) {
			getProperties().put(Environment.DATASOURCE, dataSource);
		}

		// Hibernate 5.2: manually enforce connection release mode ON_CLOSE (the former default)
		getProperties().put("hibernate.connection.handling_mode", "DELAYED_ACQUISITION_AND_HOLD");

		getProperties().put(AvailableSettings.CLASSLOADERS, Collections.singleton(resourceLoader.getClassLoader()));
		this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
	}

注意這裡設定的SpringSessionContext,後面用到的就是這裡設定的,因此如果配置檔案中沒有設定

 String CURRENT_SESSION_CONTEXT_CLASS = "hibernate.current_session_context_class";Spring整合Hibernate會使用SpringSessionContext。如果設定了會使用設定的,並且設定的要為org.springframework.orm.hibernate5.SpringSessionContext,並且要用spring的事物管理,否則會報錯,比如用spring整合卻設定為<prop key="hibernate.current_session_context_class">thread</prop>,會報錯createQuery is not valid without active transaction(原因是設定為thread時用的是ThreadLocalSessionContext,這個時候需要手動開啟事務)。

再看buildSessionFactory

/**
	 * Subclasses can override this method to perform custom initialization
	 * of the SessionFactory instance, creating it via the given Configuration
	 * object that got prepared by this LocalSessionFactoryBean.
	 * <p>The default implementation invokes LocalSessionFactoryBuilder's buildSessionFactory.
	 * A custom implementation could prepare the instance in a specific way (e.g. applying
	 * a custom ServiceRegistry) or use a custom SessionFactoryImpl subclass.
	 * @param sfb LocalSessionFactoryBuilder prepared by this LocalSessionFactoryBean
	 * @return the SessionFactory instance
	 * @see LocalSessionFactoryBuilder#buildSessionFactory
	 */
	protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
		return (this.bootstrapExecutor != null ? sfb.buildSessionFactory(this.bootstrapExecutor) :
				sfb.buildSessionFactory());
	}

這裡bootstrapExecutor沒有配置,走sfb.buildSessionFactory()

其中過程省略,最終建立的是SessionFactoryImpl例項

@Override
	public SessionFactory build() {
		metadata.validate();
		return new SessionFactoryImpl( metadata, buildSessionFactoryOptions() );
	}

看SessionFactoryImpl建構函式,很長,只關注buildCurrentSessionContext();

public SessionFactoryImpl(final MetadataImplementor metadata, SessionFactoryOptions options) {
		LOG.debug( "Building session factory" );

...
currentSessionContext = buildCurrentSessionContext();
	}
private CurrentSessionContext buildCurrentSessionContext() {
		String impl = (String) properties.get( Environment.CURRENT_SESSION_CONTEXT_CLASS );
		// for backward-compatibility
		if ( impl == null ) {
			if ( canAccessTransactionManager() ) {
				impl = "jta";
			}
			else {
				return null;
			}
		}

		if ( "jta".equals( impl ) ) {
//			if ( ! transactionFactory().compatibleWithJtaSynchronization() ) {
//				LOG.autoFlushWillNotWork();
//			}
			return new JTASessionContext( this );
		}
		else if ( "thread".equals( impl ) ) {
			return new ThreadLocalSessionContext( this );
		}
		else if ( "managed".equals( impl ) ) {
			return new ManagedSessionContext( this );
		}
		else {
			try {
				Class implClass = serviceRegistry.getService( ClassLoaderService.class ).classForName( impl );
				return (CurrentSessionContext)
						implClass.getConstructor( new Class[] { SessionFactoryImplementor.class } )
						.newInstance( this );
			}
			catch( Throwable t ) {
				LOG.unableToConstructCurrentSessionContext( impl, t );
				return null;
			}
		}
	}


看第一句String impl = (String) properties.get( Environment.CURRENT_SESSION_CONTEXT_CLASS );是不是很熟悉

這裡就是將前面加入的SpringSessionContext。

三、為什麼要用spring的事務管理器

如果不設定spring的事務管理器會報錯Could not obtain transaction-synchronized Session for current thread。看其使用

SessionFactoryImpl.java

public Session getCurrentSession() throws HibernateException {
		if ( currentSessionContext == null ) {
			throw new HibernateException( "No CurrentSessionContext configured!" );
		}
		return currentSessionContext.currentSession();
	}

SpringSessionContext.java

/**
	 * Retrieve the Spring-managed Session for the current thread, if any.
	 */
	@Override
	@SuppressWarnings("deprecation")
	public Session currentSession() throws HibernateException {
		Object value = TransactionSynchronizationManager.getResource(this.sessionFactory);
		if (value instanceof Session) {
			return (Session) value;
		}
		else if (value instanceof SessionHolder) {
			SessionHolder sessionHolder = (SessionHolder) value;
			Session session = sessionHolder.getSession();
			if (!sessionHolder.isSynchronizedWithTransaction() &&
					TransactionSynchronizationManager.isSynchronizationActive()) {
				TransactionSynchronizationManager.registerSynchronization(
						new SpringSessionSynchronization(sessionHolder, this.sessionFactory, false));
				sessionHolder.setSynchronizedWithTransaction(true);
				// Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
				// with FlushMode.MANUAL, which needs to allow flushing within the transaction.
				FlushMode flushMode = SessionFactoryUtils.getFlushMode(session);
				if (flushMode.equals(FlushMode.MANUAL) &&
						!TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
					session.setFlushMode(FlushMode.AUTO);
					sessionHolder.setPreviousFlushMode(flushMode);
				}
			}
			return session;
		}

		if (this.transactionManager != null) {
			try {
				if (this.transactionManager.getStatus() == Status.STATUS_ACTIVE) {
					Session session = this.jtaSessionContext.currentSession();
					if (TransactionSynchronizationManager.isSynchronizationActive()) {
						TransactionSynchronizationManager.registerSynchronization(new SpringFlushSynchronization(session));
					}
					return session;
				}
			}
			catch (SystemException ex) {
				throw new HibernateException("JTA TransactionManager found but status check failed", ex);
			}
		}

		if (TransactionSynchronizationManager.isSynchronizationActive()) {
			Session session = this.sessionFactory.openSession();
			if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
				session.setFlushMode(FlushMode.MANUAL);
			}
			SessionHolder sessionHolder = new SessionHolder(session);
			TransactionSynchronizationManager.registerSynchronization(
					new SpringSessionSynchronization(sessionHolder, this.sessionFactory, true));
			TransactionSynchronizationManager.bindResource(this.sessionFactory, sessionHolder);
			sessionHolder.setSynchronizedWithTransaction(true);
			return session;
		}
		else {
			throw new HibernateException("Could not obtain transaction-synchronized Session for current thread");
		}
	}

這裡value的值為null,因此條件都不滿足,this.transactionManager也為null,因此走最後一個if語句,如果再不滿足則拋異常。

條件如何才能滿足TransactionSynchronizationManager.java

/**
	 * Return if transaction synchronization is active for the current thread.
	 * Can be called before register to avoid unnecessary instance creation.
	 * @see #registerSynchronization
	 */
	public static boolean isSynchronizationActive() {
		return (synchronizations.get() != null);
	}


只需要synchronizations不為空即可,即ThreadLocal中包含TransactionSynchronization例項。

看其中的initSynchronization()

/**
	 * Activate transaction synchronization for the current thread.
	 * Called by a transaction manager on transaction begin.
	 * @throws IllegalStateException if synchronization is already active
	 */
	public static void initSynchronization() throws IllegalStateException {
		if (isSynchronizationActive()) {
			throw new IllegalStateException("Cannot activate transaction synchronization - already active");
		}
		logger.trace("Initializing transaction synchronization");
		synchronizations.set(new LinkedHashSet<TransactionSynchronization>());
	}

看註釋,和事務開啟有關,這個在下一篇會詳細分析。

四、總結

在Spring託管中,使用getCurrentSession()獲得的session並不是程式設計師自己控制的,session的生命週期交由Spring管理。而且要配置Spring事務管理器,並且使用getCurrentSession()的方法要加入事務管理器中。

<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>


比如:
@Override
	public List list(String querySql) {
		Query<?> query = currentSession().createQuery(querySql);
		return query.getResultList();
	}


必須將使用list的方法加入到事務管理中,list*使用了上述方法,加入了就沒問題,get*使用了上述方法沒有加入(註釋掉了,就會拋上述異常),因為事務管理器沒有檢測是否加入事務,從而沒有呼叫initSynchronization()所致。因此使用sessionFactory.getCurrentSession(),需要將使用的方法加入事務管理中。

<!-- 通知 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<!-- 傳播行為 -->
			<tx:method name="save*" propagation="REQUIRED"/>
			<tx:method name="delete*" propagation="REQUIRED"/>
			<tx:method name="insert*" propagation="REQUIRED"/>
			<tx:method name="update*" propagation="REQUIRED"/>
			<tx:method name="list*" propagation="SUPPORTS" read-only="true"/>
			<!--<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>  -->
		</tx:attributes>
	</tx:advice>

當然也可以使用openSession(),自己來管理事務好session的生命週期,這樣會有很多冗餘程式碼,也沒有應用Spring的特性:盡最大可能便捷Java應用開發






相關推薦

Spring實戰----原始碼解析SessionFactorySession管理getCurrentSession的使用

在上一篇Hibernate5整合中當使用sessionFactory.getCurrentSession()時會報錯Could not obtain transaction-synchronized Session for current thread,本篇就從原始碼角度

Hibernate實戰原始碼解析Hibernate引數繫結PreparedStatement防SQL注入原理

    本文采用mysql驅動是5.1.38版本。    本篇文章涉及內容比較多,單就Hibernate來講就很大,再加上資料庫驅動和資料庫相關,非一篇文章或一篇專題就能說得完。本文從使用入手在【Spring實戰】----Spring4.3.2整合Hibernate5.2

Java實戰原始碼解析為什麼覆蓋equals方法時總要覆蓋hashCode方法

1、背景知識本文程式碼基於jdk1.8分析,《Java程式設計思想》中有如下描述:另外再看下Object.java對hashCode()方法的說明:/** * Returns a hash code value for the object. This method

Spring實戰Spring註解配置工作原理原始碼解析

一、背景知識在【Spring實戰】Spring容器初始化完成後執行初始化資料方法一文中說要分析其實現原理,於是就從原始碼中尋找答案,看原始碼容易跑偏,因此應當有個主線,或者帶著問題、目標去看,這樣才能最大限度的提升自身程式碼水平。由於上文中大部分都基於註解進行設定的(Spri

Spring實戰----Spring事務管理配置解析

上篇說了aop的配置,並且說了Spring事務管理是基於aop的,那麼Spring宣告式事務的配置就有兩種方式:XML配置及註解配置不多說,直接看配置檔案一、配置檔案applicationContext-transaction.xml<?xml version="1.0

Spring實戰----Spring配置檔案的解析

一、背景知識Spring的核心的核心就是bean的配置及管理,至Spring最新發布的版本4.3.2已經有三種方式可以配置bean:1)在XML中進行顯示配置2)在Java中進行顯示配置3)隱式的bean發現機制和自動裝配上述三種配置不展開說明,而且目前用的較多的是第3種(當

Spring實戰----spring security4.1.3配置以及踩過的坑

一、所需的庫檔案//spring-security compile 'org.springframework.security:spring-security-web:4.1.3.RELEASE' compile 'org.springframework.security

Spring實戰----springMVC4.3.2的配置

一、簡單說明 本篇springMVC的配置涉及到springMVC配置、sitemesh配置、log4j2的配置 二、相關庫檔案 根據myeclipse中建立gradle web專案建立完成後(建議使用idea進行,本系列也已用idea進行分析),在

Spring Cloud原始碼-Eureka客戶端如何載入Eureka服務註冊中心列表

這部分原始碼涉及到兩個類: 1. com.netflix.discovery.endpoint.EndpointUtils 2.  org.springframework.cloud.netflix.eureka.EurekaClientConfigBean 我

Spring Security二、數據庫管理用戶權限

max xmlns art create http 文件 int nag del 一 引入相關的jar包 這個例子用的是mysql數據庫和c3p0開源的jdbc連接池,在項目的pom.xml中引入jar包 <!-- Mysql -->

MyBatis原始碼分析TypeHandler解析屬性配置元素詳述相關列舉使用高階進階

TypeHandler解析接著看一下typeHandlerElement(root.evalNode("typeHandlers"));方法,這句讀取的是<configuration>下的<typeHandlers>節點,程式碼實現為:private

Android7.1.2原始碼解析系列實戰分析init.rc檔案

實戰分析init.rc檔案 前言:經過上一篇的/system/core/init/readme.txt檔案的翻譯,對於init.rc的語法也有了一定的瞭解,這一篇就對/system/core/rootdir/init.rc檔案進行一個分析,希望能夠藉此對android的開

spring boot配置文件 application.properties 屬性解析

date hiberna mage ida str 數據丟失 art rop 就會 1.JPA命名策略 spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.DefaultNamingStrategy 有兩種值

Spring框架 ? WebApplicationInitializer源碼分析應用

web項目 方法 spring app 應用 加載 大於 filter ext 1、背景   在約定大於配置的大環境下,xml配置文件越來越多的被零配置所取代。還有大部分將原xml中的配置轉為在java類中定義。   而WebApplicationInitializer就可

Spring Boot(29)、SpringBoot整合Mybatis原始碼分析

在【Spring Boot】(23)、Spring Boot整合Mybatis的章節中講述了SpringBoot整合Mybatis的過程,以及一些配置說明,這節主要講解一下整合的原始碼。 廢話不多說,直接進入今天的主題。 閱讀過我之前寫的文章的童靴,肯定知道SpringBoot整合第三方

專案實戰:python:MongoDB資料庫的操作練習

python:MongoDB資料庫的操作及練習 import pymongo class MongodbConn(object): def __init__(self): self.CONN = pymongo.MongoClient("mongodb:/

基礎+實戰JVM原理優化系列之八:如何檢視JVM引數配置?

1. 檢視JAVA版本資訊 2. 檢視JVM執行模式  在$JAVA_HOME/jre/bin下有client和server兩個目錄,分別代表JVM的兩種執行模式。   client執行模式,針對桌面應用,載入速度比server模式快10%,而執行速度為server模

Spring訊息RabbitMq安裝簡單應用(二)

前言: 埋頭苦寫。先把官方文件翻譯過來。整個流程跑一遍。上一篇文章,【Spring訊息】RabbitMq安裝及簡單應用(一),把點對點發送訊息寫完了。之前雖然也可以一個生產者多個消費者,但是一條訊息只能被一個消費者處理,所以是點對點。這篇文章來講講釋出訂閱,一對多。一條訊息

Gson原始碼解析

private FieldNamingStrategy fieldNamingPolicy = FieldNamingPolicy.IDENTITY; public Gson create() { List<TypeAdapterFactory> facto

Spring實戰(第四版)筆記——REST在響應中設定頭部資訊

<Spring實戰(第四版)筆記>——REST在響應中設定頭部資訊 情景描述:客戶端新增資源物件,服務端儲存資源並返回資訊。 @RestController @RequestMapping(