當前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
Spring AOP 本质(3)
生活随笔
收集整理的這篇文章主要介紹了
Spring AOP 本质(3)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Spring AOP 本質(3) Spring AOP很牛,AOP是OOP的補充,而非競爭者。 前面的例子離實際的應用太遙遠。不足以顯式AOP的力量,現在就用AOP前置通知來檢查用戶的身份,只有通過檢查的才能調用業務方法。 在沒有使用AOP之前,我們是如何實現的?想想看。 1、寫一個安全檢查類,又其他類繼承,并在子類的業務方法中調用安全檢查的方法。 比如:Struts1時代就是繼承Action,其類結構如下: package org.apache.struts.action;
public class Action {
????public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm, ServletRequest servletRequest, ServletResponse servletResponse) throws java.lang.Exception { /* compiled code */ }
????public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm, http.HttpServletRequest httpServletRequest, http.HttpServletResponse httpServletResponse) throws java.lang.Exception { /* compiled code */ }
????....
}
在開發中自己實現的UserAction需要繼承Struts的Action,可以考慮做一個抽象,比如叫做CheckAciton,在其中重寫execute方法,并加入安全檢查機制,并且增加一個抽象請求處理方法
public ActionForward real(ActionMapping actionMapping, ActionForm actionForm, http.HttpServletRequest httpServletRequest, http.HttpServletResponse httpServletResponse)throws java.lang.Exception;
作為業務請求處理的方法,放到重寫的execute方法內部調用。 public class CheckAction extends Action{
????public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm, http.HttpServletRequest httpServletRequest, http.HttpServletResponse httpServletResponse) throws java.lang.Exception {
????//todo: 安全檢查邏輯
????return real(actionMapping,actionForm,httpServletRequest,httpServletResponse);
????}
????public abstract ActionForward real(ActionMapping actionMapping, ActionForm actionForm, http.HttpServletRequest httpServletRequest, http.HttpServletResponse httpServletResponse) throws java.lang.Exception;
} 這樣以后業務上的別的Aciton只要繼承了CheckAction,還需要實現real方法,別的方法),即可為該Action加入安全檢查的邏輯。 public class DoSomethingAction extends CheckAction{
????public abstract ActionForward real(ActionMapping actionMapping, ActionForm actionForm, http.HttpServletRequest httpServletRequest, http.HttpServletResponse httpServletResponse) throws java.lang.Exception{
????//todo: 單純處理實際的業務請求
????return ...
????}
????....
} 這樣做也很麻煩,還可以使用動態代理為每個業務接口加上安全檢查的邏輯,但是性能更差,更麻煩。 這個還算可行的方案,實現也很容易。但是很死板,如果有多種驗證策略就比較棘手了。 沒有對比就顯式不出來Spring AOP的優勢。下面看看Spring的優雅處理: /**
* 用戶登錄信息載體
*/
public class UserInfo {
????private String userName;
????private String password;
????public UserInfo(String userName, String password) {
????????this.userName = userName;
????????this.password = password;
????}
????
????public String getPassword() {
????????return password;
????}
????public String getUserName() {
????????return userName;
????}
} /**
* 業務組件:被代理的對象
*/
public class SecureBean {
????/**
???? * 示范性的業務方法,這個方法將被攔截,加入一些附加邏輯
???? */
????public void businessOperate() {
????????System.out.println("業務方法businessOperate()被調用了!");
????}
} /**
* 安全管理類:檢查用戶登錄和管理用戶注銷登錄的業務邏輯。
*/
public class SecurityManager {
????//為每一個SecurityManager創建一個本地線程變量threadLocal,用來保存用戶登錄信息UserInfo
????private static ThreadLocal threadLocal = new ThreadLocal();
????/**
???? * 用戶登錄方法,允許任何用戶登錄。
???? * @param userName
???? * @param password
???? */
????public void login(String userName, String password) {
????????// 假定任何的用戶名和密碼都可以登錄
????????// 將用戶登錄信息封裝為UerInfo對象,保存在ThreadLocal類的對象threadLocal里面
????????threadLocal.set(new UserInfo(userName, password));
????}
????public void logout() {
????????// 設置threadLocal對象為null
????????threadLocal.set(null);
????????int x = 0;
????}
????public UserInfo getLoggedOnUser() {
????????// 從本地線程變量中獲取用戶信息UerInfo對象
????????return (UserInfo) threadLocal.get();
????}
} import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
/**
* 前置通知類
*/
public class SecurityAdvice implements MethodBeforeAdvice {
????private SecurityManager securityManager;
????public SecurityAdvice() {
????????this.securityManager = new SecurityManager();
????}
????/**
???? * 前置通知的接口方法實現。僅允許robh用戶登錄,強制設定的。
???? */
????public void before(Method method, Object[] args, Object target)
????????????throws Throwable {
????????UserInfo user = securityManager.getLoggedOnUser();
????????if (user == null) {
????????????System.out.println("沒有用戶憑證信息!,本前置通知僅僅允許robh用戶登錄,不信你試試看!");
????????????throw new SecurityException(
????????????????????"你必須在調用此方法" + method.getName() + "前進行登錄:");
????????} else if ("robh".equals(user.getUserName())) {
????????????System.out.println("用戶robh成功登錄:OK!");
????????} else {
????????????System.out.println("非法用戶"+user.getUserName()+",請使用robh登錄,用戶調用的方法是:" + method.getName());
????????????throw new SecurityException("用戶" + user.getUserName()
????????????????????+ " 不允許調用" + method.getName() + "方法!");
????????}
????}
}
? import org.springframework.aop.framework.ProxyFactory;
/**
* 測試類,客戶端
*/
public class SecurityExample {
????public static void main(String[] args) {
????????//得到一個 security manager
????????SecurityManager mgr = new SecurityManager();
????????//獲取一個SecureBean的代理對象
????????SecureBean bean = getSecureBean();
????????//嘗試用robh登錄
????????mgr.login("robh", "pwd");?? //檢查登錄情況
????????bean.businessOperate();???? //業務方法調用
????????mgr.logout();?????????????? //注銷登錄
????????//嘗試用janm登錄
????????try {
????????????mgr.login("janm", "pwd");?????? //檢查登錄情況
????????????bean.businessOperate();???????? //業務方法調用
????????} catch (SecurityException ex) {
????????????System.out.println("發生了異常: " + ex.getMessage());
????????} finally {
????????????mgr.logout();?????????????????? //注銷登錄
????????}
????????// 嘗試不使用任何用戶名身份調用業務方法
????????try {
????????????bean.businessOperate();???????? //業務方法調用
????????} catch (SecurityException ex) {
????????????System.out.println("發生了異常: " + ex.getMessage());
????????}
????}
????/**
???? * 獲取SecureBean的代理對象
???? *
???? * @return SecureBean的代理
???? */
????private static SecureBean getSecureBean() {
????????//創建一個目標對象
????????SecureBean target = new SecureBean();
????????//創建一個通知
????????SecurityAdvice advice = new SecurityAdvice();
????????//獲取代理對象
????????ProxyFactory factory = new ProxyFactory();
????????factory.setTarget(target);
????????factory.addAdvice(advice);
????????SecureBean proxy = (SecureBean) factory.getProxy();
????????return proxy;
????}
} 運行結果: - Using JDK 1.4 collections
用戶robh成功登錄:OK!
業務方法businessOperate()被調用了!
非法用戶janm,請使用robh登錄,用戶調用的方法是:businessOperate
發生了異常: 用戶janm 不允許調用businessOperate方法!
沒有用戶憑證信息!,本前置通知僅僅允許robh用戶登錄,不信你試試看!
發生了異常: 你必須在調用此方法businessOperate前進行登錄:
Process finished with exit code 0 觀察運行結果,精確實現了驗證的要求。 這里從底層觀察Spring AOP的應用,實際應用中最好還是通過xml配置耦合代碼。只有明白了AOP其中奧秘,使用Spring的配置才能深諳其中的精妙!
public class Action {
????public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm, ServletRequest servletRequest, ServletResponse servletResponse) throws java.lang.Exception { /* compiled code */ }
????public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm, http.HttpServletRequest httpServletRequest, http.HttpServletResponse httpServletResponse) throws java.lang.Exception { /* compiled code */ }
????....
}
在開發中自己實現的UserAction需要繼承Struts的Action,可以考慮做一個抽象,比如叫做CheckAciton,在其中重寫execute方法,并加入安全檢查機制,并且增加一個抽象請求處理方法
public ActionForward real(ActionMapping actionMapping, ActionForm actionForm, http.HttpServletRequest httpServletRequest, http.HttpServletResponse httpServletResponse)throws java.lang.Exception;
作為業務請求處理的方法,放到重寫的execute方法內部調用。 public class CheckAction extends Action{
????public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm, http.HttpServletRequest httpServletRequest, http.HttpServletResponse httpServletResponse) throws java.lang.Exception {
????//todo: 安全檢查邏輯
????return real(actionMapping,actionForm,httpServletRequest,httpServletResponse);
????}
????public abstract ActionForward real(ActionMapping actionMapping, ActionForm actionForm, http.HttpServletRequest httpServletRequest, http.HttpServletResponse httpServletResponse) throws java.lang.Exception;
} 這樣以后業務上的別的Aciton只要繼承了CheckAction,還需要實現real方法,別的方法),即可為該Action加入安全檢查的邏輯。 public class DoSomethingAction extends CheckAction{
????public abstract ActionForward real(ActionMapping actionMapping, ActionForm actionForm, http.HttpServletRequest httpServletRequest, http.HttpServletResponse httpServletResponse) throws java.lang.Exception{
????//todo: 單純處理實際的業務請求
????return ...
????}
????....
} 這樣做也很麻煩,還可以使用動態代理為每個業務接口加上安全檢查的邏輯,但是性能更差,更麻煩。 這個還算可行的方案,實現也很容易。但是很死板,如果有多種驗證策略就比較棘手了。 沒有對比就顯式不出來Spring AOP的優勢。下面看看Spring的優雅處理: /**
* 用戶登錄信息載體
*/
public class UserInfo {
????private String userName;
????private String password;
????public UserInfo(String userName, String password) {
????????this.userName = userName;
????????this.password = password;
????}
????
????public String getPassword() {
????????return password;
????}
????public String getUserName() {
????????return userName;
????}
} /**
* 業務組件:被代理的對象
*/
public class SecureBean {
????/**
???? * 示范性的業務方法,這個方法將被攔截,加入一些附加邏輯
???? */
????public void businessOperate() {
????????System.out.println("業務方法businessOperate()被調用了!");
????}
} /**
* 安全管理類:檢查用戶登錄和管理用戶注銷登錄的業務邏輯。
*/
public class SecurityManager {
????//為每一個SecurityManager創建一個本地線程變量threadLocal,用來保存用戶登錄信息UserInfo
????private static ThreadLocal threadLocal = new ThreadLocal();
????/**
???? * 用戶登錄方法,允許任何用戶登錄。
???? * @param userName
???? * @param password
???? */
????public void login(String userName, String password) {
????????// 假定任何的用戶名和密碼都可以登錄
????????// 將用戶登錄信息封裝為UerInfo對象,保存在ThreadLocal類的對象threadLocal里面
????????threadLocal.set(new UserInfo(userName, password));
????}
????public void logout() {
????????// 設置threadLocal對象為null
????????threadLocal.set(null);
????????int x = 0;
????}
????public UserInfo getLoggedOnUser() {
????????// 從本地線程變量中獲取用戶信息UerInfo對象
????????return (UserInfo) threadLocal.get();
????}
} import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
/**
* 前置通知類
*/
public class SecurityAdvice implements MethodBeforeAdvice {
????private SecurityManager securityManager;
????public SecurityAdvice() {
????????this.securityManager = new SecurityManager();
????}
????/**
???? * 前置通知的接口方法實現。僅允許robh用戶登錄,強制設定的。
???? */
????public void before(Method method, Object[] args, Object target)
????????????throws Throwable {
????????UserInfo user = securityManager.getLoggedOnUser();
????????if (user == null) {
????????????System.out.println("沒有用戶憑證信息!,本前置通知僅僅允許robh用戶登錄,不信你試試看!");
????????????throw new SecurityException(
????????????????????"你必須在調用此方法" + method.getName() + "前進行登錄:");
????????} else if ("robh".equals(user.getUserName())) {
????????????System.out.println("用戶robh成功登錄:OK!");
????????} else {
????????????System.out.println("非法用戶"+user.getUserName()+",請使用robh登錄,用戶調用的方法是:" + method.getName());
????????????throw new SecurityException("用戶" + user.getUserName()
????????????????????+ " 不允許調用" + method.getName() + "方法!");
????????}
????}
}
? import org.springframework.aop.framework.ProxyFactory;
/**
* 測試類,客戶端
*/
public class SecurityExample {
????public static void main(String[] args) {
????????//得到一個 security manager
????????SecurityManager mgr = new SecurityManager();
????????//獲取一個SecureBean的代理對象
????????SecureBean bean = getSecureBean();
????????//嘗試用robh登錄
????????mgr.login("robh", "pwd");?? //檢查登錄情況
????????bean.businessOperate();???? //業務方法調用
????????mgr.logout();?????????????? //注銷登錄
????????//嘗試用janm登錄
????????try {
????????????mgr.login("janm", "pwd");?????? //檢查登錄情況
????????????bean.businessOperate();???????? //業務方法調用
????????} catch (SecurityException ex) {
????????????System.out.println("發生了異常: " + ex.getMessage());
????????} finally {
????????????mgr.logout();?????????????????? //注銷登錄
????????}
????????// 嘗試不使用任何用戶名身份調用業務方法
????????try {
????????????bean.businessOperate();???????? //業務方法調用
????????} catch (SecurityException ex) {
????????????System.out.println("發生了異常: " + ex.getMessage());
????????}
????}
????/**
???? * 獲取SecureBean的代理對象
???? *
???? * @return SecureBean的代理
???? */
????private static SecureBean getSecureBean() {
????????//創建一個目標對象
????????SecureBean target = new SecureBean();
????????//創建一個通知
????????SecurityAdvice advice = new SecurityAdvice();
????????//獲取代理對象
????????ProxyFactory factory = new ProxyFactory();
????????factory.setTarget(target);
????????factory.addAdvice(advice);
????????SecureBean proxy = (SecureBean) factory.getProxy();
????????return proxy;
????}
} 運行結果: - Using JDK 1.4 collections
用戶robh成功登錄:OK!
業務方法businessOperate()被調用了!
非法用戶janm,請使用robh登錄,用戶調用的方法是:businessOperate
發生了異常: 用戶janm 不允許調用businessOperate方法!
沒有用戶憑證信息!,本前置通知僅僅允許robh用戶登錄,不信你試試看!
發生了異常: 你必須在調用此方法businessOperate前進行登錄:
Process finished with exit code 0 觀察運行結果,精確實現了驗證的要求。 這里從底層觀察Spring AOP的應用,實際應用中最好還是通過xml配置耦合代碼。只有明白了AOP其中奧秘,使用Spring的配置才能深諳其中的精妙!
總結
以上是生活随笔為你收集整理的Spring AOP 本质(3)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 促进儿童语言发展的方法
- 下一篇: Cisco网络设备搭建×××服务器的全部