A. java 目前市面上比較火的框架有哪些
Java 始終排在第一位,這使它成為有史以來最著名的軟體編程語言之一。及時的更新和新版本發布使它成為一種充滿活力的、有競爭力的編程語言。
2020年最常用的java框架
十大常用框架:
一、SpringMVC
二、Spring
三、Mybatis
四、Dubbo
五、Maven
六、RabbitMQ
七、Log4j
八、Ehcache
九、Redis
十、Shiro
一、SpringMVC
Spring Web MVC是一種基於Java的實現了Web MVC設計模式的請求驅動類型的輕量級Web框架,即使用了MVC架構模式的思想,將web層進行職責解耦,基於請求驅動指的就是使用請求-響應模型,框架的目的就是幫助我們簡化開發,Spring Web MVC也是要簡化我們日常Web開發的。
模型(Model )封裝了應用程序的數據和一般他們會組成的POJO。
視圖(View)是負責呈現模型數據和一般它生成的HTML輸出,客戶端的瀏覽器能夠解釋。
控制器(Controller )負責處理用戶的請求,並建立適當的模型,並把它傳遞給視圖渲染。
Spring的web模型 - 視圖 - 控制器(MVC)框架是圍繞著處理所有的HTTP請求和響應的DispatcherServlet的設計。
Spring Web MVC處理請求的流程
具體執行步驟如下:
1、 首先用戶發送請求————>前端控制器,前端控制器根據請求信息(如URL)來決定選擇哪一個頁面控制器進行處理並把請求委託給它,即以前的控制器的控制邏輯部分;圖2-1中的1、2步驟;
2、 頁面控制器接收到請求後,進行功能處理,首先需要收集和綁定請求參數到一個對象,這個對象在Spring Web MVC中叫命令對象,並進行驗證,然後將命令對象委託給業務對象進行處理;處理完畢後返回一個ModelAndView(模型數據和邏輯視圖名);圖2-1中的3、4、5步驟;
3、 前端控制器收回控制權,然後根據返回的邏輯視圖名,選擇相應的視圖進行渲染,並把模型數據傳入以便視圖渲染;圖2-1中的步驟6、7;
4、 前端控制器再次收回控制權,將響應返回給用戶,圖2-1中的步驟8;至此整個結束。
二、Spring
2.1、IOC容器:
IOC容器就是具有依賴注入功能的容器,IOC容器負責實例化、定位、配置應用程序中的對象及建立這些對象間的依賴。應用程序無需直接在代碼中new相關的對象,應用程序由IOC容器進行組裝。在Spring中BeanFactory是IOC容器的實際代表者。
2.2、AOP:
簡單地說,就是將那些與業務無關,卻為業務模塊所共同調用的邏輯或責任封裝起來,便於減少系統的重復代碼,降低模塊間的耦合度,並有利於未來的可操作性和可維護性。AOP代表的是一個橫向的關系
AOP用來封裝橫切關注點,具體可以在下面的場景中使用:
Authentication 許可權
Caching 緩存
Context passing 內容傳遞
Error handling 錯誤處理
Lazy loading懶載入
Debugging 調試
logging, tracing, profiling and monitoring記錄跟蹤優化校準
Performance optimization性能優化
Persistence 持久化
Resource pooling資源池
Synchronization同步
Transactions 事務
三、Mybatis
MyBatis 是支持普通 SQL查詢,存儲過程和高級映射的優秀持久層框架。MyBatis 消除了幾乎所有的JDBC代碼和參數的手工設置以及結果集的檢索。MyBatis 使用簡單的 XML或註解用於配置和原始映射,將介面和 Java 的POJOs(Plain Old Java Objects,普通的 Java對象)映射成資料庫中的記錄。
總體流程:
(1)載入配置並初始化
觸發條件:載入配置文件
將SQL的配置信息載入成為一個個MappedStatement對象(包括了傳入參數映射配置、執行的SQL語句、結果映射配置),存儲在內存中。
(2)接收調用請求
觸發條件:調用Mybatis提供的API
傳入參數:為SQL的ID和傳入參數對象
處理過程:將請求傳遞給下層的請求處理層進行處理。
(3)處理操作請求
觸發條件:API介面層傳遞請求過來
傳入參數:為SQL的ID和傳入參數對象
處理過程:
(A)根據SQL的ID查找對應的MappedStatement對象。
(B)根據傳入參數對象解析MappedStatement對象,得到最終要執行的SQL和執行傳入參數。
©獲取資料庫連接,根據得到的最終SQL語句和執行傳入參數到資料庫執行,並得到執行結果。
(D)根據MappedStatement對象中的結果映射配置對得到的執行結果進行轉換處理,並得到最終的處理結果。
(E)釋放連接資源。
(4)返回處理結果將最終的處理結果返回
MyBatis 最強大的特性之一就是它的動態語句功能。如果您以前有使用JDBC或者類似框架的經歷,您就會明白把SQL語句條件連接在一起是多麼的痛苦,要確保不能忘記空格或者不要在columns列後面省略一個逗號等。動態語句能夠完全解決掉這些痛苦。
四、Dubbo
Dubbo是一個分布式服務框架,致力於提供高性能和透明化的RPC(遠程過程調用協議)遠程服務調用方案,以及SOA服務治理方案。簡單的說,bbo就是個服務框架,如果沒有分布式的需求,其實是不需要用的,只有在分布式的時候,才有bbo這樣的分布式服務框架的需求,並且本質上是個服務調用的東東,說白了就是個遠程服務調用的分布式框架。
1、透明化的遠程方法調用,就像調用本地方法一樣調用遠程方法,只需簡單配置,沒有任何API侵入。
2、軟負載均衡及容錯機制,可在內網替代F5等硬體負載均衡器,降低成本,減少單點。
3、 服務自動注冊與發現,不再需要寫死服務提供方地址,注冊中心基於介面名查詢服務提供者的IP地址,並且能夠平滑添加或刪除服務提供者。
節點角色說明:
Provider: 暴露服務的服務提供方。
Consumer: 調用遠程服務的服務消費方。
Registry: 服務注冊與發現的注冊中心。
Monitor: 統計服務的調用次調和調用時間的監控中心。
Container: 服務運行容器。
五、Maven
Maven這個個項目管理和構建自動化工具,越來越多的開發人員使用它來管理項目中的jar包。但是對於我們程序員來說,我們最關心的是它的項目構建功能。
六、RabbitMQ
消息隊列一般是在項目中,將一些無需即時返回且耗時的操作提取出來,進行了非同步處理,而這種非同步處理的方式大大的節省了伺服器的請求響應時間,從而提高了系統的吞吐量。
RabbitMQ是用Erlang實現的一個高並發高可靠AMQP消息隊列伺服器。
Erlang是一門動態類型的函數式編程語言。對應到Erlang里,每個Actor對應著一個Erlang進程,進程之間通過消息傳遞進行通信。相比共享內存,進程間通過消息傳遞來通信帶來的直接好處就是消除了直接的鎖開銷(不考慮Erlang虛擬機底層實現中的鎖應用)。
AMQP(Advanced Message Queue Protocol)定義了一種消息系統規范。這個規范描述了在一個分布式的系統中各個子系統如何通過消息交互。
七、Log4j
日誌記錄的優先順序,分為OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定義的級別。
八、Ehcache
EhCache 是一個純Java的進程內緩存框架,具有快速、精乾等特點,是Hibernate中默認的CacheProvider。Ehcache是一種廣泛使用的開源Java分布式緩存。主要面向通用緩存,Java EE和輕量級容器。它具有內存和磁碟存儲,緩存載入器,緩存擴展,緩存異常處理程序,一個gzip緩存servlet過濾器,支持REST和SOAP api等特點。
優點:
1、 快速
2、 簡單
3、 多種緩存策略
4、緩存數據有兩級:內存和磁碟,因此無需擔心容量問題
5、 緩存數據會在虛擬機重啟的過程中寫入磁碟
6、可以通過RMI、可插入API等方式進行分布式緩存
7、 具有緩存和緩存管理器的偵聽介面
8、支持多緩存管理器實例,以及一個實例的多個緩存區域
9、提供Hibernate的緩存實現
缺點:
1、使用磁碟Cache的時候非常佔用磁碟空間:這是因為DiskCache的演算法簡單,該演算法簡單也導致Cache的效率非常高。它只是對元素直接追加存儲。因此搜索元素的時候非常的快。如果使用DiskCache的,在很頻繁的應用中,很快磁碟會滿。
2、不能保證數據的安全:當突然kill掉java的時候,可能會產生沖突,EhCache的解決方法是如果文件沖突了,則重建cache。這對於Cache數據需要保存的時候可能不利。當然,Cache只是簡單的加速,而不能保證數據的安全。如果想保證數據的存儲安全,可以使用Bekeley DB Java Edition版本。這是個嵌入式資料庫。可以確保存儲安全和空間的利用率。
九、Redis
redis是一個key-value存儲系統。和Memcached類似,它支持存儲的value類型相對更多,包括string(字元串)、list(鏈表)、set(集合)、zset(sorted set –有序集合)和hash(哈希類型)。這些數據類型都支持push/pop、add/remove及取交集並集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,redis支持各種不同方式的排序。與memcached一樣,為了保證效率,數據都是緩存在內存中。區別的是redis會周期性的把更新的數據寫入磁碟或者把修改操作寫入追加的記錄文件,並且在此基礎上實現了master-slave(主從)同步。
Redis資料庫完全在內存中,使用磁碟僅用於持久性。相比許多鍵值數據存儲,Redis擁有一套較為豐富的數據類型。Redis可以將數據復制到任意數量的從伺服器。
1.2、Redis優點:
(1)異常快速:Redis的速度非常快,每秒能執行約11萬集合,每秒約81000+條記錄。
(2)支持豐富的數據類型:Redis支持最大多數開發人員已經知道像列表,集合,有序集合,散列數據類型。這使得它非常容易解決各種各樣的問題,因為我們知道哪些問題是可以處理通過它的數據類型更好。
(3)操作都是原子性:所有Redis操作是原子的,這保證了如果兩個客戶端同時訪問的Redis伺服器將獲得更新後的值。
(4)多功能實用工具:Redis是一個多實用的工具,可以在多個用例如緩存,消息,隊列使用(Redis原生支持發布/訂閱),任何短暫的數據,應用程序,如Web應用程序會話,網頁命中計數等。
1.3、Redis缺點:
(1)單線程
(2)耗內存
十、Shiro
Apache Shiro是Java的一個安全框架,旨在簡化身份驗證和授權。Shiro在JavaSE和JavaEE項目中都可以使用。它主要用來處理身份認證,授權,企業會話管理和加密等。Shiro的具體功能點如下:
(1)身份認證/登錄,驗證用戶是不是擁有相應的身份;
(2)授權,即許可權驗證,驗證某個已認證的用戶是否擁有某個許可權;即判斷用戶是否能做事情,常見的如:驗證某個用戶是否擁有某個角色。或者細粒度的驗證某個用戶對某個資源是否具有某個許可權;
(3)會話管理,即用戶登錄後就是一次會話,在沒有退出之前,它的所有信息都在會話中;會話可以是普通JavaSE環境的,也可以是如Web環境的;
(4)加密,保護數據的安全性,如密碼加密存儲到資料庫,而不是明文存儲;
(5)Web支持,可以非常容易的集成到Web環境;
Caching:緩存,比如用戶登錄後,其用戶信息、擁有的角色/許可權不必每次去查,這樣可以提高效率;
(6)shiro支持多線程應用的並發驗證,即如在一個線程中開啟另一個線程,能把許可權自動傳播過去;
(7)提供測試支持;
(8)允許一個用戶假裝為另一個用戶(如果他們允許)的身份進行訪問;
(9)記住我,這個是非常常見的功能,即一次登錄後,下次再來的話不用登錄了。
文字描述可能並不能讓猿友們完全理解具體功能的意思。下面我們以登錄驗證為例,向猿友們介紹Shiro的使用。至於其他功能點,猿友們用到的時候再去深究其用法也不遲。
十一、設計模式
這個算不上框架,可自行忽略,不過我認為設計模式的思想很有必要了解一下。
思想:
開閉原則:
開閉原則就是說對擴展開放,對修改關閉。在程序需要進行拓展的時候,不能去修改原有的代碼。
針對介面編程,針對介面編程,依賴於抽象而不依賴於具體。
盡量使用合成/聚合的方式,而不是使用繼承。
一個實體應當盡量少的與其他實體之間發生相互作用,使得系統功能模塊相對獨立。
使用多個隔離的介面,比使用單個介面要好。
里氏代換原則:
(1)子類的能力必須大於等於父類,即父類可以使用的方法,子類都可以使用。
(2)返回值也是同樣的道理。假設一個父類方法返回一個List,子類返回一個ArrayList,這當然可以。如果父類方法返回一個ArrayList,子類返回一個List,就說不通了。這里子類返回值的能力是比父類小的。
(3)還有拋出異常的情況。任何子類方法可以聲明拋出父類方法聲明異常的子類。 而不能聲明拋出父類沒有聲明的異常。
B. 如何使用NODEJS+REDIS開發一個消息隊列
MQ全稱為Message
Queue,
消息隊列(MQ)是一種應用程
序對應用程序的通信方法。應用程序通過讀寫出入隊列的消息(針對應用程序的數據)來通信,而無需專用連接來鏈接它們>。消
息傳遞指的是程序之間通過在消息中發送數據進行通信,而不是通過直接調用彼此來通信,直接調用通常是用於諸如遠程過程調用的技術。排隊指的是應用程序通過
隊列來通信。隊列的使用除去了接收和發送應用程序同時執行的要求。其中較為成熟的MQ產品有IBM
WEBSPHERE
MQ。
以上介紹仍舊來自網路.
消息隊列產品對比
目前比較流行的MQ有2種,ActiveMQ
以及
RabbitMQ
,
RabbitMQ性能號稱能夠達到每秒10000,而REDIS官方的壓力測試值在7-8萬之間,而且是去掉了網路IO操作,真實情況我估計在每秒2-3
萬的並發操作,但這個數目對於一般的應用應該足夠了.
Redis如何支持消息隊列?
在新版本的redis
v2.6以上以及以上版本開始支持
subscribe
以及
publish
操作,
subscribe訂閱一個頻道,publish可以像頻道廣播消息.
這個機制最老的應用應該是算是聊天室了.
Sub/Pub
模式固然很好用,但是同樣有一個問題,就是如果有多個人訂閱了同一頻道,而這個頻道的數據只能被一個接收方處理,不能夠重復處理,這時該怎麼辦?
解決方法有2種,
1.
publish
將數據寫入到一個list
or
sorted
list
隊列,寫完成後開始給終端廣播消息,告訴大家,有新的數據等待處理,這個時候,誰能pop到數據,就是誰處理,這個操作是原子性的,也就是說不會被重復處理.
2.
使用阻塞模式,
redis提供了blpop
brpop這種操作,也就是一直阻塞一個隊列,直到有數據來.
這種模式保證了數據的原子性,而且使應用程序可以支持分布式多台機器部署.
Sub/Pub模式
(sub.js):
var
redis
=
require("redis");
var
client
=
redis.createClient(6379,
『127.0.0.1『,
{connect_timeout:
1});
//訂閱一個頻道
var
sub
=
function(c)
{
var
c
=
c
||
『roban:test:channel『;
client.subscribe(c,function(e){
console.log(『starting
subscribe
channel:『+c);
});
};
//訂閱一個頻道
sub();
//處理錯誤,如果出現錯誤,或者伺服器斷開了鏈接,等待恢復時,繼續訂閱這個頻道
client.on(『error『,
function(error)
{
console.log(error);
sub();
});
//訂閱處理函數
client.on(『message『,function(err,response){
console.log(response);
});
打開redis命令行,輸入以下命令:
publish
roban:test:channel
hello
發布這條信息後,sub端會輸出以下信息:
Robans-Pro:node
robanlee$
node
demo.js
starting
subscribe
channel:roban:test:channel
hello
C. redis適合什麼場景
1、緩存。 緩存現在幾乎是所有中大型網站都在用的必殺技,合理的利用緩存不僅能夠提升網站訪問速度,還能大大降低資料庫的壓力。Redis提供了鍵過期功能,也提供了靈活的鍵淘汰策略,所以,現在Redis用在緩存的場合非常多。(推薦:《 Redis視頻教程 》)
2、排行榜。 很多網站都有排行榜應用的,如京東的月度銷量榜單、商品按時間的上新排行榜等。Redis提供的有序集合數據類構能實現各種復雜的排行榜應用。
3、計數器。 什麼是計數器,如電商網站商品的瀏覽量、視頻網站視頻的播放數等。為了保證數據實時效,每次瀏覽都得給+1,並發量高時如果每次都請求資料庫操作無疑是種挑戰和壓力。Redis提供的incr命令來實現計數器功能,內存操作,性能非常好,非常適用於這些計數場景。
4、分布式會話。 集群模式下,在應用不多的情況下一般使用容器自帶的session復制功能就能滿足,當應用增多相對復雜的系統中,一般都會搭建以Redis等內存資料庫為中心的session服務,session不再由容器管理,而是由session服務及內存資料庫管理。
5、分布式鎖。 在很多互聯網公司中都使用了分布式技術,分布式技術帶來的技術挑戰是對同一個資源的並發訪問,如全局ID、減庫存、秒殺等場景,並發量不大的場景可以使用資料庫的悲觀鎖、樂觀鎖來實現,但在並發量高的場合中,利用資料庫鎖來控制資源的並發訪問是不太理想的,大大影響了資料庫的性能。可以利用Redis的setnx功能來編寫分布式的鎖,如果設置返回1說明獲取鎖成功,否則獲取鎖失敗,實際應用中要考慮的細節要更多。
D. spring-data-redis 怎麼監聽消息隊列有消息來了
pom.xml中添加如下配置 添加版本配置 <properties> <jedis.version>2.8.1</jedis.version> <spring-data-redis.version>1.7.2.RELEASE</spring-data-redis.version> <commons-pool2.version>2.2</commons-pool2.version> </properties> <!-- jedis --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>${jedis.version}</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>${commons-pool2.version}</version> </dependency> <!-- --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>${spring-data-redis.version}</version> </dependency> properties文件中添加如下配置 #redis配置 redis.host=192.168.1.150 redis.port=6379 redis.password=redis redis.timeout=2000 redis.max_total=100 redis.max_idle=20 redis.min_idle=5 redis.test_on_borrow=true redis.test_on_return=true applicationContext.xml中添加如下配置: <!-- Jedis 連接池配置--> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxIdle" value="${redis.max_idle}" /> <property name="maxTotal" value="${redis.max_total}"/> <property name="minIdle" value="${redis.min_idle}"/> <property name="testOnBorrow" value="${redis.test_on_borrow}" /> <property name="testOnReturn" value="${redis.test_on_return}"/> </bean> <!-- Jedis ConnectionFactory 資料庫連接配置,注意id名稱必須為redisConnectionFactory--> <bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="hostName" value="${redis.host}" /> <property name="port" value="${redis.port}" /> <property name="password" value="${redis.password}" /> <property name="poolConfig" ref="jedisPoolConfig" /> </bean> 定義消息發送者(生產者): @Component public class SendMessage { @Autowired private RedisTemplate<String, Object> redisTemplate; public void sendMessage(String channel, Serializable message) { redisTemplate.convertAndSend(channel, message); } } 定義消息處理者(消費者): public class ListenMessage { public void handleMessage(Serializable message){ System.out.println(message); } } 調用:/queue/redis @Controller @RequestMapping(value = "/queue") public class QueueController { @Autowired SendMessage sendMessage; @RequestMapping(value="/redis") public void redis(){ for (int i = 0; i <1000; i++) { sendMessage.sendMessage("java",i); } } }
E. spring-data-redis 怎麼監聽消息隊列有消息來了
pom.xml中添加如下配置
添加版本配置
<properties>
<jedis.version>2.8.1</jedis.version>
<spring-data-redis.version>1.7.2.RELEASE</spring-data-redis.version>
<commons-pool2.version>2.2</commons-pool2.version>
</properties>
<!-- jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>${commons-pool2.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-redis -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>${spring-data-redis.version}</version>
</dependency>
properties文件中添加如下配置
#redis配置
redis.host=192.168.1.150
redis.port=6379
redis.password=redis
redis.timeout=2000
redis.max_total=100
redis.max_idle=20
redis.min_idle=5
redis.test_on_borrow=true
redis.test_on_return=true
applicationContext.xml中添加如下配置:
<!-- Jedis 連接池配置-->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.max_idle}" />
<property name="maxTotal" value="${redis.max_total}"/>
<property name="minIdle" value="${redis.min_idle}"/>
<property name="testOnBorrow" value="${redis.test_on_borrow}" />
<property name="testOnReturn" value="${redis.test_on_return}"/>
</bean>
<!-- Jedis ConnectionFactory 資料庫連接配置,注意id名稱必須為redisConnectionFactory-->
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${redis.host}" />
<property name="port" value="${redis.port}" />
<property name="password" value="${redis.password}" />
<property name="poolConfig" ref="jedisPoolConfig" />
</bean>
定義消息發送者(生產者):
@Component
public class SendMessage {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public void sendMessage(String channel, Serializable message) {
redisTemplate.convertAndSend(channel, message);
}
}
定義消息處理者(消費者):
public class ListenMessage {
public void handleMessage(Serializable message){
System.out.println(message);
}
}
調用:/queue/redis
@Controller
@RequestMapping(value = "/queue")
public class QueueController {
@Autowired
SendMessage sendMessage;
@RequestMapping(value="/redis")
public void redis(){
for (int i = 0; i <1000; i++) {
sendMessage.sendMessage("java",i);
}
}
}
F. java面試中redis,mongodb類的,會問哪些問題,怎麼回答
1、可能會問nosql和關系型資料庫的區別:
優點:
1)成本:nosql資料庫簡單易部署,基本都是開源軟體,不需要像使用Oracle那樣花費大量成本購買使用,相比關系型資料庫價格便宜
2)查詢速度:nosql資料庫將數據存儲於緩存之中,關系型資料庫將數據存儲在硬碟中,自然查詢速度遠不及nosql資料庫
3)存儲數據的格式:nosql的存儲格式是key,value形式、文檔形式、圖片形式等等,所以可以存儲基礎類型以及對象或者是集合等各種格式,而資料庫則只支持基礎類型
4)擴展性:關系型資料庫有類似join這樣的多表查詢機制的限制導致擴展很艱難
缺點:
1)維護的工具和資料有限,因為nosql是屬於新的技術,不能和關系型資料庫10幾年的技術同日而語。
2)不提供對sql的支持,如果不支持sql這樣的工業標准,將產生一定用戶的學習和使用成本
3)不提供關系型資料庫對事物的處理
2、介紹下redis和mongodb:
自行google。
3、應用場景:
redis:
a.主要是做熱點數據緩存。
b.數據過期處理。
c.消息隊列等功能。
d.計數,例如投票等。
mongodb:
mongodb的主要目標是在鍵/值存儲方式(提供了高性能和高度伸縮性)以及傳統的RDBMS系統(豐富的功能)架起一座橋梁,集兩者的優勢於一身。mongo適用於以下場景:
a.網站數據:mongo非常適合實時的插入,更新與查詢,並具備網站實時數據存儲所需的復制及高度伸縮性。
b.緩存:由於性能很高,mongo也適合作為信息基礎設施的緩存層。在系統重啟之後,由mongo搭建的持久化緩存可以避免下層的數據源過載。
c.大尺寸、低價值的數據:使用傳統的關系資料庫存儲一些數據時可能會比較貴,在此之前,很多程序員往往會選擇傳統的文件進行存儲。
d.高伸縮性的場景:mongo非常適合由數十或者數百台伺服器組成的資料庫。
e.用於對象及JSON數據的存儲:mongo的BSON數據格式非常適合文檔格式化的存儲及查詢。
4、支持的數據類型:
內容比較多,自行將網上的信息整理一下。
G. redis消息隊列還有其他嗎
基於Redis消息隊列-實現簡訊服務化
1.Redis實現消息隊列原理
常用的消息隊列有RabbitMQ,ActiveMQ,個人覺得這種消息隊列太大太重,本文介紹下基於Redis的輕量級消息隊列服務。
一般來說,消息隊列有兩種模式,一種是發布者訂閱模式,另外一種是生產者和消費者模式。Redis的消息隊列,也是基於這2種原理的實現。
發布者和訂閱者模式:發布者發送消息到隊列,每個訂閱者都能收到一樣的消息。
生產者和消費者模式:生產者將消息放入隊列,多個消費者共同監聽,誰先搶到資源,誰就從隊列中取走消息去處理。注意,每個消息只能最多被一個消費者接收。
2.Redis消息隊列使用場景
在我們的項目中,使用消息隊列來實現簡訊的服務化,任何需要發送簡訊的模塊,都可以直接調用簡訊服務來完成簡訊的發送。比如用戶系統登錄注冊簡訊,訂單系統的下單成功的簡訊等。
3.SpringMVC中實現Redis消息隊列
因為我們簡訊只需要發送一次,所以我們使用的是消息隊列的生產者和消費者模式。
3.1引入Maven依賴
引入Redis相應的maven依賴,這里需要spring-data-redis和jedis
//pom.xml <dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.6.0.RELEASE</version>
</dependency>
<!-- jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.5.1</version>
</dependency>12345678910111213
3.2配置redis生成者消費者模式
//applicationContext-redis.xml <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:redis="http://www.springframework.org/schema/redis"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-34.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.0.xsd
http://www.springframework.org/schema/redis http://www.springframework.org/schema/redis/spring-redis-1.0.xsd">
<description>spring-data-redis配置</description>
<bean id="redisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${redis.host}"></property>
<property name="port" value="${redis.port}"></property>
<property name="usePool" value="true"></property>
</bean>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="redisConnectionFactory"></property>
</bean>
<bean id="jdkSerializer"
class="org.springframework.data.redis.serializer." />
<bean id="smsMessageListener"
class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
<property name="delegate" ref="smsMessageDelegateListener" />
<property name="serializer" ref="jdkSerializer" />
</bean>
<bean id="sendMessage" class="com.djt.common.cache.redis.queue.SendMessage">
<property name="redisTemplate" ref="redisTemplate"/>
</bean>
<redis:listener-container>
<redis:listener ref="smsMessageListener" method="handleMessage"
serializer="jdkSerializer" topic="sms_queue_web_online" />
</redis:listener-container>
<!-- jedis -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="300" /> <!-- 最大能夠保持idel狀態的對象數 -->
<property name="maxTotal" value="60000" /> <!-- 最大分配的對象數 -->
<property name="testOnBorrow" value="true" /> <!-- 當調用borrow Object方法時,是否進行有效性檢查 -->
</bean>
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg index="0" ref="jedisPoolConfig" />
<constructor-arg index="1" value="${redis.host}" />
<constructor-arg index="2" value="${redis.port}" type="int" />
</bean></beans>
主要的配置說明:
1.序列化:一般我們向Redis發送一個消息定義的Java對象,這個對象需要序列化。這里使用:
<bean id="jdkSerializer" class="org.springframework.data.redis.serializer." />1
2.發送者:
<bean id="sendMessage" class="com.djt.common.cache.redis.queue.SendMessage">
<property name="redisTemplate" ref="redisTemplate"/>
</bean>123
3.監聽者:
<bean id="smsMessageListener"
class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
<property name="delegate" ref="smsMessageDelegateListener" />
<property name="serializer" ref="jdkSerializer" />
</bean>
<redis:listener-container>
<redis:listener ref="smsMessageListener" method="handleMessage"
serializer="jdkSerializer" topic="sms_queue_web_online" />
</redis:listener-container>123456789
smsMessageListener:消息監聽器
redis:listener-container:定義消息監聽,method:監聽消息執行的方法,serializer:序列化,topic:監聽主題(可以理解為隊列名稱)
3.3代碼實現
1.定義簡訊消息對象SmsMessageVo
public class SmsMessageVo implements Serializable {
//id
private Integer smsId; //手機號
private String mobile; //類型,1:驗證碼 2:訂單通知
private Byte type; //簡訊創建時間
private Date createDate; //簡訊消息處理時間
private Date processTime; //簡訊狀態,1:未發送 2:發送成功 3:發送失敗
private Byte status; //簡訊內容
private String content; //省略setter和getter方法
...
2.定義消息隊列發送對象SendMessage
//SendMessage.javapublic class SendMessage { private RedisTemplate<String, Object> redisTemplate; public RedisTemplate<String, Object> getRedisTemplate() { return redisTemplate;
} public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) { this.redisTemplate = redisTemplate;
} public void sendMessage(String channel, Serializable message) {
redisTemplate.convertAndSend(channel, message);
}
}
3.發送消息
String smsContent = templateToContent(template.getContent(),
regMsgCode);
SmsMessageVo smsMessageVo = new SmsMessageVo();
smsMessageVo.setMobile(mobile);
smsMessageVo.setType((byte) SmsType.VERIFICATION.getType());
smsMessageVo.setChannelId(1);
smsMessageVo.setContent(smsContent);
smsMessageVo.setCreateDate(new Date());
smsMessageVo.setStatus((byte) SmsSendStatus.TO_SEND.getType());
smsMessageVo.setTemplateId(1);
//先把待發送的簡訊存入資料庫
SmsQueue smsQueue = new SmsQueue();
BeanUtils.Properties(smsQueue, smsMessageVo);
smsQueueService.addSmsQueue(smsQueue);
//非同步發送簡訊到redis隊列
sendMessage.sendMessage(Constants.REDIS_QUEUE_SMS_WEB, smsMessageVo);
//Constants.REDIS_QUEUE_SMS_WEB = "sms_queue_web_online",和applicationContext-redis中topic配置一樣
4.監聽消息
//SmsMessageDelegateListener.java@Component("smsMessageDelegateListener")public class SmsMessageDelegateListener {
@Autowired
private SmsQueueService smsQueueService; //監聽Redis消息
public void handleMessage(Serializable message){ if(message instanceof SmsMessageVo){
SmsMessageVo messageVo = (SmsMessageVo) message; //發送簡訊
SmsSender smsSender = SmsSenderFactory.buildEMaySender();
smsSender.setMobile(messageVo.getMobile());
smsSender.setContent(messageVo.getContent()); boolean sendSucc = false; //判斷簡訊類型
//驗證碼簡訊
if(messageVo.getType() == (byte)SmsType.VERIFICATION.getType()){
sendSucc = smsSender.send();
} if(!sendSucc){ return;
} // 非同步更新簡訊表狀態為發送成功
final Integer smsId = messageVo.getSmsId();
Executor executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() { public void run() {
SmsQueue smsQueue = new SmsQueue();
smsQueue.setSmsId(smsId);
smsQueue.setStatus((byte)SmsSendStatus.SEND.getType());
smsQueue.setProcessTime(new Date());
smsQueueService.updateSmsQueue(smsQueue);
}
});
}
}
}04142434445
4.總結
下面使用一張流程圖,來總結Redis消息隊列和簡訊服務。
閱讀全文
H. JAVA開發需要哪些技術
作為一個Java開發人員,最大的挑戰就是不斷更新了解新的技術。在時代的變化中,主流技術的掌握也是一門持久的功課。
1、微服務技術
微服務架構主要有:Spring Cloud、 Dubbo、 Dubbox等,以 Dubbo佔比最高,可達26%,微服務網關技術,使用springcloud-zuul的程序員佔比最高。
2、遠程調用技術
使用RPC框架的程序員中, 使用Dubbo的人數佔比最高,其次為 bbox、gRPC、hessian也具有一定的使用比例。
3、開發技術
多數程序員在工作中使用的開發技術為許可權管理和消息隊列。1/4的程序員在工作中使用的開發技術為報表技術、分布式緩存技術和負載均衡解決方案。
4、許可權管理技術
shiro的使用比例最高,其次為spring security和自定義框架。
5、消息隊列技術
消息隊列技術主要有:ActiveMQ、RabbitMQ和Kafka。RocketMQ的使用人數較少。
I. redis為什麼總是把訂閱/發布和消息隊列聯系在一起
首先redis的發布訂閱模式不會緩存數據,就是我發布了,如果你已經可以接受了,那麼你就能接收到,如果你還沒有準備好那麼就會錯誤准備好之前的數據。至於為啥為啥和消息隊列聯系在一起,是因為redis的發布訂閱模式的實現就是通過消息隊列實現的。比如多個發布端都可以發布消息,而訂閱端都會接收到消息。可見中間必然有一個隊列取集中發布的消息。然後把消息按序發出去
J. 消息隊列為什麼用redis實現
redis只是提供一個高性能的、原子操作的分布式隊列實現。具體的業務還是得需要你自己定製。
你的需求實際上是一個變形的生產者-消費者實現。對於此類需求,主要是將請求和實際的處理過程解耦,一般都是採取非同步的方式來通知請求方,這跟用不用redis其實沒有多大的關系。一般的實現方法是你需要將用戶的請求封裝成一個Task,然後將這個Task再push到redis隊列,然後後端的worker.php完全可以多進程、多線程的並發處理Task並將處理結果回調給請求方。這里唯一麻煩點的就是這個Task的設計,需要能夠包含請求信息(請求內容,請求方標識等等).