zoukankan      html  css  js  c++  java
  • AOP及spring AOP的使用

    介绍

    AOP是一种概念(思想),并没有设定具体语言的实现。
    AOP是对oop的一种补充,不是取而代之。
    具体思想:定义一个切面,在切面的纵向定义处理方法,处理完成之后,回到横向业务流。

    特征

    散布于应用中多处的功能被称为横切关注点
    横切关注点可以被描述为影响应用多处的功能
    切面提供了取代继承和委托的另一种可选方案
    通过声明的方式定义这个功能要以何种方式在何处应用,而无需修改受影响的类

    处理过程

    核心概念

    连接点(join point)

    就是程序执行的某个特定的点:

    你的一个类里,有15个方法,那就有几十个连接点了
    Spring仅支持方法的连接点
    连接点就是为了让你好理解切点,搞出来的,明白这个概念就行了

    切点(pointcut)

    顾名思义切点就是切入哪些连接点,
    切点是用来筛选连接点的,来定义都有哪些连接点需要被执行织入通知,
    连接点相当于数据库中的记录,而切点相当于查询条件,
    一个切点可以匹配出多个连接点
    切点指明:都有哪些切点被切面选中了

    通知(advice)

    切面的工作内容被称为通知,主要是定义我们要做什么事情
    比如:我们要记录每一个方法执行前后的时间日志,这个就是我们这个aop的切面工作内容,也就是通知
    基于连接点的概念,我们必须要指定这些切点
    一般spring的切点都是匹配到方法级别,不会直接定义到某个类某个方法的哪个点,
    所以我们需要为这些切点指定在什么时候织入通知。
    比如:我们的切点包括了10类的100个方法,那么我们不会为每一个类中的方法单独指定在哪个点(前,后,异常)执行通知,我们会采用统一规则,比如都指定为方法前。
    方法前(before)
    方法后(after)
    方法前后(around)
    跑出异常(Exception)
    通知指明:做什么事情,在什么时机(统一切入点)执行

    切面

    通知和切点的结合
    通知和切点共同定义了切面的全部内容——它是什么,在何时和何处完成其功能

    引入

    允许我们向现有的类添加新方法属性。这不就是把切面(也就是新方法属性:通知定义的)用到目标类中吗

    织入

    织入是把切面应用到目标对象并创建新的代理对象的过程
    编译期:切面在目标类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。
    类加载期:切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader),它可以在目标类被引入应用之前增
    强该目标类的字节码。AspectJ 5的加载时织入(load-time weaving,LTW)就支持以这种方式织入切面。
    运行期:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。Spring
    AOP就是以这种方式织入切面的。

    spring mvc中的Aop的实现方式

    基于XML配置的Spring AOP

    创建一个普通的pojo类,没有添加任何注解也没有继承和实现任何接口

    使用xml的方式创建这个切面处理类的实例

    声明切点和切面

    注意通知的配置

    基于注解配置Spring AOP

    首先需要在spring的配置文件中启动对@AspectJ注解的支持

    创建一个切面处理类为这个类上加上@Aspect以及@Component注解

    创建一个切入点表达式

    创建前置通知


    @Before
    @AfterReturning
    @AfterThrowing
    @After
    @Around

    实战

    项目中有很多的页面都需要展示用户的信息,
    没有使用aop之前每一个controller层都需要去设置用户信息,
    于是想起来使用aop的方式解决;

    创建一个注解,用于标识哪些conroller处理函数需要添加用户信息

    /**
     * 注入用户信息
     * <p>
     * 在controller层中添加这个注解就可以实现在返回页面的
     * 的数据里添加上用户的信息
     * 
     * @author   WangSen(wangsenhehe@126.com)
     * @Date     2018年1月17日      
     */
    @Target({ ElementType.METHOD, ElementType.TYPE })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface InjectionUserInfo {
    }
    

    编写切面处理类

    /**
    * PageService.java
    * com.we.core.web.aop
    * Copyright (c) 
    */
    
    package cn.isuyang.web.www.aop;
    
    import java.lang.reflect.Method;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    import cn.isuyang.service.UserDetailBaseService;
    import cn.isuyang.web.www.annotation.InjectionUserInfo;
    
    import com.we.bussiness.sso.interfaces.IFetchUser;
    import com.we.core.web.util.AspectUtil;
    import com.we.core.web.util.MvcUtil;
    
    /**
    * 个人中心用户信息切面
    *
    * @author  wangsen(wangsenhehe@126.com)
    * @Date    2018年1月17日
    */
    @Component
    @Aspect
    @Order(2)
    public class UserInfoAspect {
        @Autowired
        private UserDetailBaseService userDetailBaseService;
        @Autowired
        private IFetchUser fetchUser;
    
        /**
        * 
        * @param pjp 执行的切点对象
        * 
        * @throws Throwable 方法执行错误的时候会抛此异常
        */
        @Around("@annotation(cn.isuyang.web.www.annotation.InjectionUserInfo)")
        @Order(1)
        public Object setUserInfos(final ProceedingJoinPoint pjp) throws Throwable {
            Object result = pjp.proceed();
            if (!isNeedSetUserInfo(pjp)) {
                return result;
            }
            MvcUtil.getRequest().setAttribute("userInfo",
                    userDetailBaseService.getByUserId(fetchUser.getCurrentUserIdWithEx()));
            return result;
        }
    
        /**
        * 是否需要设置用户信息
        *
        * @param pjp 切点
        * 
        * @return true表示存在
        */
        private boolean isNeedSetUserInfo(final ProceedingJoinPoint pjp) {
            Method method = AspectUtil.getMethod(pjp);
            return method.isAnnotationPresent(InjectionUserInfo.class);
        }
    }
    
    

    在controller的处理函数上添加 @InjectionUserInfo注解即可

    /**
     * 
     * @author   WangSen(wangsenhehe@126.com)
     * @Date     2017年8月10日      
     */
    @Controller
    @RequestMapping("/personcenter")
    public class PersonCenterController {
        @Autowired
        private PersonCenterViewService personCenterViewService;
        /**
         * 我的项目
         *
         * @param model 模型
        */
        @RequestMapping
        @InjectionUserInfo
        public void myProject(final MyProjectListForm listform, @ModelAttribute final Page page, final Model model) {
            personCenterViewService.setMyProjectInfo(listform, page, model);
        }
        /**
         * 我的关注
         *
         * @param model 模型
         */
        @RequestMapping
        @InjectionUserInfo
        public void myFollow(final MyFollowListForm listform, @ModelAttribute final Page page, final Model model) {
            personCenterViewService.setMyFollowInfo(listform, page, model);
        }
    }
    

    资料

    aop的基本概念
    http://blog.csdn.net/yuanye348623610/article/details/8823429
    http://www.jianshu.com/p/601713b20e43
    了解知识【AspectJ表达式函数或者叫做切入点表达式】
    execution():满足匹配模式字符串的所有目标类方法的连接点
    @annotation():任何标注了指定注解的目标方法链接点
    资料http://blog.csdn.net/wangpeng047/article/details/8556800
    spring aop的实现原理
    http://www.cnblogs.com/lcngu/p/5339555.html
    http://blog.csdn.net/luanlouis/article/details/51155821
    spring aop的简单模拟实现
    http://www.cnblogs.com/hqbhonker/p/3822237.html

  • 相关阅读:
    证明一下拉普拉斯的《概率分析论》观点
    Android实现小圆点显示未读功能
    命名 —— 函数的命名
    node.js 之爬虫
    ubuntu安装 tensorflow GPU
    古文(诗词文)—— 结构模式与复用
    Win10安装Ubuntu16.04 双系统
    python使用wget下载网络文件
    文字检测与识别资源
    10大深度学习架构:计算机视觉优秀从业者必备
  • 原文地址:https://www.cnblogs.com/wangsen/p/8305026.html
Copyright © 2011-2022 走看看