aop

Spring第三谈(aop的实现,切入点表达式,aop的作用,浅谈aop底层)

本人是一名物联网工程专业大二的学生,是互联网浪潮中一朵小小的浪花,写博客即是为了记录自己的学习历程,又希望能够帮助到很多和自己一样处于起步阶段的萌新。临渊羡鱼,不如退而结网。与其羡慕别人有顶尖的技术,还不如自己从慢慢摸索学习。终有一天,你也能称为别人“羡慕”的人
博客主页:https://blog.csdn.net/qq_44895397

aop是一个规范,是动态化的一个规范,一个标准

AOP:

        面向切面编程,基于动态代理的,可以使用jdk,cglib两种代理方式
        AOP就是动态代理的规范化,把动态代理的实现步骤,方法都定义好了,让开发人员用一种统一的方式,
        使用动态代理。

 
 
  • 1
  • 2
  • 3

怎么理解面向切面编程:

1)需要在分析项目功能时找出切面
2)合理的安排切面的执行时间
3)合理的安排切面执行的位置

 
 
  • 1
  • 2
  • 3

术语:

 1)Aspect:切面,表示增强功能,完成某一个个的功能,非业务功能
        常见的切面功能有日志、事务、统计信息、参数检查、权限验证
 2)JoinPoint:连接点,连接业务方法和切面的位置,就某类中的业务方法
 3)Pointcut:切入点,指多个连接点方法的集合,多个方法
 4)目标对象:哪个类要增加功能,这个类就是目标对象
 5)Advice:通知,通知表示切面功能执行的时间

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

切面的三个关键要素:

1)切面的功能代码,切面干什么的
2)切面的执行位置,使用Pointcut表示切面的执行位置
3)切面的执行时间,使用Advice表示时间,在目标方法之前,还是目标方法之后 

 
 
  • 1
  • 2
  • 3

aop的技术实现框架:

    1、spring:spring在内部实现了aop规范能够做aop的工作
    spring主要在事务处理时使用aop
    但是spring的aop比较笨重
2、aspectJ:一个开源的专门做aop的框架,spring框架集成了aspectJ框架,通过spring就能够使用aspectj的功能
实现方式有两种:
    1、使用xml的配置文件:配置全局事务
    2、使用注解,项目中使用aop一般都使用注解,aspectj有5个注解
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这里插入图片描述

切入点表达式:

在这里插入图片描述
execution表达式中明显就是方法的签名黑色字体部分可省略,各部分用空格分开,可以用到一下符号:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实现步骤:

1、增加maven依赖
     1)spring依赖
     2)aspectj的依赖
     3)单元测试依赖

 
 
  • 1
  • 2
  • 3
<!--添加spring依赖-->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>5.2.5.RELEASE</version>
</dependency>
<!--aspectj依赖-->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-aspects</artifactId>
	<version>5.2.5.RELEASE</version>
</dependency>

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
2、创建,目标类:接口和他的实现类
    给类中的方法增加功能

 
 
  • 1
3、创建切面类:普通的类
    1)在类的上面加入@Aspectj
	2)在类中定义方法,方法就是切面要执行的功能代码,
         在方法上添加aspectj中的通知注解(@Before)
    	 需要指定切入点表达式,execution()

 
 
  • 1
  • 2
  • 3
  • 4
4、创建配置文件:声明对象,把对象交给容器统一管理,

声明对象你可以使用注解或者xml文件配置文件

  1. 声明目标对象
  2. 声明切面类对象
  3. 声明aspectj框架中的自动代理生成器标签
    自动代理生成器,用来完成代理对象的自动创建功能的
5、创建测试类,从spring容器中获取目标对象(实际是代理对象)
通过代理方法,实现aop的功能增强

 
 
  • 1
代码:

xml文件:

<!--创建实现类对象-->
<bean id="someServiceImpl" class="com.aspectj.domain.SomeServiceImpl"/>

<!–创建切面类的对象–>
<bean id=“utilsTools” class=“com.aspectj.domain.UtilsTools”/>

<!
声明自动代理生成器,使用aspectj框架内部的功能,创建目标对象的代理对象
创建代理对象是在内存中实现的,修改目标对象的内存中的结构,创建为代理对象
所以目标对象就是被修改后的代理对象
>
<aop:aspectj-autoproxy />

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

切面类:

/**
 * 切面类
 * @Aspect :是aspectj框架中的注解
 *  作用:表示当前的类是切面类
 *  切面类:只用来给业务方法增加功能的类,在这个类中有切面的功能代码
 *  位置:类定义的上面
 */
@Aspect
public class UtilsTools {
/**
 * 定义方法,是实现切面功能的
 * 方法定义的要求:
 *      1、公共方法:public
 *      2、方法没有返回值
 *      3、方法名称自定义
 *      4、方法可以有参数,也可以没有参数
 *          如果有参数,参数不是自定义的,有几个参数类型可以使用
 */
/**
 * @Before  前置通知注解
 *      属性value,是切入点表达式,表示切面的功能执行的位置
 *      位置:方法的上面
 *    public void doSome<span class="token punctuation">(</span>String name,Integer age<span class="token punctuation">)</span>
 */
@Before<span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"execution(public void com.aspectj.domain.SomeServiceImpl.doSome(String,Integer))"</span><span class="token punctuation">)</span>
public void dolog<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    //就是切面类要执行的功能代码
    System.out.println<span class="token punctuation">(</span><span class="token string">"切面类"</span> + new Date<span class="token punctuation">(</span><span class="token punctuation">))</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 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

JoinPoint:

指定通知方法中的参数
业务方法,要加入切面功能的业务方法,
**作用是:**可以在通知方法中获取方法执行时的信息,例如方法名,方法参数
如果你的方法中需要用到方法的信息,就加入JoinPoint
这个JoinPoint参数的值是由框架赋予的,必须是第一个位置的参数
使用方法:

/**
 * JoinPoint :切入点
 *  可以获取方法执行的信息
 */
public void dolog(JoinPoint jp){
        Object[] args = jp.getArgs();
        for(Object arg:args){
        System.out.println("参数"+arg);
        }
        System.out.println("切面"+new Date());
        }

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

后置通知:@AfterReturning

	属性:value:切入点表达式
            return:自定义的变量,表示目标方法的返回值的
            自定义的变量名必须和通知方法的形参名一样
            位置:在方法定义的上面
            特点:
                1、在目标方法之后执行的
                2、能够获取到方法的返回值,可以根据这个返回值的不同做不同的处理
                3、可以修改这个返回值

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

具体使用:

@AfterReturning(value = "execution(* *..SomeServiceImpl.*(..))",
        returning = "o")
public void doStudent(JoinPoint jp,Student o){
        System.out.println("事务提交");
        o.setName("多级包");
        o.setAge(12);
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述

环绕通知:@Around

定义格式

1、public
2、必须有一个返回值
3、方法名称自定义自定义
4、方法有参数,固定的参数,ProceedingJoinPoint

 
 
  • 1
  • 2
  • 3
  • 4

属性:value,切入点表达式
位置:在方法的定义上

 特点:
        1、他是功能最强的通知
        2、在目标前后都能增强功能
        3、控制目标方法是是否被调用执行
        4、修改原来的目标方法的执行结果,影响最后的调用结果

 
 
  • 1
  • 2
  • 3
  • 4
  • 5

环绕通知:

等同于jdk动态代理的,InvocationHandler接口
参数:ProceedingJoinPoint pjp 等同于Method
作用:执行目标方法的 pjp.doSome();
返回值:就是目标方法的执行结果,可以被修改
经常做的是事务

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
/**
 * 环绕通知:功能最强大,能在业务方法前后增强功能
 * value:切片表达式
 * ProceedingJoinPoint:参数用来执行方法
 */
@Around(value = "execution(* *..SomeServiceImpl.*(..))")
public Object MyAspectj(ProceedingJoinPoint pjp) throws Throwable {
    //控制方法是否执行
    Object[] args = pjp.getArgs();
    String name = "";
    if (args != null && args.length > 1) {
        name = (String) args[0];
    }
    Object proceed = null;
    System.out.println("方法后执行");
    //目标方法的调用
    if ("yky".equals(name)) {
        proceed = pjp.proceed();//相当于,method.invoke(),可以在这个方法前后增加功能
    }
    System.out.println("方法前执行");
    //修改方法的返回值
    if(proceed != null){
        proceed = "hello world";
    }
    return proceed;
}

 
 
  • 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

异常通知:@AfterThrowing

	1、public
	2、没有返回值
    3、方法名称自定义
    4、方法可以有参数Exception,如果还有是JoinPoint

 
 
  • 1
  • 2
  • 3
  • 4

属性:

    value:切入点表达式
    throwing:表示目标方法抛出的异常对象,自定义变量
    变量名必须和方法的参数名一样

 
 
  • 1
  • 2
  • 3

特点:

  1. 在目标方法抛出异常时执行
  2. 可以做异常的监控程序,监控方法是不是有异常,如果有异常,可以发邮件,短信进行通知

最终通知:@After

	1、public
	2、没有返回值
    3、方法名称自定义
    4、没有参数,,如果有是JoinPoint

 
 
  • 1
  • 2
  • 3
  • 4

特点:总是会执行,在目标方法后执行的 做资源清除的

@Pointcut:

定义和管理切入点,如果项目中有多个切入点是重复的,可以复用的,可以使用这个注解

  • 属性value:切入点表达式

  • 位置:自定义的方法上面

  • 特点:

     当使用@pointcut定义在一个方法的上面,此时方法的名称就是,切入点表达式的别名
     其他通知中value属性可以使用这个方法名,代替切入点表达式了
    
       
       
    • 1
    • 2

代码:

@Before(value = "mycut()")
public void before(){
        System.out.println("前置通知");
        }

@After(value = “mycut()”)
public void finalDemo(){
System.out.println(“最终通知”);
}

/**

  • @Pointcut: 用来管理切入点
    /
    @Pointcut(value = "execution(
    …SomeServiceImpl.(…))")")
    public void mycut(){}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

jdk动态代理实现:

1、创建目标类,SomeServiceImpl目标类,给他的doSome,doOther增加输出时间,事务
 2、创建InvocationHandler接口的实现类,在这个实现类给目标方法增加功能
 3、使用jdk中类Proxy,创建代理对象。实现创建对象的能力

 
 
  • 1
  • 2
  • 3
public static void main(String[] args) {
        //创建目标对象
        SomeService someService = new SomeServiceImpl();
        //创建
        MyInvocationHandler handler = new MyInvocationHandler(someService);

 
 
  • 1
  • 2
  • 3
  • 4
  • 5

创建代理

        SomeService poxy = (SomeService) Proxy.newProxyInstance(someService.getClass().getClassLoader(),
        someService.getClass().getInterfaces(),
        handler);
        poxy.dosome();
        }
public class MyInvocationHandler implements InvocationHandler {
    private Object target;
public MyInvocationHandler<span class="token punctuation">(</span>Object target<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    this.target <span class="token operator">=</span> target<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

@Override
public Object invoke<span class="token punctuation">(</span>Object proxy, Method method, Object<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> throws Throwable <span class="token punctuation">{</span>
    //通过代理对象执行方法时调用执行invoke<span class="token punctuation">(</span><span class="token punctuation">)</span>
    Object res <span class="token operator">=</span> null<span class="token punctuation">;</span>
    utilsTools.dolog<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    //执行目标类的方法,通过Method类实现
    res <span class="token operator">=</span> method.invoke<span class="token punctuation">(</span>target, args<span class="token punctuation">)</span><span class="token punctuation">;</span>//实现类的方法
    utilsTools.doTrans<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    //执行结果
    <span class="token keyword">return</span> res<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

本站所有文章均为原创,欢迎转载,请注明文章出处:爱敲代码的小游子

                                </div>
            <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-60ecaf1f42.css" rel="stylesheet">
                            </div>
</article>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值