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