更新時(shí)間:2018年12月07日13時(shí)58分 來(lái)源:傳智播客 瀏覽次數(shù):
SpringSecurity方法級(jí)別的權(quán)限控制
引言
Spring Security是一個(gè)能夠?yàn)榛赟pring的企業(yè)應(yīng)用系統(tǒng)提供安全訪問(wèn)控制解決方案的安全框架,它利用Spring IOC、DI和AOP功能,為企業(yè)應(yīng)用系統(tǒng)提供聲明式的安全訪問(wèn)控制功能,簡(jiǎn)化企業(yè)系統(tǒng)為了安全控制而編寫大量重復(fù)代碼的工作,Spring Security支持Url級(jí)別的權(quán)限控制,同樣也支持方法級(jí)別的權(quán)限控制,今天主要介紹Spring Security方法級(jí)別的權(quán)限控制。
Spring Security方法級(jí)別權(quán)限控制方式
Spring Security方法級(jí)別權(quán)限控制主要有以下幾種方式:
• intercept-methods定義方法權(quán)限控制。
• 使用pointcut定義方法權(quán)限控制。
• 使用JSR-250注解定義方法權(quán)限控制。
• 使用@Secured注解定義方法權(quán)限控制。
• 注解使用表達(dá)式定義方法權(quán)限控制。
項(xiàng)目搭建
要想實(shí)現(xiàn)Spring Security方法級(jí)別的權(quán)限控制,必須先將項(xiàng)目搭建起來(lái)。
創(chuàng)建名稱為Spring-Security的web項(xiàng)目
在pom.xml文件中引入相關(guān)的依賴包。
/** * 單例設(shè)計(jì)模式之 懶漢式 * @author nianqiang */ public class SingletonClass { // 私有化及volatile修飾成員類 private static volatile SingletonClass instance = null; // 向外提供靜態(tài)創(chuàng)建對(duì)象實(shí)例 public static SingletonClass getInstance() { // 只有調(diào)用當(dāng)前靜態(tài)方法,才返回當(dāng)前類的實(shí)例 if (instance == null) { instance = new SingletonClass(); } return instance; } // 私有化構(gòu)造 private SingletonClass() { } } |
public static void main(String[] args) { for (int i = 0; i < 10; i++) { SingletonClass singletonClass = SingletonClass.getInstance(); System.out.println(singletonClass); } } |
/** * java 設(shè)計(jì)模式之 餓漢式實(shí)現(xiàn) * @author nianqiang */ public class Singleton { // 私有化構(gòu)造 private Singleton() {} // 設(shè)置成員屬性時(shí)就創(chuàng)建當(dāng)前的實(shí)例 private static final Singleton instance = new Singleton(); // 向外提供靜態(tài)方法訪問(wèn)返回該類的實(shí)例 public static Singleton getInstance() { return instance; } } |
public static void main(String[] args) { for (int i = 0; i < 10; i++) { Singleton singleton = Singleton.getInstance(); System.out.println(singleton); } } |
/** * Java設(shè)計(jì)模式之雙重檢查鎖單例 * @author nianqiang */ public class Singleton { private static volatile Singleton instance = null; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton1.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } } |
public static void main(String[] args) { for (int i = 0; i < 10; i++) { Singleton singleton = Singleton.getInstance(); System.out.println(singleton); } } |
上述的設(shè)計(jì)是當(dāng)前用的比較多的一種,也是設(shè)計(jì)的比較巧妙的方式。我們接下來(lái)就仔細(xì)的分析一下上面的單例模式。
• 懶漢式的加強(qiáng)版:保證第一次使用的時(shí)候創(chuàng)建該類的實(shí)體對(duì)象。
• 線程安全:在多線程環(huán)境中如何高效的使用線程鎖機(jī)制來(lái)解決線程安全的問(wèn)題,這里的設(shè)計(jì)是使用同步代碼塊最大限度的提高效率。
• 提高性能:在多線程環(huán)境下,如果只有一次檢查if (instance == null) 的話,相當(dāng)于為了解決 1% 幾率的同步問(wèn)題,而使用了一個(gè) 100% 出現(xiàn)的防護(hù)盾。雙重檢查就是把 100% 出現(xiàn)的防護(hù)盾,也改為 1% 的幾率出現(xiàn)。只有 instance 為 null 的時(shí)候,才進(jìn)入 synchronized 的代碼段——大大減少了幾率。
• private static volatile Singleton instance = null;
關(guān)鍵詞 volatile 的作用:
– 內(nèi)存可見(jiàn)性:可見(jiàn)性的意思是當(dāng)一個(gè)線程修改一個(gè)共享變量時(shí),另外一個(gè)線程能讀到這個(gè)修改的值。就是相當(dāng)于共享同一塊內(nèi)存區(qū)域。
– 禁止指令重排:雙重檢查鎖單例中利用的就是這一點(diǎn)。 那什么是指令重排呢?指令重排是指計(jì)算機(jī)為了提高執(zhí)行效率,會(huì)做一些優(yōu)化,在不影響最終結(jié)果的情況下,可能會(huì)對(duì)一些語(yǔ)句的執(zhí)行順序進(jìn)行調(diào)整。
3.4. 靜態(tài)內(nèi)部類單例
/** * 單例設(shè)計(jì)模式之靜態(tài)內(nèi)部類實(shí)現(xiàn) * * @author nianqiang */ public class Singleton { // 提供私有構(gòu)造,目的防止外部new對(duì)象 private Singleton() { } // 私有靜態(tài)內(nèi)部類提供當(dāng)前對(duì)象的的實(shí)例 private static class InnerClass { private static final Singleton INSTANCE = new Singleton(); } // 外部提供當(dāng)前類的對(duì)象的實(shí)例 public static Singleton getInstance() { return InnerClass.INSTANCE; } } |
public static void main(String[] args) { for (int i = 0; i < 10; i++) { Singleton singleton = Singleton.getInstance(); System.out.println(singleton); } } |
上述內(nèi)部類實(shí)現(xiàn)的單例中,由于 InnerClass 是一個(gè)內(nèi)部類,只在外部類的 Singleton 的 getInstance() 中被使用,所以它被加載的時(shí)機(jī)只會(huì)在 getInstance() 方法第一次被調(diào)用的時(shí)候。并且 InnerClass 初始化的時(shí)候會(huì)由 ClassLoader 來(lái)保證同步。 這種設(shè)計(jì)單例是一個(gè)巧妙的利用的內(nèi)部類的加載機(jī)制來(lái)實(shí)現(xiàn)的,但是為什么只能是靜態(tài)的內(nèi)部類呢?如果內(nèi)部類不是靜態(tài)的結(jié)果如何呢? 答案是必須要把內(nèi)部類設(shè)置成靜態(tài)的,如果內(nèi)部類設(shè)置的不是靜態(tài)的,那么編譯器會(huì)報(bào)一個(gè)異常信息如下:
那么我們來(lái)解釋一下出現(xiàn)上述問(wèn)題的原因,如果使用一個(gè)類的靜態(tài)成員,需要先把這個(gè)類加載到虛擬機(jī)中,而成員內(nèi)部類是需要由外部類對(duì)象 new 一個(gè)實(shí)例才可以使用,這就無(wú)法做到靜態(tài)成員的要求。所以 Java 不允許非靜態(tài)內(nèi)部類持有靜態(tài)的聲明。此時(shí)必須將當(dāng)前的內(nèi)部類加上static修飾。
4. 總結(jié)
以上我們就學(xué)習(xí)了關(guān)于設(shè)計(jì)模式中的單例模式在實(shí)際開發(fā)中常用的實(shí)現(xiàn)方式,以及各個(gè)實(shí)現(xiàn)方式的優(yōu)缺點(diǎn),那么在開發(fā)中根據(jù)實(shí)際的業(yè)務(wù)需求選擇不同的單例模式即可。一般情況下單例模式在多線程環(huán)境下使用的時(shí)候需要特別注意的是線程安全相關(guān)的問(wèn)題。
北京校區(qū)