精华内容
下载资源
问答
  • aopDemo springboot + aop / Around +注解@ReqLog日志记录
  • 外研版一起小学英语五上《Module 8Unit 1 Children often sit around tables.》word教案 (1).docx
  • 主要介绍了Javascript aop(面向切面编程)之around(环绕) ,需要的朋友可以参考下
  • 在开发中使用EditText时可能被软键盘遮挡布局,只需在布局中加入NestedScrollView 在对应的界面初始化 就可完美的解决.
  • Around-源码

    2021-03-19 00:07:51
    Around
  • json-around 在对象流周围放置一个 JSON 字符串。 例子 鉴于此代码 var through = require ( 'through2' ) ; var jsonAround = require ( 'json-around' ) ; var source = through . obj ( ) ; source . pipe ( ...
  • 主要介绍了spring AOP的Around增强实现方法,结合实例形式分析了spring面向切面AOP的Around增强具体步骤与相关操作方法,需要的朋友可以参考下
  • 可插拔,可移动,带monkey-around修补程序 是否曾经需要在某个地方使用猴子补丁方法? 如果您是唯一一个这样做的人,或者可以在程序的整个生命周期中保留该补丁,这并不难。 但是,如果需要多个独立编写的代码来修补...
  • RecyclerView66996774解决方法 ... 首先,您需要尝试更好的解决方案: : 仅当您不想要一种行为或您无法拥有一种行为时。 然后尝试这个解决方案 ... RecyclerView66996774Workaround.assistRcyclerView(recyclerview);
  • haxm-extract-workaround.rar

    2020-02-03 17:43:26
    1、下载haxm_extra_workaround.zip 附件 2、解压后提取hax_extract.cmd 文件到 HAXM 的解压文件路径中 3、hax_extract.cmd 右键用管理员权限运行。 执行以上步骤后,基本可以解决以上提示的安装异常问题。祝大家...
  • Around-View-Monitor-Project
  • pythoning-around 在Heroku上试用Python
  • java错误-java.lang.ClassNotFoundException: org.aspectj.lang.annotation.Around Spring的AOP需要上述三个jar包
  • what goes around stonebraker

    2018-07-07 15:01:38
    数据库大牛谈newsql时代,数据库大牛谈newsql时代,数据库大牛谈newsql时代,数据库大牛谈newsql时代,数据库大牛谈newsql时代,数据库大牛谈newsql时代,数据库大牛谈newsql时代,数据库大牛谈newsql时代,数据库大...
  • 我周围的空气 嘿,这是针对Android设备的众包空气质量测量工具
  • Project_ARound_2021.03:젝트로프-어라운드
  • haxm-extract-workaround.zip

    2015-07-22 13:57:29
    android studio,虚拟机启动失败,安装一下这个
  • django-write-around-cache 用于缓存的 Django 应用程序,可随意刷新模板缓存!
  • 英语优秀教学案(人教版):必修一 Unit 2 English around the world Period 4 Grammar.doc
  • @Around 和 @After 等advice。最近,为了实现项目中的 输出日志 和 权限控制 这两个需求,我也使用到了AOP功能。我使用到了 @Before 、 @Around 这两个advice。但在,使用过程中,却对它们的执行顺序并不清楚。为了...

    用过spring框架进行开发的人,多多少少会使用过它的AOP功能,都知道有@Before@Around@After等advice。最近,为了实现项目中的输出日志权限控制这两个需求,我也使用到了AOP功能。我使用到了@Before@Around这两个advice。但在,使用过程中,却对它们的执行顺序并不清楚。为了弄清楚在不同情况下,这些advice到底是以怎么样的一个顺序进行执行的,我作了个测试,在此将其记录下来,以供以后查看。

    前提

    • 对于AOP相关类(aspect、pointcut等)的概念,本文不作说明。
    • 对于如何让spring框架扫描到AOP,本文也不作说明。

    情况一: 一个方法只被一个Aspect类拦截

    当一个方法只被一个Aspect拦截时,这个Aspect中的不同advice是按照怎样的顺序进行执行的呢?请看:

    添加 PointCut

    该pointcut用来拦截test包下的所有类中的所有方法。

    package test;
    
    import org.aspectj.lang.annotation.Pointcut;
    
    public class PointCuts {
        @Pointcut(value = "within(test.*)")
        public void aopDemo() {
    
        }
    }
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    添加Aspect

    该类中的advice将会用到上面的pointcut,使用方法请看各个advice的value属性。

    package test;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    
    @Component
    @Aspect
    public class Aspect1 {
    
        @Before(value = "test.PointCuts.aopDemo()")
        public void before(JoinPoint joinPoint) {
            System.out.println("[Aspect1] before advise");
        }
    
        @Around(value = "test.PointCuts.aopDemo()")
        public void around(ProceedingJoinPoint pjp) throws  Throwable{
            System.out.println("[Aspect1] around advise 1");
            pjp.proceed();
            System.out.println("[Aspect1] around advise2");
        }
    
        @AfterReturning(value = "test.PointCuts.aopDemo()")
        public void afterReturning(JoinPoint joinPoint) {
            System.out.println("[Aspect1] afterReturning advise");
        }
    
        @AfterThrowing(value = "test.PointCuts.aopDemo()")
        public void afterThrowing(JoinPoint joinPoint) {
            System.out.println("[Aspect1] afterThrowing advise");
        }
    
        @After(value = "test.PointCuts.aopDemo()")
        public void after(JoinPoint joinPoint) {
            System.out.println("[Aspect1] after advise");
        }
    }
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    添加测试用Controller

    添加一个用于测试的controller,这个controller中只有一个方法,但是它会根据参数值的不同,会作出不同的处理:一种是正常返回一个对象,一种是抛出异常(因为我们要测试@AfterThrowing这个advice)

    package test;
    
    import test.exception.TestException;
    import org.springframework.http.HttpStatus;
    import org.springframework.web.bind.annotation.*;
    
    @RestController
    @RequestMapping(value = "/aop")
    public class AopTestController {
    
        @ResponseStatus(HttpStatus.OK)
        @RequestMapping(value = "/test", method = RequestMethod.GET)
        public Result test(@RequestParam boolean throwException) {
            // case 1
            if (throwException) {
                System.out.println("throw an exception");
                throw new TestException("mock a server exception");
            }
    
            // case 2
            System.out.println("test OK");
            return new Result() {{
                this.setId(111);
                this.setName("mock a Result");
            }};
        }
    
        public static class Result {
            private int id;
            private String name;
    
            public int getId() {
                return id;
            }
    
            public void setId(int id) {
                this.id = id;
            }
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
        }
    }
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    测试 正常情况

    在浏览器直接输入以下的URL,回车:

    http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=false
     
    • 1

    我们会看到输出的结果是:

    [Aspect1] around advise 1
    [Aspect1] before advise
    test OK
    [Aspect1] around advise2
    [Aspect1] after advise
    [Aspect1] afterReturning advise
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    测试 异常情况

    在浏览器中直接输入以下的URL,回车:

    http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=true
     
    • 1

    我们会看到输出的结果是:

    [Aspect1] around advise 1
    [Aspect1] before advise
    throw an exception
    [Aspect1] after advise
    [Aspect1] afterThrowing advise
     
    • 1
    • 2
    • 3
    • 4
    • 5

    结论

    在一个方法只被一个aspect类拦截时,aspect类内部的 advice 将按照以下的顺序进行执行:

    正常情况:
    one-ok


    异常情况:
    one-exception

    情况二: 同一个方法被多个Aspect类拦截

    此处举例为被两个aspect类拦截。
    有些情况下,对于两个不同的aspect类,不管它们的advice使用的是同一个pointcut,还是不同的pointcut,都有可能导致同一个方法被多个aspect类拦截。那么,在这种情况下,这多个Aspect类中的advice又是按照怎样的顺序进行执行的呢?请看:

    pointcut类保持不变

    添加一个新的aspect类

    package test;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    
    @Component
    @Aspect
    public class Aspect2 {
    
        @Before(value = "test.PointCuts.aopDemo()")
        public void before(JoinPoint joinPoint) {
            System.out.println("[Aspect2] before advise");
        }
    
        @Around(value = "test.PointCuts.aopDemo()")
        public void around(ProceedingJoinPoint pjp) throws Throwable{
            System.out.println("[Aspect2] around advise 1");
            pjp.proceed();
            System.out.println("[Aspect2] around advise2");
        }
    
        @AfterReturning(value = "test.PointCuts.aopDemo()")
        public void afterReturning(JoinPoint joinPoint) {
            System.out.println("[Aspect2] afterReturning advise");
        }
    
        @AfterThrowing(value = "test.PointCuts.aopDemo()")
        public void afterThrowing(JoinPoint joinPoint) {
            System.out.println("[Aspect2] afterThrowing advise");
        }
    
        @After(value = "test.PointCuts.aopDemo()")
        public void after(JoinPoint joinPoint) {
            System.out.println("[Aspect2] after advise");
        }
    }
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    测试用Controller也不变

    还是使用上面的那个Controller。但是现在 aspect1 和 aspect2 都会拦截该controller中的方法。

    下面继续进行测试!

    测试 正常情况

    在浏览器直接输入以下的URL,回车:

    http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=false
     
    • 1

    我们会看到输出的结果是:

    [Aspect2] around advise 1
    [Aspect2] before advise
    [Aspect1] around advise 1
    [Aspect1] before advise
    test OK
    [Aspect1] around advise2
    [Aspect1] after advise
    [Aspect1] afterReturning advise
    [Aspect2] around advise2
    [Aspect2] after advise
    [Aspect2] afterReturning advise
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    但是这个时候,我不能下定论说 aspect2 肯定就比 aspect1 先执行。
    不信?你把服务务器重新启动一下,再试试,说不定你就会看到如下的执行结果:

    [Aspect1] around advise 1
    [Aspect1] before advise
    [Aspect2] around advise 1
    [Aspect2] before advise
    test OK
    [Aspect2] around advise2
    [Aspect2] after advise
    [Aspect2] afterReturning advise
    [Aspect1] around advise2
    [Aspect1] after advise
    [Aspect1] afterReturning advise
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    也就是说,这种情况下, aspect1 和 aspect2 的执行顺序是未知的。那怎么解决呢?不急,下面会给出解决方案。

    测试 异常情况

    在浏览器中直接输入以下的URL,回车:

    http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=true
     
    • 1

    我们会看到输出的结果是:

    [Aspect2] around advise 1
    [Aspect2] before advise
    [Aspect1] around advise 1
    [Aspect1] before advise
    throw an exception
    [Aspect1] after advise
    [Aspect1] afterThrowing advise
    [Aspect2] after advise
    [Aspect2] afterThrowing advise
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    同样地,如果把服务器重启,然后再测试的话,就可能会看到如下的结果:

    [Aspect1] around advise 1
    [Aspect1] before advise
    [Aspect2] around advise 1
    [Aspect2] before advise
    throw an exception
    [Aspect2] after advise
    [Aspect2] afterThrowing advise
    [Aspect1] after advise
    [Aspect1] afterThrowing advise
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    也就是说,同样地,异常情况下, aspect1 和 aspect2 的执行顺序也是未定的。

    那么在 情况二 下,如何指定每个 aspect 的执行顺序呢?
    方法有两种:

    • 实现org.springframework.core.Ordered接口,实现它的getOrder()方法
    • 给aspect添加@Order注解,该注解全称为:org.springframework.core.annotation.Order

    不管采用上面的哪种方法,都是值越小的 aspect 越先执行。
    比如,我们为 apsect1 和 aspect2 分别添加 @Order 注解,如下:

    @Order(5)
    @Component
    @Aspect
    public class Aspect1 {
        // ...
    }
    
    @Order(6)
    @Component
    @Aspect
    public class Aspect2 {
        // ...
    }
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    这样修改之后,可保证不管在任何情况下, aspect1 中的 advice 总是比 aspect2 中的 advice 先执行。如下图所示:
    two-ok

    注意点

    • 如果在同一个 aspect 类中,针对同一个 pointcut,定义了两个相同的 advice(比如,定义了两个 @Before),那么这两个 advice 的执行顺序是无法确定的,哪怕你给这两个 advice 添加了 @Order 这个注解,也不行。这点切记。

    • 对于@Around这个advice,不管它有没有返回值,但是必须要方法内部,调用一下 pjp.proceed();否则,Controller 中的接口将没有机会被执行,从而也导致了 @Before这个advice不会被触发。比如,我们假设正常情况下,执行顺序为”aspect2 -> apsect1 -> controller”,如果,我们把 aspect1中的@Around中的 pjp.proceed();给删掉,那么,我们看到的输出结果将是:

    [Aspect2] around advise 1
    [Aspect2] before advise
    [Aspect1] around advise 1
    [Aspect1] around advise2
    [Aspect1] after advise
    [Aspect1] afterReturning advise
    [Aspect2] around advise2
    [Aspect2] after advise
    [Aspect2] afterReturning advise
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    从结果可以发现, Controller 中的 接口 未被执行,aspect1 中的 @Before advice 也未被执行。

    参考资料

    Advice ordering
    
    What happens when multiple pieces of advice all want to run at the same join point? 
    Spring AOP follows the same precedence rules as AspectJ to determine the order of advice execution. 
    The highest precedence advice runs first "on the way in" (so given two pieces of before advice, the one with highest precedence runs first).
    "On the way out" from a join point, the highest precedence advice runs last (so given two pieces of after advice, the one with the highest precedence will run second).
    
    When two pieces of advice defined in different aspects both need to run at the same join point,
    unless you specify otherwise the order of execution is undefined. 
    You can control the order of execution by specifying precedence.
    This is done in the normal Spring way by either implementing the org.springframework.core.Ordered interface in the aspect class or annotating it with the Order annotation. 
    Given two aspects, the aspect returning the lower value from Ordered.getValue() (or the annotation value) has the higher precedence.
    
    When two pieces of advice defined in the same aspect both need to run at the same join point, 
    the ordering is undefined (since there is no way to retrieve the declaration order via reflection for javac-compiled classes). 
    Consider collapsing such advice methods into one advice method per join point in each aspect class, 
    or refactor the pieces of advice into separate aspect classes - which can be ordered at the aspect level.
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
                <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-e44c3c0e64.css" rel="stylesheet">
                    </div>
    
    展开全文
  • Bean-Around-源码

    2021-03-19 13:07:44
    Bean Around是面向咖啡爱好者的全栈式Web应用程序,他们希望跟踪他们尝试过的每种咖啡豆。对于每个bean条目,您可以选择添加基于brew方法的个人评论。这是记住您尝试过的内容并与朋友分享您的收藏夹的好方法!想要...
  • workaround.s51

    2015-09-07 15:21:41
    使用IAR8.30.2编译之前版本协议栈出现错误解决方法
  • 与Binaryninja一起转转 这是我在twitch流中编写的代码库 。 集数 : Callgraph插件,部分: : : : :自动化去混淆处理! 第7集:实际上是自动化的东西!
  • 此段小代码演示了spring aop中@Around @Before @After三个注解的区别 @Before是在所拦截方法执行之前执行一段逻辑。 @After 是在所拦截方法执行之后执行一段逻辑。 @Around是可以同时在所拦截方法的前后执行一段...

    此段小代码演示了spring aop中@Around @Before @After三个注解的区别

    @Before是在所拦截方法执行之前执行一段逻辑。

    @After 是在所拦截方法执行之后执行一段逻辑。

    @Around是可以同时在所拦截方法的前后执行一段逻辑。

    连接点(JoinPoint) 这个就更好解释了,就是spring允许你是通知(Advice)的地方,那可就真多了,基本每个方法的前、后(两者都有也行),或抛出异常是时都可以是连接点,spring只支持方法连接点。

    其他如AspectJ还可以让你在构造器或属性注入时都行,不过那不是咱们关注的,只要记住,和方法有关的前前后后都是连接点。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package com.itsoft.action;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.springframework.stereotype.Controller;
    /**
     * 
     * @author zxf
     * 演示aop测试类
     */
    @Controller
    public class UserAction {
     public void queryUsers(){
      System.out.println("查询所有用户【all users list】");
     }
     public static void main(String[] args) {
      ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("application-aop.xml");
      UserAction userAction = (UserAction)ctx.getBean("userAction");
      userAction.queryUsers();
      ctx.destroy();
     }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    package com.itsoft;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    /**
     * 
     * @author Administrator
     * 通过aop拦截后执行具体操作
     */
    @Aspect
    @Component
    public class LogIntercept {
     @Pointcut("execution(public * com.itsoft.action..*.*(..))")
     public void recordLog(){}
     @Before("recordLog()")
     public void before() {
      this.printLog("已经记录下操作日志@Before 方法执行前");
     }
     @Around("recordLog()")
     public void around(ProceedingJoinPoint pjp) throws Throwable{
      this.printLog("已经记录下操作日志@Around 方法执行前");
      pjp.proceed();
      this.printLog("已经记录下操作日志@Around 方法执行后");
     }
     @After("recordLog()")
     public void after() {
      this.printLog("已经记录下操作日志@After 方法执行后");
     }
     private void printLog(String str){
      System.out.println(str);
     }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:aop="http://www.springframework.org/schema/aop"
      xmlns:context="http://www.springframework.org/schema/context"
      xsi:schemaLocation="
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-3.0.xsd
      http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
      http://www.springframework.org/schema/aop 
      http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
     <context:annotation-config />
     <context:component-scan base-package="com.itsoft"/>
     <aop:aspectj-autoproxy />
    </beans>
    补充:spring aop的@Before,@Around,@After,@AfterReturn,@AfterThrowing的理解

    1.AOP的基本概念
    切面(Aspect) :通知(advice)和切入点(pointcut)共同组成了切面(aspect),时间、地点和要发生的“故事”。

    可以从注解方式来理解,代码如下。

    @aspect为类上面的注解——切面

    @pointcut(…)——切入点。为此类内一个空方法上面的注解。可以把拦截的地址表达式表示为方法签名,利于使用起来方便。

    @before@after等——通知。为此类下面的方法上面的注解。

    三者在一块组成一个切面。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Aspect
    public class ExampleAspect {
     @Pointcut("execution(* com.psjay.example.spring.aop.*.*(..))")
     public void aPointcut() {
     }
     @Before("aPointcut()")
     public void beforeAdvice() {
      System.out.println("before advice is executed!");
     }
    }
    连接点(Joinpoint) :程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法被调用时、异常被抛出时等等。——可以理解为被aop拦截的类或者方法就是连接点。

    通知(Advice) :通知定义了切面是什么以及何时使用。描述了切面要完成的工作和何时需要执行这个工作。——可以理解为被注解有@Before等advice注解的安全校验的方法,拦截了过来的请求要做什么逻辑的校验。

    切入点(Pointcut) :通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的地点,例如某个类或方法的名称。——可以理解为切面切向哪里?是个类或者某层的包路径。

    目标对象(Target Object) :即被通知的对象。

    AOP代理(AOP Proxy) 在Spring AOP中有两种代理方式,JDK动态代理和CGLIB代理。默认情况下,TargetObject实现了接口时,则采用JDK动态代理;反之,采用CGLIB代理。

    织入(Weaving)把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机:

    (1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才能做到,例如AspectJ的织入编译器;

    (2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码;

    (3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理是使用了JDK的动态代理。

    2 通知(Advice)类型的说明
    @Before 前置通知(Before advice) :在某连接点(JoinPoint)——核心代码(类或者方法)之前执行的通知,但这个通知不能阻止连接点前的执行。

    为啥不能阻止线程进入核心代码呢?

    因为@Before注解的方法入参不能传ProceedingJoinPoint,而只能传入JoinPoint。

    要知道从aop走到核心代码就是通过调用ProceedingJionPoint的proceed()方法。

    而JoinPoint没有这个方法。

    这里牵扯区别这两个类:Proceedingjoinpoint 继承了 JoinPoint 。

    是在JoinPoint的基础上暴露出 proceed 这个方法。proceed很重要,这个是aop代理链执行的方法。

    暴露出这个方法,就能支持 aop:around 这种切面(而其他的几种切面只需要用到JoinPoint,这跟切面类型有关), 能决定是否走代理链还是走自己拦截的其他逻辑。

    建议看一下 JdkDynamicAopProxy的invoke方法,了解一下代理链的执行原理。

    这样你就能明白 proceed方法的重要性。

    @After 后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

    @AfterReturning 返回后通知(After return advice) :在某连接点正常完成后执行的通知,不包括抛出异常的情况。

    @Around 环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。

    可以在方法的调用前后完成自定义的行为,也可以选择不执行。

    这时aop的最重要的,最常用的注解。

    用这个注解的方法入参传的是ProceedingJionPoint pjp,可以决定当前线程能否进入核心方法中——通过调用pjp.proceed();

    @AfterThrowing 抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。

    展开全文
  • 通知(Advice):切面何时使用,即注有@Around、@Before、@After等注解的方法 情况一:一个方法只被一个Aspect类拦截 添加PointCut类 添加Aspect类 这两个可以放在一起 package com.bob.hello.aspect; import ...

    1.AOP基本概念

    切面(Aspect):通知(advice)和切入点(pointcut)共同组成了切面(aspect)

    切入点(Pointcut):匹配join point的谓词,切面切向哪里,某个类或者某一层包路径

    连接点(Joinpoint):aop拦截的类或者方法,例如方法被调用时、异常被抛出时。(在Spring中,所有的方法都可以认为是joinpoint,但是我们不希望所有的方法都添加Advice,而pointcut的作用就是提供一组规则来匹配joinpoint,给满足规则的joinpoint添加Advice。)

    通知(Advice):切面何时使用,即注有@Around、@Before、@After等注解的方法

    目标对象(Target Object):被通知的对象

    AOP代理(AOP Proxy): AOP的代理有两种,一种是JDK动态代理,一种是CGLIB代理。默认情况下,TargetObject实现了接口时,则采用JDK动态代理;反之,采用CGLIB代理

    Joinpoint和Pointcut区别:在Spring AOP中,所有的方法执行都是joinpoint,而pointcut是一个描述信息,它修饰的是joinpoint,通过pointcut可以确定哪些jointpoint可以被Advice。

    2.通知(Advice)类型说明

    @Around:环绕通知,包围一个连接点的通知,可以在核心方法前后完成自定义的行为。这是最常用最重要的。这个注解需要传入参数ProceedingJoinPoint pjp,决定是否进入核心方法----调用pjp.proceed();如果不调的话将不进入核心方法!

    @Before:前通知,核心代码执行前通知

    @After:后通知,连接点执行退出时通知(不论正常返回还是异常退出)

    @AfterReturning:返回后通知,正常返回后通知

    @AfterThrowing:抛出异常后通知,抛出异常时通知

    注意:除了@Around传的参数是ProceedingJoinPoint pjp外,其它都是传的JoinPoint jp,也就是说能控制是否进入核心代码的只有Around,因为aop走到核心代码就是通过调用ProceedingJoinPoint的proceed()方法,而JoinPoint没有这个方法。

    3.Advice顺序:

    情况一:一个方法只被一个Aspect类拦截

    添加PointCut类  添加Aspect类   这两个可以放在一起

    package com.bob.hello.aspect;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    
    /**
     * Description
     *
     * @author Bob
     * @date 2020/6/2
     **/
    @Component
    @Aspect
    public class DemoAspect {
    
        /**
         * @description 拦截com.bob.hello包下所有方法
         * @author Bob
         * @date 2020/6/2
         */
        @Pointcut(value = "within(com.bob.hello.controller.*)")
        public void demoPointCut() {
    
        }
    
        @Before(value = "demoPointCut()")
        public void before(JoinPoint joinPoint) {
            System.out.println("[DemoAspect] before advice");
        }
    
        @Around(value = "demoPointCut()")
        public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("[DemoAspect] around advice 1");
            proceedingJoinPoint.proceed();
            System.out.println("[DemoAspect] around advice 2");
        }
    
        @After(value = "demoPointCut()")
        public void after(JoinPoint joinPoint) {
            System.out.println("[DemoAspect] after advice");
        }
    
        @AfterThrowing(value = "demoPointCut()")
        public void afterThrowing(JoinPoint joinPoint) {
            System.out.println("[DemoAspect] afterThrowing advice");
        }
    
        @AfterReturning(value = "demoPointCut()")
        public void afterReturning(JoinPoint joinPoint) {
            System.out.println("[DemoAspect] afterReturning advice");
        }
    }
    

    添加测试用的Controller

    package com.bob.hello.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * Description
     *
     * @author Bob
     * @date 2020/5/26
     **/
    @RestController
    public class HelloController {
    
        @GetMapping("/hello")
        public String hello(){
            System.out.println("hello");
            return "hello";
        }
    }

    测试 正常情况

    浏览器直接输入:http://localhost:8080/hello

    输出的结果:

    [DemoAspect] around advice 1
    [DemoAspect] before advice
    hello
    [DemoAspect] around advice 2
    [DemoAspect] after advice
    [DemoAspect] afterReturning advice

    注意:如果用到了Spring Security,会先走登录拦截

    结论

    在一个方法只被一个aspect类拦截时,aspect类内部的 advice 将按照以下的顺序进行执行:

    one-ok

    情况二:同一个方法被多个Aspect类拦截

    aspect1和aspect2的执行顺序是未知的,除非设置他们的Order顺序,具体参见:Spring AOP @Before @Around @After 等 advice 的执行顺序

    4.定义Aspect(切面)

    当使用@Aspect标注一个bean后,Spring框架会自动收集这些bean,并添加到Spring AOP中,例如:

    @Component
    @Aspect
    public class DemoAspect {
    
    }

    注意:仅仅使用@Aspect 注解并不能将一个Java对象转换为bean,因此还需要类似@Component 之类的注解。

    注意:如果一个类被@Aspect 标注,则这个类就不能是其它aspect的**advised object** 了,因为使用@Aspect后,这个类就会别排除在auto-proxying机制之外。

    5.声明Pointcut(切入点)

    在@AspectJ 风格的AOP中,这样来描述pointcut,例如:

    @Pointcut(value = "within(com.bob.hello.controller.*)")
    public void demoPointCut() {
    
    }

    value里面的值叫pointcut(切点)表达式,它由标识符操作参数组成,within就是标识符,()里的就是操作参数。

    6.组合切入点表达式

    AspectJ使用 且(&&)、或(||)、非(!)来组合切入点表达式

    常见的切点表达式

    execution:使用"execution(方法表达式)"匹配方法执行

    // 任何公共方法的执行
    public * *(..)
    
    // 匹配指定包中的所有的方法
    execution(* com.xys.service.*(..))
    
    // 匹配当前包中的指定类的所有方法
    execution(* UserService.*(..))
    
    // 匹配指定包中的所有 public 方法
    execution(public * com.xys.service.*(..))
    
    // 匹配指定包中的所有 public 方法, 并且返回值是 int 类型的方法
    execution(public int com.xys.service.*(..))
    
    // 匹配指定包中的所有 public 方法, 并且第一个参数是 String, 返回值是 int 类型的方法
    execution(public int com.xys.service.*(String name, ..))
    
    // 匹配所有带@Scheduled 注解的方法
    execution(@org.springframework.scheduling.annotation.Scheduled * *(..))

    within:使用"within(类型表达式)"匹配指定类型内的方法执行

    // 匹配指定包中的所有的方法, 但不包括子包
    within(com.xys.service.*)
    
    // 匹配指定包中的所有的方法, 包括子包
    within(com.xys.service..*)
    
    // 匹配当前包中的指定类中的方法
    within(UserService)
    
    // 匹配一个接口的所有实现类中的实现的方法
    within(UserDao+)
    

    @within:使用"@within(注解类型)"匹配所以持有指定注解类型内的方法;注解类型也必须是全限定类型名;

    // 匹配注解
    @within(org.springframework.web.bind.annotation.RestController) || @within(org.springframework.stereotype.Controller) ||  @within(org.springframework.stereotype.Service) || @within(org.springframework.stereotype.Component)
    
    //任何目标对象对应的类型持有Secure注解的类方法;必须是在目标对象上声明这个注解,在接口上声明的对它不起作用
    @within(cn.javass.spring.chapter6.Secure)

    @annotation:使用"@annotation(注解类型)"匹配当前执行方法持有指定注解的方法;注解类型也必须是全限定类型名;

    提示:括号里的"注解类型"不是接口!而是"@interface"!!

    // 当前执行方法上持有注解 cn.javass.spring.chapter6.Secure将被匹配
    @annotation(cn.javass.spring.chapter6.Secure )

    匹配Bean名字

    // 匹配以指定名字结尾的 Bean 中的所有方法
    bean(*Service)

    切点表达式组合

    // 匹配以 Service 或 ServiceImpl 结尾的 bean
    bean(*Service || *ServiceImpl)
    
    // 匹配名字以 Service 开头, 并且在包 com.xys.service 中的 bean
    bean(*Service) && within(com.xys.service.*)

    execution通常用与匹配方法,within通常用于匹配特定注解

    参考:彻底征服 Spring AOP 之 理论篇 

    6.声明Advice(通知)

    示例中的@Before @Around等

    7.Spring AOP实战

    HTTP接口鉴权

    核心代码:

    @Component
    @Aspect
    public class HttpAopAdviseDefine {
    
        // 定义一个 Pointcut, 使用 切点表达式函数 来描述对哪些 Join point 使用 advise.
        @Pointcut("@annotation(com.xys.demo1.AuthChecker)")
        public void pointcut() {
        }
    
        // 定义 advise
        @Around("pointcut()")
        public Object checkAuth(ProceedingJoinPoint joinPoint) throws Throwable {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                    .getRequest();
    
            // 检查用户所传递的 token 是否合法
            String token = getUserToken(request);
            if (!token.equalsIgnoreCase("123456")) {
                return "错误, 权限不合法!";
            }
    
            return joinPoint.proceed();
        }
    
        private String getUserToken(HttpServletRequest request) {
            Cookie[] cookies = request.getCookies();
            if (cookies == null) {
                return "";
            }
            for (Cookie cookie : cookies) {
                if (cookie.getName().equalsIgnoreCase("user_token")) {
                    return cookie.getValue();
                }
            }
            return "";
        }
    }

    方法调用日志

    核心代码:

    @Component
    @Aspect
    public class LogAopAdviseDefine {
        private Logger logger = LoggerFactory.getLogger(getClass());
    
        // 定义一个 Pointcut, 使用 切点表达式函数 来描述对哪些 Join point 使用 advise.
        @Pointcut("within(NeedLogService)")
        public void pointcut() {
        }
    
        // 定义 advise
        @Before("pointcut()")
        public void logMethodInvokeParam(JoinPoint joinPoint) {
            logger.info("---Before method {} invoke, param: {}---", joinPoint.getSignature().toShortString(), joinPoint.getArgs());
        }
    
        @AfterReturning(pointcut = "pointcut()", returning = "retVal")
        public void logMethodInvokeResult(JoinPoint joinPoint, Object retVal) {
            logger.info("---After method {} invoke, result: {}---", joinPoint.getSignature().toShortString(), joinPoint.getArgs());
        }
    
        @AfterThrowing(pointcut = "pointcut()", throwing = "exception")
        public void logMethodInvokeException(JoinPoint joinPoint, Exception exception) {
            logger.info("---method {} invoke exception: {}---", joinPoint.getSignature().toShortString(), exception.getMessage());
        }
    }

    方法耗时统计

    核心代码:

    @Component
    @Aspect
    public class ExpiredAopAdviseDefine {
        private Logger logger = LoggerFactory.getLogger(getClass());
    
        // 定义一个 Pointcut, 使用 切点表达式函数 来描述对哪些 Join point 使用 advise.
        @Pointcut("within(SomeService)")
        public void pointcut() {
        }
    
        // 定义 advise
        // 定义 advise
        @Around("pointcut()")
        public Object methodInvokeExpiredTime(ProceedingJoinPoint pjp) throws Throwable {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            // 开始
            Object retVal = pjp.proceed();
            stopWatch.stop();
            // 结束
    
            // 上报到公司监控平台
            reportToMonitorSystem(pjp.getSignature().toShortString(), stopWatch.getTotalTimeMillis());
    
            return retVal;
        }
    
    
        public void reportToMonitorSystem(String methodName, long expiredTime) {
            logger.info("---method {} invoked, expired time: {} ms---", methodName, expiredTime);
            //
        }
    }

    来自:彻底征服 Spring AOP 之 实战篇

    参考:

    Spring AOP @Before @Around @After 等 advice 的执行顺序

    spring aop的@Before,@Around,@After,@AfterReturn,@AfterThrowing的理解

    彻底征服 Spring AOP 之 理论篇 

    彻底征服 Spring AOP 之 实战篇

    https://blog.csdn.net/qq_23167527/article/details/78623639

    展开全文
  • Shows a 'Trips around Taiwan' in overall summary page on Endomondo site在Endomondo官方網站首頁或使用者的主頁的Overall Summary,新增一個Trips Around Taiwan的欄位,顯示目前該運動總里程等於環台灣多少圈。...
  • 数组排序的代码,在运行时显示:Stack around the variable 'array' was corrupted. 以下为源代码: ``` #include main() { //定义数组 int array[10]; int p; int i,j; int min; for (i = 0;i ;i...
  • around方法及其注释是before、after、afterReturning和afterThrowing方法或注释的综合。 其具体的运作流程可以简化为: try { try { doBefore();// @Before注解所修饰的方法 method.invoke();// 执行目标...

    around方法及其注解是before、after、afterReturning和afterThrowing方法或注解的综合。

    其具体的运作流程可以简化为:

    try {
    	try {
    		doBefore();// @Before注解所修饰的方法
    		method.invoke();// 执行目标对象内的方法
    	} finally {
    		doAfter();// @After注解所修饰的方法
    	}
    	doAfterReturning();// @AfterReturning注解所修饰的方法
    } catch (Exception e) {
    	doAfterThrowing();// @AfterThrowing注解所修饰的方法
    }
    

    仍以与前两篇博客相同的实验结构:

    具体实验代码如下。

    Spring框架配置文件application.xml为:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <context:component-scan base-package="com.jd"></context:component-scan>
    
        <bean class="com.jd.aspect.CaculatorAspect" id="caculatorAspect"></bean>
        <aop:config proxy-target-class="true">
            <aop:pointcut id="p" expression="execution(* com.jd.caculator.service.CaculatorService.* (..))"/>
            <aop:aspect ref="caculatorAspect" >
                <aop:around method="around" pointcut-ref="p"></aop:around>
            </aop:aspect>
        </aop:config>
    </beans>

    切片类CaculatorAspect.java及其around方法:

    package com.jd.aspect;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    @Component
    public class CaculatorAspect {
    
        public Object around(ProceedingJoinPoint jp){
            Object result = -1;
            try {
                String name = jp.getSignature().getName();//获取调用该类的方法名
                try {
                    Object [] args = jp.getArgs();//获取参数
                    System.out.println("Before->The "+name+" method begins");
                    System.out.println("Before->The params of the "+name+" method are "+args[0]+","+args[1]);
                    result = jp.proceed();// 执行目标对象内的方法
                } finally {
                    System.out.println("After->"+"The "+name+" method ends");// @After注解所修饰的方法
                }
                System.out.println("AfterReturning->"+"The "+name+" method ends-returning:"+result);// @AfterReturning注解所修饰的方法
            } catch (Throwable e) {
                System.out.println("AfterThrowing->"+e);// @AfterThrowing注解所修饰的方法
            }
            return result;
        }
    
    }
    

     实验类Test.java及主方法为:

    import com.jd.caculator.service.ICaculatorService;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Test {
    
        public static void main(String[] args) {
            ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
            ICaculatorService caculatorService = applicationContext.getBean(ICaculatorService.class);
            int result = caculatorService.div(8,2);
            System.out.println(result);
            applicationContext.close();
        }
    }
    

    实验结果如下:

    与最初相比,使用Spring的XML框架和around方法完成AOP的编程,能最大程度的减少代码量,提高了复用度。

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 277,290
精华内容 110,916
关键字:

around