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的配置才能深谙其中的精妙!

Spring AOP 本质(3)相关推荐

  1. Spring AOP本质(7)

    Spring AOP本质(7) 上一个里面,给出静态方法切点匹配的例子,现在给出一个动态的实现例子: 没有 /** * 业务组件 */ public class SampleBean {     pu ...

  2. Spring AOP 本质

    AOP本质是拦截,拦截的本质是代理,代理分动态和静态,静态代理很简单,功能有限,应用不是很广泛,Spring中主要用的动态代理.   用Spring做开发,AOP的实现仅仅是编程实现一些接口,然后配置 ...

  3. 《Spring揭秘》读书笔记 2:Spring AOP

    7 一起来看AOP 2009年8月,<一起来看流星雨>开播. 2009年9月,<Spring揭秘>出版. 7.1 AOP核心概念 AOP AOP全称为Aspect-Orient ...

  4. Spring Aop 常见注解和执行顺序

    欢迎关注方志朋的博客,回复"666"获面试宝典 来源:juejin.cn/post/7062506923194581029 Spring 一开始最强大的就是 IOC / AOP 两 ...

  5. 彻底理解Spring AOP

    目录 前言 1. AOP概念 2. AOP的实现 3. Spring的IoC理解: 4. Sping知识整理 前言 AOP英文名为Aspect Oriented Programming,意为面向切面编 ...

  6. (转)Spring AOP的底层实现技术

    AOP概述 软件的编程语言最终的目的就是用更自然更灵活的方式模拟世界,从原始机器语言到过程语言再到面向对象的语言,我们看到编程语言在一步步用更自然.更强大的方式描述软件.AOP是软件开发思想的一个飞跃 ...

  7. Spring AOP中定义切点(PointCut)和通知(Advice)

    本文讨论一下Spring AOP编程中的两个关键问题,定义切点和定义通知,理解这两个问题能应付大部分AOP场景. 如果你还不熟悉AOP,请先看AOP基本原理,本文的例子也沿用了AOP基本原理中的例子. ...

  8. 9000+ 字,彻底征服 Spring AOP ,美滋滋

    基本知识 其实, 接触了这么久的 AOP, 我感觉, AOP 给人难以理解的一个关键点是它的概念比较多, 而且坑爹的是, 这些概念经过了中文翻译后, 变得面目全非, 相同的一个术语, 在不同的翻译下, ...

  9. Spring AOP概述及底层实现原理

    Spring AOP概述及底层实现原理 aop概述 AOP全称为Aspect Oriented Programming的缩写,意为:面向切面编程.将程序中公用代码进行抽离,通过动态代理实现程序功能的统 ...

最新文章

  1. CentOS7(64位)安装NVIDIA显卡驱动和CUDA8.0
  2. ACM学习历程—Hihocoder [Offer收割]编程练习赛1
  3. Spring与日志的整合
  4. php中对ASCII码的处理ord() 、chr()
  5. 求你了,听我一句劝吧,这几个玩意就别学了!
  6. 用R语言做数据分析——时间序列分类
  7. 为什么使用工作流引擎,什么是工作流引擎,工作流引擎选型以及如何使用
  8. 一个完整的产品设计都要哪些设计流程
  9. STC8I2CGY-302(BH1750光照度强度模块)
  10. 租酥雨的NOIP2018赛前日记
  11. JAVA:实现ClosestPair最近对算法(附完整源码)
  12. DWcs6+AppServ快速搭建PHP环境
  13. Web设计网站软件推荐
  14. 数控铣削图案及编程_数控铣床编程30例带图
  15. 2021最新 腾讯云从零搭建PHP运行环境
  16. UE5 官方案例Lyra 全特性详解 10.进度汇报和视频推荐
  17. 2021-09-12 Autodesk inventor 技巧整理
  18. nltk离线数据:解决nltk.download()下载错误
  19. 测试用例设计方法 之【等价类划分法】
  20. Win7系统配置开机自动连接宽带

热门文章

  1. Ansible系列之roles使用说明
  2. JMS ActiveMQ案例
  3. hibernate延迟加载(get和load的区别)(转)
  4. 黑客与画家 part1 版权声明 part2 O'Reilly Media,Ina.介绍
  5. 《25项最优时间管理工具与技巧》
  6. Excel VBA 学习总结 - 数据验证与正则表达式
  7. WEBBASE篇: 第五篇, CSS知识3
  8. shell编程基础之根据输入进行相应的操作
  9. 制作wordpress页面的学习记录
  10. 10深入理解C指针之---指针运算和比较