- 論壇徽章:
- 0
|
Spring的影響實(shí)在太大了,連Python也在向其靠攏了。
一直以為Spring只是跟Java非常親密,原來Spring早就潛入Python了。今天本來只是想Spring如何應(yīng)用在Python中,于是就Google了下,發(fā)現(xiàn)原來Python早已經(jīng)有個(gè)叫SpringPython東東了。于是到其官網(wǎng)下載了springpython-reference.pdf,粗略的翻翻學(xué)習(xí)了下。感覺其實(shí)跟Spring Java非常的相似,只是類名等不同而已。其IoC、AOP、數(shù)據(jù)訪問、事務(wù)等都差不多了。
于是我邊看文檔,邊整理了一下。因?yàn)楝F(xiàn)在我還沒有Python項(xiàng)目,用不上它,所以現(xiàn)在只是做個(gè)筆記,知道個(gè)大概,為以后應(yīng)用它時(shí)能夠快速定位做個(gè)準(zhǔn)備。
AOP那一章節(jié)沒有寫,因?yàn)橐皇歉鶶pring非常的像,二是項(xiàng)目中一般都很少用它。
一、IoC容器
1、ObjectContainer和ApplicationContainer比較
ApplicationContainer繼承ObjectContainer對(duì)象,和Spring Java一樣,它同樣是增強(qiáng)了功能,提供了Bean的pre-和post-創(chuàng)建邏輯。
任何實(shí)現(xiàn)了ApplicationContextAware的對(duì)象將會(huì)有額外的app_context屬性,它代表了ApplicationContext對(duì)象的一個(gè)引用。
from springpython.context import ApplicationContext
from springpython.config import XMLConfig
container = ApplicationContext(XMLConfig("app-context.xml" )
service = container.get_object("MovieLister"
繼承ObjectPostProcessor對(duì)象并且定義了post_process_after_initialization方法的任何對(duì)象,在它實(shí)例創(chuàng)建之后 ,ApplicationContext都會(huì)執(zhí)行該方法。
繼承springpython.context.DisposableObject對(duì)象并且定義了destroy或是destroy_method方法的對(duì)象,在ApplicationContext銷毀時(shí),都會(huì)執(zhí)行該方法。我們可以把銷毀實(shí)例、釋放內(nèi)存等工作放在該方法之中。
需要注意的是,當(dāng)同時(shí)定義了destroy和destroy_method兩個(gè)方法時(shí),ApplicationContext會(huì)優(yōu)先執(zhí)行destroy方法;繼承自DisposableObject的對(duì)象必須提供destroy或是destroy_method方法,否則會(huì)報(bào)錯(cuò),錯(cuò)誤日志會(huì)被記錄在SpringPython日志文件中。
2、對(duì)象生命周期
SpringPython提供了對(duì)象的兩種生命周期:SINGLETON和PROTOTYPE。
默認(rèn)情況下為SINGLETON,當(dāng)類實(shí)例化時(shí),容器會(huì)注入對(duì)象所有屬性。
使用方法和Spring Java一樣:scope=“prototype”。
3、SpringPython的配置
目前常見的配置有兩種:XMLConfig和YamlConfig。受到Spring JavaConfig的啟發(fā),通過擴(kuò)展PythonConfig并且使用@Object裝飾,我們可以用純Python代碼來配置Bean。同樣的,我們可以通過擴(kuò)展Config來定義自己的格式。
XMLConfig跟Spring Java 2.5 XSD非常相似,下面是一個(gè)簡(jiǎn)單的例子。
<?xml version="1.0" encoding="UTF-8"?>
<objects xmlns="http://www.springframework.org/springpython/schema/objects/1.1"
xmlns si="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/springpython/schema/objects/1.1
http://springpython.webfactional ... hon-context-1.1.xsd">
<object id="MovieLister" class="springpythontest.support.testSupportClasses.MovieLister" scope="prototype">
<property name="finder" ref="MovieFinder"/>
<property name="description"><ref object="SingletonString"/></property>
</object>
<object id="MovieFinder" class="springpythontest.support.testSupportClasses.ColonMovieFinder" scope="singleton">
<property name="filename"><value>support/movies1.txt</value></property>
</object>
<object id="SingletonString" class="springpythontest.support.testSupportClasses.StringHolder" lazy-init="<property name="str" value="There should only be one copy of this string"></property>
</object>
</objects>
內(nèi)部對(duì)象:
<object id="MovieLister3" class="springpythontest.support.testSupportClasses.MovieLister">
<property name="finder">
<object id="named" class="springpythontest.support.testSupportClasses.ColonMovieFinder">
<property name="filename"><value>support/movies1.txt</value></property>
</object>
</property>
<property name="description"><ref object="SingletonString"/></property>
</object>
SpringPython支持多種集合屬性:字典(dict)、列表(list)、屬性(props)、集合(set、frozenset)、元組(tuple);
<object id="ValueHolder" class="springpythontest.support.testSupportClasses.ValueHolder">
<constructor-arg><ref object="SingletonString"/></constructor-arg>
<property name="some_dict">
<dict>
<entry><key><value>Hello</value></key><value>World</value></entry>
<entry><key><value>Spring</value></key><value> ython</value></entry>
<entry><key><value>holder</value></key><ref object="SingletonString"/></entry>
<entry><key><value>another copy</value></key><ref object="SingletonString"/></entry>
</dict>
</property>
<property name="some_list">
<list>
<value>Hello, world!</value>
<ref object="SingletonString"/>
<value>Spring Python</value>
</list>
</property>
<property name="some_props">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
<property name="some_set">
<set>
<value>Hello, world!</value>
<ref object="SingletonString"/>
<value>Spring Python</value>
</set>
</property>
<property name="some_frozen_set">
<frozenset>
<value>Hello, world!</value>
<ref object="SingletonString"/>
<value>Spring Python</value>
</frozenset>
</property>
<property name="some_tuple">
<tuple>
<value>Hello, world!</value>
<ref object="SingletonString"/>
<value>Spring Python</value>
</tuple>
</property>
</object>
注意set和frozenset的關(guān)系和區(qū)別(http://docs.python.org/release/2.5.2/lib/types-set.html):
構(gòu)造函數(shù)配置方法:
<object id="AnotherSingletonString" class="springpythontest.support.testSupportClasses.StringHolder">
<constructor-arg value="attributed value"/>
</object>
<object id="MultiValueHolder" class="springpythontest.support.testSupportClasses.MultiValueHolder">
<constructor-arg name="a"><value>alt a</value></constructor-arg>
<constructor-arg name="b"><value>alt b</value></constructor-arg>
</object>
Python的基本類型(str, unicode, int, long, float, decimal.Decimal, bool和complex)在XML配置文件中有著不同的簡(jiǎn)短的表示方法:
<str id="MyString">My string</str>
<unicode id="MyUnicode">Za#ó## g##l# ja##</unicode>
<int id="MyInt">10</int>
<long id="MyLong">100000000000000000000000</long>
<float id="MyFloat">3.14</float>
<decimal id="MyDecimal">12.34</decimal>
<bool id="MyBool">False</bool>
<complex id="MyComplex">10+0j</complex>
同樣的,XMLConfig也可以定義抽象(abstract="True")和使用繼承(parent):
<object id="crm_service" parent="service" abstract="True">
<property name="port"><value>3393</value></property>
</object>
<object id="get_customer_id" parent="crm_service">
<property name="path"><value>/soap/invoke/get_customer_id</value></property>
</object>
當(dāng)在程序中需要引用一個(gè)抽象類型的對(duì)象時(shí),必須加上屬性(ignore_abstract=True),否則會(huì)引發(fā)AbstractObjectException異常:
service = ctx.get_object("service", ignore_abstract=True)
4、對(duì)象工廠
SpringPython提供了兩種類型的工廠:ReflectiveObjectFactory和PythonObjectFactory。它們很少被我們用到,主要是用在不的同配置掃描器中。
5、在運(yùn)行時(shí)查詢或是修改ApplicationContent
ApplicationContext實(shí)例暴露了兩個(gè)屬性和一個(gè)方法使用我們?cè)谶\(yùn)行時(shí)能夠知道其當(dāng)前狀態(tài)并且動(dòng)態(tài)改變它:object_defs、objects、get_objects_by_type(type, include_type=True);
二、AOP編程
三、數(shù)據(jù)訪問
1、數(shù)據(jù)庫模板:
在沒有使用數(shù)據(jù)庫模板情況下,我們傳統(tǒng)的寫法如下:
conn = MySQL.connection(username="me", password"secret", hostname="localhost", db="springpython"
cursor = conn.cursor()
results = []
try:
cursor.execute("select title, air_date, episode_number, writer from tv_shows where name = %s", ("Monty Python",))
for row in cursor.fetchall():
tvShow = TvShow(title=row[0], airDate=row[1], episodeNumber=row[2], writer=row[3])
results.append(tvShow)
finally:
try:
cursor.close()
except Exception:
pass
conn.close()
return results
在傳統(tǒng)的數(shù)據(jù)庫訪問中,所有的數(shù)據(jù)庫操作都是建立連接、執(zhí)行查詢、獲取數(shù)據(jù)、釋放連接,最后是返回結(jié)果。
下面是在使用了數(shù)據(jù)庫模板情況下的做法:
""" The following part only has to be done once."""
from springpython.database.core import *
from springpython.database.factory import *
connectionFactory = MySQLConnectionFactory(username="me", password="secret", hostname="localhost", db="springpython"
dt = DatabaseTemplate(connectionFactory)
class TvShowMapper(RowMapper):
"""This will handle one row of database. It can be reused for many queries if they
are returning the same columns."""
def map_row(self, row, metadata=None):
return TvShow(title=row[0], airDate=row[1], episodeNumber=row[2], writer=row[3])
results = dt.query("select title, air_date, episode_number, writer from tv_shows where name = %s", \
("Monty Python",), TvShowMapper())
results = dt.query("select title, air_date, episode_number, writer from tv_shows where episode_number < %s", \
(100,), TvShowMapper())
results = dt.query("select title, air_date, episode_number, writer from tv_shows where upper(title) like %s", \
("%CHEESE%",), TvShowMapper())
results = dt.query("select title, air_date, episode_number, writer from tv_shows where writer in ('Cleese', 'Graham')",
rowhandler=TvShowMapper())
從上面可以看出,在使用了模板后,程序所要做的,就是提供一個(gè)RowMapper,從而使它返回最終結(jié)果。
一種便利的RowMapper:SimpleRowMapper(TvShow)。它自動(dòng)把數(shù)據(jù)表列和對(duì)象屬性關(guān)聯(lián)起來。
2、把數(shù)據(jù)行映射成字典
results = dt.query("select title, air_date, episode_number, writer from tv_shows where episode_number < %s", \
(100,), DictionaryRowMapper())
四、事務(wù)管理
1、事務(wù)模板TransactionTemplate
class Bank:
def __init__(self):
self.factory = factory.MySQLConnectionFactory("springpython", "springpython", "localhost", "springpython"
self.dt = DatabaseTemplate(self.factory)
self.txManager = ConnectionFactoryTransactionManager(self.factory)
self.txTemplate = TransactionTemplate(self.txManager)
try:
self.txTemplate.execute(txDefinition())
print "If you made it to here, then your transaction has already been committed."
except InvalidBankAccount, InsufficientFunds:
print "If you made it to here, then your transaction has already been rolled back."
2、使用裝飾@transactional
@transactional
def transfer(self, transfer_amount, source_account_num, target_account_num):
self.withdraw(transfer_amount, source_account_num)
self.deposit(transfer_amount, target_account_num)
3、事務(wù)傳播屬性
當(dāng)使用@transactional裝飾時(shí),同時(shí)也可以指定事務(wù)傳播屬性,比如:@transactional([" ROPAGATION_REQUIRED"])。
事務(wù)一共有4種傳播屬性:
PROPAGATION_SUPPORTS:程序能夠在有事務(wù)或是沒有事務(wù)的環(huán)境中運(yùn)行,也就是有沒有無所謂;
PROPAGATION_REQUIRED:如果當(dāng)前沒事務(wù),則開始一個(gè)事務(wù);
PROPAGATION_MANDATORY:程序邏輯只能在事務(wù)中運(yùn)行,如果沒有,則產(chǎn)生異常;
PROPAGATION_NEVER:與上面的相反,程序只能在無事務(wù)的環(huán)境中運(yùn)行,如果有事務(wù),則產(chǎn)生異常。 |
|