ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

spring aop

2020-11-24 17:33:20  阅读:224  来源: 互联网

标签:spring 切入点 aop 代理 pointcut 通知 public 表达式


 

1. AOP

  aspect oriented programming,面向切面编程。通过预编译方式和运行期动态代理实现程序功能的技术。把程序重复的代码抽取出来,在需要执行的时候通过动态代理的方式,在不修改源码的情况下,对已有的方法进行增强。

 

  ①Joinpoint 连接点:

    被拦截到的点。spring中指方法(spring只支持方法类型的连接点)

  ②Pointcut 切入点:

    会被拦截并增强的连接点

  ③Advice  通知/增强:

    拦截到连接点后要做的事

    通知类型(根据和invoke方法的前后顺序区分):前置通知、后置通知、异常通知(catch里面的)、最终通知(finally里面的)、环绕通知

  ④Introduction  引介

    在不修改现有的类的情况下,向现有的类添加新属性和新方法

  ⑤Target  目标对象

    被代理对象

  ⑥Weaving  织入

    把增强部分应用到目标对象来创建新的代理的过程:①编译期织入(需要特殊的编译器,AspectJ) ②类加载期织入(需要特殊的类加载器,Aspectj 5)   ③运行期织入(运行时为目标对象动态地创建一个代理对象,在代理对象里面执行目标对象的方法)

    spring采用动态代理在运行期织入 ;  AspectJ采用编译期织入和类装载器织入

  ⑦Proxy 代理

    一个类被AOP织入增强后,产生一个代理类

  ⑧Aspect  切面

    切入点和通知的结合

 

2. spring中的aop

  spring内部会根据配置或注解创建代理工厂,我们只需要做好配置即可。

  例:增强代码为日志输出

  2.1 xml配置

  被增强接口及其实现类:

package com.xt.service;

public interface IAccountService {

    void saveAccount();

    void updateAccount(int i);

    int deleteAccount();
}

 

package com.xt.service.impl;

import com.xt.service.IAccountService;

public class AccountServiceImpl implements IAccountService {
    @Override
    public void saveAccount() {
        System.out.println("保存");
    }

    @Override
    public void updateAccount(int i) {
        System.out.println("更新");
    }

    @Override
    public int deleteAccount() {
        System.out.println("删除");
        return 10;
    }
}

 

增强类/通知类:一个打印日志的类

package com.xt.utils;

public class Logger {
    public void printLog(){
        System.out.println("---------输出日志-----------");
    }

    public void printLog2(){
        System.out.println("--------又一个日志输出---------");
    }
}

 

bean的xml也要加入aop命名空间标志:

<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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
        
</beans>

 

(1)准备一个被增强类,这里是一个普通的类

<bean id="accountService" class="com.xt.service.impl.AccountServiceImpl"></bean>

(2)将通知类/增强代码用bean配置

<bean id="logger" class="com.xt.utils.Logger"></bean>

 

(3)声明aop配置 <aop:config>

  ①配置切入点表达式 <aop:pointcut>

  对哪些类的哪些方法进行增强

    id:切入点表达式唯一标识

    expression:定义切入点表达式  execution(访问修饰符 返回值 包名.类名.方法名(参数列表))

  ②配置切面 <aop:aspect>

    id:切面唯一标识

    ref:引用配置好的通知类/增强的bean的id

  在<aop:aspect>内部配置通知类型

    <aop:before> 前置通知

    <aop:after-returning>  后置通知,和异常通知只能有一个执行

    <aop:after-throwing>  异常通知

    <aop:after>    最终通知

    <aop:around>  环绕通知

    属性:这几个属性就建立了普通类和通知类之间的关系

      method:指定通知类中的方法名称

      pointcut-ref:指定切入点表达式的引用,即<aop:pointcut>的id

      pointcut:不引用切入点表达式,直接定义切入点表达式

 

  则上面例子的bean写为:

<aop:config>
    <aop:pointcut id="pc1" expression="execution(public void com.xt.service.impl.AccountServiceImpl.updateAccount(int))" />
    <aop:aspect id="logAdvice" ref="logger">
        <aop:before method="printLog" pointcut="execution(public void com.xt.service.impl.AccountServiceImpl.saveAccount())">
        </aop:before>
        
        <aop:before method="printLog2" pointcut-ref="pc1">
        </aop:before>
    </aop:aspect>
</aop:config>

  调用测试:

ApplicationContext ac = new ClassPathXmlApplicationContext("beanaop.xml");
IAccountService accountService = ac.getBean("accountService", IAccountService.class);
accountService.updateAccount(10);
accountService.saveAccount();
System.out.println(accountService.getClass()); //class com.sun.proxy.$Proxy3   基于接口的代理

  

  两个注意的地方:

    ①如果被增强类没有接口,则spring框架自动使用基于 CGLIB的动态代理来增强代码

System.out.println(accountService.getClass()); //class com.xt.service.impl.AccountServiceImpl$$EnhancerBySpringCGLIB$$72e1fb9e

    ②配置切入点表达式的时候,原方法参数为int,如果切入点表达式里面写 Integer,则不会代理成功

 

切入点表达式:修饰符 返回值 包名.类名.方法名(参数)

  修饰符可省略

  返回值:可用 * 表示任意返回值

  包名: 可用 * 表示任意包,有多级包时要写多个 *

      可用  .. 表示当前包及其子包

  类名: 可用 * 表示任意类

  方法名: 可用 * 表示任意方法

  参数列表: 可用 * 表示任意数据类型,但必须有参数

        可用 .. 表示有无参数都可以,参数可为任意类型 

 

  2.2 注解配置

  其实xml配置里面重要的就两个:①aop:aspect关联切面类  ②aop:before等指定切入点表达式(切面类具体的方法(method属性)和被增强类方法(pointcut)的关联)

  注解:在切面类上加 @Aspect  ; 在切面类的方法上加注解 @Before("execution(xxx)")

 

  注解API:

    @Aspect 指定一个类为通知类

    @Pointcut("execution(xxx)") 指定切入点表达式,然后可用如下的注解引用

    @Before("pointcut()")  前置通知

    @After("pointcut()")     后置通知,最终通知,始终会执行

    @AfterReturning("pointcut()")     目标方法后执行,异常不执行

    @AfterThrowing("pointcut()")  异常通知

    @Around("pointcut()")  环绕通知,环绕目标方法执行

  

 

标签:spring,切入点,aop,代理,pointcut,通知,public,表达式
来源: https://www.cnblogs.com/taoXiang/p/13053851.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有