快速理解聚合根、實(shí)體、值對(duì)象的區(qū)別和聯(lián)系

posted @ 2017-02-19 08:32 paulwong 閱讀(1293) | 評(píng)論 (0) | 編輯 收藏
posted @ 2017-02-19 08:32 paulwong 閱讀(1293) | 評(píng)論 (0) | 編輯 收藏
posted @ 2017-02-18 22:00 paulwong 閱讀(1866) | 評(píng)論 (0) | 編輯 收藏
posted @ 2017-02-18 21:53 paulwong 閱讀(479) | 評(píng)論 (0) | 編輯 收藏
posted @ 2016-10-15 19:57 paulwong 閱讀(1623) | 評(píng)論 (0) | 編輯 收藏
Spring Cloud Security OAuth2 是 Spring 對(duì) OAuth2 的開(kāi)源實(shí)現(xiàn),優(yōu)點(diǎn)是能與Spring Cloud技術(shù)線無(wú)縫集成,如果全部使用默認(rèn)配置,開(kāi)發(fā)者只需要添加注解就能完成 OAuth2 授權(quán)服務(wù)的搭建。
授權(quán)服務(wù)是基于Spring Security的,因此需要在項(xiàng)目中引入兩個(gè)依賴:
前者為 Security,后者為Security的OAuth2擴(kuò)展。
在啟動(dòng)類中添加@EnableAuthorizationServer
注解:
完成這些我們的授權(quán)服務(wù)最基本的骨架就已經(jīng)搭建完成了。但是要想跑通整個(gè)流程,我們必須分配 client_id
, client_secret
才行。Spring Security OAuth2的配置方法是編寫@Configuration
類繼承AuthorizationServerConfigurerAdapter
,然后重寫void configure(ClientDetailsServiceConfigurer clients)
方法,如:
訪問(wèn)授權(quán)頁(yè)面:
此時(shí)瀏覽器會(huì)讓你輸入用戶名密碼,這是因?yàn)?Spring Security 在默認(rèn)情況下會(huì)對(duì)所有URL添加Basic Auth認(rèn)證。默認(rèn)的用戶名為user
, 密碼是隨機(jī)生成的,在控制臺(tái)日志中可以看到。
畫風(fēng)雖然很簡(jiǎn)陋,但是基本功能都具備了。點(diǎn)擊Authorize
后,瀏覽器就會(huì)重定向到百度,并帶上code
參數(shù):
拿到code
以后,就可以調(diào)用
來(lái)?yè)Q取access_token
了:
返回如下:
到此我們最最基本的授權(quán)服務(wù)就搭建完成了。然而,這僅僅是個(gè)demo,如果要在生產(chǎn)環(huán)境中使用,還需要做更多的工作。
把授權(quán)服務(wù)器中的數(shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫(kù)中并不難,因?yàn)?Spring Cloud Security OAuth 已經(jīng)為我們?cè)O(shè)計(jì)好了一套Schema和對(duì)應(yīng)的DAO對(duì)象。但在使用之前,我們需要先對(duì)相關(guān)的類有一定的了解。
Spring Cloud Security OAuth2通過(guò)DefaultTokenServices
類來(lái)完成token生成、過(guò)期等 OAuth2 標(biāo)準(zhǔn)規(guī)定的業(yè)務(wù)邏輯,而DefaultTokenServices
又是通過(guò)TokenStore
接口完成對(duì)生成數(shù)據(jù)的持久化。在上面的demo中,TokenStore
的默認(rèn)實(shí)現(xiàn)為InMemoryTokenStore
,即內(nèi)存存儲(chǔ)。 對(duì)于Client信息,ClientDetailsService
接口負(fù)責(zé)從存儲(chǔ)倉(cāng)庫(kù)中讀取數(shù)據(jù),在上面的demo中默認(rèn)使用的也是InMemoryClientDetialsService
實(shí)現(xiàn)類。說(shuō)到這里就能看出,要想使用數(shù)據(jù)庫(kù)存儲(chǔ),只需要提供這些接口的實(shí)現(xiàn)類即可。慶幸的是,框架已經(jīng)為我們寫好JDBC實(shí)現(xiàn)了,即JdbcTokenStore
和JdbcClientDetailsService
。
要想使用這些JDBC實(shí)現(xiàn),首先要建表。框架為我們提前設(shè)計(jì)好了schema, 在github上:https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql
在使用這套表結(jié)構(gòu)之前要注意的是,對(duì)于MySQL來(lái)說(shuō),默認(rèn)建表語(yǔ)句中主鍵是varchar(255)類型,在mysql中執(zhí)行會(huì)報(bào)錯(cuò),原因是mysql對(duì)varchar主鍵長(zhǎng)度有限制。所以這里改成128即可。其次,語(yǔ)句中會(huì)有某些字段為LONGVARBINARY
類型,它對(duì)應(yīng)mysql的blob
類型,也需要修改一下。
數(shù)據(jù)庫(kù)建好后,下一步就是配置框架使用JDBC實(shí)現(xiàn)。方法還是編寫@Configuration
類繼承AuthorizationServerConfigurerAdapter
:
完成這些后,框架就會(huì)將中間產(chǎn)生的數(shù)據(jù)寫到mysql中了。oauth_client_details
是client表,可以直接在該表中添加記錄來(lái)添加client:
這里不得不說(shuō) Spring 設(shè)計(jì)有一個(gè)奇葩地的方。注意看oauth_access_token
表是存放訪問(wèn)令牌的,但是并沒(méi)有直接在字段中存放token。Spring 使用OAuth2AccessToken
來(lái)抽象與令牌有關(guān)的所有屬性,在寫入到數(shù)據(jù)庫(kù)時(shí),Spring將該對(duì)象通過(guò)JDK自帶的序列化機(jī)制序列成字節(jié)直接保存到了該表的token
字段中。也就是說(shuō),如果只看數(shù)據(jù)表你是看不出access_token
的值是多少,過(guò)期時(shí)間等信息的。這就給資源服務(wù)器的實(shí)現(xiàn)帶來(lái)了麻煩。我們的資源提供方并沒(méi)有使用Spring Security,也不想引入 Spring Security 的任何依賴,這時(shí)候就只能將 DefaultOAuth2AccessToken
的源碼copy到資源提供方的項(xiàng)目中,然后讀取token
字段并反序列化還原對(duì)象來(lái)獲取token信息。但是如果這樣做還會(huì)遇到反序列化兼容性的問(wèn)題,具體解決方法參考我另一篇博文:http://blog.csdn.net/neosmith/article/details/52539614
至此一個(gè)能在生產(chǎn)環(huán)境下使用的授權(quán)服務(wù)就搭建好了。其實(shí)我們?cè)趯?shí)際使用時(shí)應(yīng)該適當(dāng)定制JdbcTokenStore
或ClientDetailsService
來(lái)實(shí)適應(yīng)業(yè)務(wù)需要,甚至可以直接從0開(kāi)始實(shí)現(xiàn)接口,完全不用框架提供的實(shí)現(xiàn)。另外,Spring 直接將DefaultOAuth2AccessToken
序列化成字節(jié)保存到數(shù)據(jù)庫(kù)中的設(shè)計(jì),我認(rèn)為是非常不合理的。或許設(shè)計(jì)者的初衷是保密access_token
,但是通過(guò)加密的方法也可以實(shí)現(xiàn),完全不應(yīng)該直接扔字節(jié)。不過(guò)通過(guò)定制TokenStore
接口,我們可以使用自己的表結(jié)構(gòu)而不拘泥于默認(rèn)實(shí)現(xiàn)。
http://blog.csdn.net/tracker_w/article/category/6360121
http://blog.csdn.net/neosmith/article/details/52539927
posted @ 2016-09-16 18:22 paulwong 閱讀(8753) | 評(píng)論 (0) | 編輯 收藏
在Spring Cloud Netflix棧中,各個(gè)微服務(wù)都是以HTTP接口的形式暴露自身服務(wù)的,因此在調(diào)用遠(yuǎn)程服務(wù)時(shí)就必須使用HTTP客戶端。我們可以使用JDK原生的URLConnection
、Apache的Http Client
、Netty的異步HTTP Client, Spring的RestTemplate
。但是,用起來(lái)最方便、最優(yōu)雅的還是要屬Feign了。
Feign是一種聲明式、模板化的HTTP客戶端。在Spring Cloud中使用Feign, 我們可以做到使用HTTP請(qǐng)求遠(yuǎn)程服務(wù)時(shí)能與調(diào)用本地方法一樣的編碼體驗(yàn),開(kāi)發(fā)者完全感知不到這是遠(yuǎn)程方法,更感知不到這是個(gè)HTTP請(qǐng)求。比如:
開(kāi)發(fā)者通過(guò)service.findByGroupId()
就能完成發(fā)送HTTP請(qǐng)求和解碼HTTP返回結(jié)果并封裝成對(duì)象的過(guò)程。
為了讓Feign知道在調(diào)用方法時(shí)應(yīng)該向哪個(gè)地址發(fā)請(qǐng)求以及請(qǐng)求需要帶哪些參數(shù),我們需要定義一個(gè)接口:
A: @FeignClient
用于通知Feign組件對(duì)該接口進(jìn)行代理(不需要編寫接口實(shí)現(xiàn)),使用者可直接通過(guò)@Autowired
注入。
B: @RequestMapping
表示在調(diào)用該方法時(shí)需要向/group/{groupId}
發(fā)送GET
請(qǐng)求。
C: @PathVariable
與SpringMVC
中對(duì)應(yīng)注解含義相同。
Spring Cloud應(yīng)用在啟動(dòng)時(shí),F(xiàn)eign會(huì)掃描標(biāo)有@FeignClient
注解的接口,生成代理,并注冊(cè)到Spring容器中。生成代理時(shí)Feign會(huì)為每個(gè)接口方法創(chuàng)建一個(gè)RequetTemplate
對(duì)象,該對(duì)象封裝了HTTP請(qǐng)求需要的全部信息,請(qǐng)求參數(shù)名、請(qǐng)求方法等信息都是在這個(gè)過(guò)程中確定的,F(xiàn)eign的模板化就體現(xiàn)在這里。
在本例中,我們將Feign與Eureka和Ribbon組合使用,@FeignClient(name = "ea")
意為通知Feign在調(diào)用該接口方法時(shí)要向Eureka中查詢名為ea
的服務(wù),從而得到服務(wù)URL。
Feign將方法簽名中方法參數(shù)對(duì)象序列化為請(qǐng)求參數(shù)放到HTTP請(qǐng)求中的過(guò)程,是由編碼器(Encoder)完成的。同理,將HTTP響應(yīng)數(shù)據(jù)反序列化為java對(duì)象是由解碼器(Decoder)完成的。
默認(rèn)情況下,F(xiàn)eign會(huì)將標(biāo)有@RequestParam
注解的參數(shù)轉(zhuǎn)換成字符串添加到URL中,將沒(méi)有注解的參數(shù)通過(guò)Jackson轉(zhuǎn)換成json放到請(qǐng)求體中。注意,如果在@RequetMapping
中的method
將請(qǐng)求方式指定為POST
,那么所有未標(biāo)注解的參數(shù)將會(huì)被忽略,例如:
此時(shí)因?yàn)槁暶鞯氖荊ET請(qǐng)求沒(méi)有請(qǐng)求體,所以obj
參數(shù)就會(huì)被忽略。
在Spring Cloud環(huán)境下,F(xiàn)eign的Encoder*只會(huì)用來(lái)編碼沒(méi)有添加注解的參數(shù)*。如果你自定義了Encoder, 那么只有在編碼obj
參數(shù)時(shí)才會(huì)調(diào)用你的Encoder。對(duì)于Decoder, 默認(rèn)會(huì)委托給SpringMVC中的MappingJackson2HttpMessageConverter
類進(jìn)行解碼。只有當(dāng)狀態(tài)碼不在200 ~ 300之間時(shí)ErrorDecoder才會(huì)被調(diào)用。ErrorDecoder的作用是可以根據(jù)HTTP響應(yīng)信息返回一個(gè)異常,該異常可以在調(diào)用Feign接口的地方被捕獲到。我們目前就通過(guò)ErrorDecoder來(lái)使Feign接口拋出業(yè)務(wù)異常以供調(diào)用者處理。
Feign在默認(rèn)情況下使用的是JDK原生的URLConnection
發(fā)送HTTP請(qǐng)求,沒(méi)有連接池,但是對(duì)每個(gè)地址會(huì)保持一個(gè)長(zhǎng)連接,即利用HTTP的persistence connection
。我們可以用Apache的HTTP Client替換Feign原始的http client, 從而獲取連接池、超時(shí)時(shí)間等與性能息息相關(guān)的控制能力。Spring Cloud從Brixtion.SR5
版本開(kāi)始支持這種替換,首先在項(xiàng)目中聲明Apache HTTP Client和feign-httpclient
依賴:
然后在application.properties
中添加:
通過(guò)Feign, 我們能把HTTP遠(yuǎn)程調(diào)用對(duì)開(kāi)發(fā)者完全透明,得到與調(diào)用本地方法一致的編碼體驗(yàn)。這一點(diǎn)與阿里Dubbo中暴露遠(yuǎn)程服務(wù)的方式類似,區(qū)別在于Dubbo是基于私有二進(jìn)制協(xié)議,而Feign本質(zhì)上還是個(gè)HTTP客戶端。如果是在用Spring Cloud Netflix搭建微服務(wù),那么Feign無(wú)疑是最佳選擇。
http://blog.csdn.net/tracker_w/article/category/6360121
http://blog.csdn.net/neosmith/article/details/52449921
posted @ 2016-09-16 18:13 paulwong 閱讀(2655) | 評(píng)論 (0) | 編輯 收藏
posted @ 2016-09-11 20:49 paulwong 閱讀(953) | 評(píng)論 (0) | 編輯 收藏
posted @ 2016-09-11 16:40 paulwong 閱讀(604) | 評(píng)論 (0) | 編輯 收藏
Spring 框架給企業(yè)軟件開(kāi)發(fā)者提供了常見(jiàn)問(wèn)題的通用解決方案,包括那些在未來(lái)開(kāi)發(fā)中沒(méi)有意識(shí)到的問(wèn)題。但是,它構(gòu)建的 J2EE 項(xiàng)目變得越來(lái)越臃腫,逐漸被 Spring Boot 所替代。Spring Boot 讓我們創(chuàng)建和運(yùn)行項(xiàng)目變得更為迅速,現(xiàn)在已經(jīng)有越來(lái)越多的人使用它。我們已經(jīng)在幾個(gè)項(xiàng)目中使用了 Spring Boot ,今天我們就來(lái)一起討論一下如何改進(jìn) Spring Boot 應(yīng)用的性能。
首先,從之前我在開(kāi)發(fā)中遇到的一個(gè)問(wèn)題說(shuō)起。在一次查看項(xiàng)目運(yùn)行日志的時(shí)候,我偶然發(fā)現(xiàn)了一個(gè)問(wèn)題,日志里顯示這個(gè)項(xiàng)目總是加載 Velocity 模板引擎,但實(shí)際上這個(gè)項(xiàng)目是一個(gè)沒(méi)有 web 頁(yè)面的 REST Service 項(xiàng)目。于是我花了一點(diǎn)時(shí)間去尋找產(chǎn)生這個(gè)問(wèn)題的原因,以及如何改進(jìn) Spring Boot 應(yīng)用的性能。在查找了相關(guān)的資料后,我得出的結(jié)論如下:
默認(rèn)情況下,我們會(huì)使用 @SpringBootApplication 注解來(lái)自動(dòng)獲取的應(yīng)用的配置信息,但這樣也會(huì)給應(yīng)用帶來(lái)一些副作用。使用這個(gè)注解后,會(huì)觸發(fā)自動(dòng)配置( auto-configuration )和 組件掃描 ( component scanning),這跟使用 @Configuration、@EnableAutoConfiguration 和 @ComponentScan 三個(gè)注解的作用是一樣的。這樣做給開(kāi)發(fā)帶來(lái)方便的同時(shí),也會(huì)有兩方面的影響:
1、會(huì)導(dǎo)致項(xiàng)目啟動(dòng)時(shí)間變長(zhǎng)。當(dāng)啟動(dòng)一個(gè)大的應(yīng)用程序,或?qū)⒆龃罅康募蓽y(cè)試啟動(dòng)應(yīng)用程序時(shí),影響會(huì)特別明顯。
2、會(huì)加載一些不需要的多余的實(shí)例(beans)。
3、會(huì)增加 CPU 消耗。
針對(duì)以上兩個(gè)情況,我們可以移除 @SpringBootApplication 和 @ComponentScan 兩個(gè)注解來(lái)禁用組件自動(dòng)掃描,然后在我們需要的 bean 上進(jìn)行顯式配置:
我們?cè)谏厦嫣岬剑?#64;SpringBootApplication 注解的作用跟 @EnableAutoConfiguration 注解的作用是相當(dāng)?shù)模蔷鸵馕吨材軒?lái)上述的三個(gè)問(wèn)題。要避免這些問(wèn)題,我們就要知道我們需要的組件列表是哪些,可以用 -Ddebug 的方式來(lái)幫助我們明確地定位:
mvn spring-boot:run -Ddebug … ========================= AUTO-CONFIGURATION REPORT ========================= Positive matches: ----------------- DispatcherServletAutoConfiguration - @ConditionalOnClass classes found: org.springframework.web.servlet.DispatcherServlet (OnClassCondition) - found web application StandardServletEnvironment (OnWebApplicationCondition) ...
接著拷貝 Positive matches
中列出的信息:
DispatcherServletAutoConfiguration
EmbeddedServletContainerAutoConfiguration
ErrorMvcAutoConfiguration
HttpEncodingAutoConfiguration
HttpMessageConvertersAutoConfiguration
JacksonAutoConfiguration
JmxAutoConfiguration
MultipartAutoConfiguration
ServerPropertiesAutoConfiguration
PropertyPlaceholderAutoConfiguration
ThymeleafAutoConfiguration
WebMvcAutoConfiguration
WebSocketAutoConfiguration
然后來(lái)更新項(xiàng)目配置,顯式地引入這些組件,引入之后,再運(yùn)行一下應(yīng)用確保沒(méi)有錯(cuò)誤發(fā)生:
在上面的代碼中,我們可以刪掉我們不需要的組件信息,來(lái)提高應(yīng)用的性能,比如在我的項(xiàng)目中,不需要 JMX 和 WebSocket 功能,我就刪掉了它們。刪掉之后,再次運(yùn)行項(xiàng)目,確保一切正常。
默認(rèn)情況下,Spring Boot 使用 Tomcat 來(lái)作為內(nèi)嵌的 Servlet 容器。我們可以啟動(dòng)項(xiàng)目,然后用 VisualVM 或者 JConsole 來(lái)查看應(yīng)用所占的內(nèi)存情況:
以上是我使用 Spring Boot 的默認(rèn)方式啟動(dòng)應(yīng)用后,用 VisualVM 監(jiān)控到的內(nèi)存的占用情況:堆內(nèi)存占用 110M,16 個(gè)線程被開(kāi)啟。
可以將 Web 服務(wù)器切換到 Undertow 來(lái)提高應(yīng)用性能。Undertow 是一個(gè)采用 Java 開(kāi)發(fā)的靈活的高性能 Web 服務(wù)器,提供包括阻塞和基于 NIO 的非堵塞機(jī)制。Undertow 是紅帽公司的開(kāi)源產(chǎn)品,是 Wildfly 默認(rèn)的 Web 服務(wù)器。首先,從依賴信息里移除 Tomcat 配置:
然后添加 Undertow:
啟動(dòng)項(xiàng)目后,用 VisualVM 監(jiān)控到的信息顯示:堆內(nèi)存占用 90M,13個(gè)線程被開(kāi)啟。
這些都是我們?cè)陧?xiàng)目開(kāi)發(fā)中使用到的一些優(yōu)化 Spring Boot 應(yīng)用的小技巧,對(duì)于大的應(yīng)用性能的提高還是很明顯的。大家可以嘗試一下,然后告訴我們你的測(cè)試結(jié)果。
最后,附上代碼,大家可以去這里下載:spring-boot-performance。
文中大部分內(nèi)容參考英國(guó)一個(gè)架構(gòu)師的博客 和 DZone 近期發(fā)布的文章,在此感謝兩位大牛。參考文章及鏈接:
(1)Spring Boot 性能優(yōu)化:Spring Boot Performance;
(2)Spring Boot 內(nèi)存優(yōu)化:Spring Boot Memory Performance。
(3)https://www.techempower.com/benchmarks/;
(4)Spring 應(yīng)用程序優(yōu)化:Optimizing Spring Framework for App Engine Applications。
posted @ 2016-09-11 16:37 paulwong 閱讀(839) | 評(píng)論 (0) | 編輯 收藏
posted @ 2016-09-11 16:26 paulwong 閱讀(2005) | 評(píng)論 (0) | 編輯 收藏