spring_03_AOP配置文件和注解开发

spring_03_AOP

简介
  • AOP(Aspect Oriented Programing)面向切面编程,一种编程范式,属于软工范畴,指导开发者如何组织程序结构

  • AOP弥补了OOP的不足,基于OOP基础之上进行横向开发

    • OOP规定程序开发以类为主体模型,一切围绕对象进行,完成某个任务先构建模型
    • AOP程序开发主要关注基于OOP开发中的共性功能,一切围绕共性功能进行,完成某个任务先构建可能遇到的所有共性功能(当所有功能都开发出来也就没有共性与非共性之分)
  • 目标:将软件开发由手工制作走向半自动化/全自动化阶段,实现“插拔式组件体系结构”搭建

  • 优势

    • 提高代码的可重用性
    • 业务代码编码更简洁
    • 业务代码维护更高效
    • 业务功能扩展更便捷
AOP相关概念
  • Joinpoint(连接点):就是方法
  • Pointcut(切入点):就是挖掉共性功能的方法
  • Advice(通知):就是共性功能,最终以一个方法的形式呈现
  • Aspect(切面):就是共性功能与挖的位置的对应关系
  • Target(目标对象):就是挖掉功能的方法对应的类产生的对象,这种对象是无法直接完成最终工作的
  • Weaving(织入):就是将挖掉的功能回填的动态过程
  • Proxy(代理):目标对象无法直接完成工作,需要对其进行功能回填,通过创建原始对象的代理对象实现
  • Introduction(引入/引介) :就是对原始对象无中生有的添加成员变量或成员方法
AOP配置
  • aop:config标签

    作用:设置AOP

  • aop:aspect标签

    作用:设置具体的AOP通知对应的切入点

    ref属性:通知所在的bean的id

  • aop:pointcut标签

    作用:设置切入点

    id属性:识别切入点的名称

    expression属性:切入点表达式

  • 切入点表达式,通配符

    切入点描述的是某个方法

    • 语法

      关键字访问修饰符 返回值 包名.类名.方法名参数异常名

      1 关键字:描述表达式的匹配模式(参看关键字列表)

      2 访问修饰符:方法的访问控制权限修饰符

      3类名:方法所在的类(此处可以配置接口名称)

      4异常:方法定义中指定抛出的异常

    • 通配符

      1 * :单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现

    execution(public * com.it.*.UserService.find*(*))
    

    匹配com.it包下的任意包中的UserService类或接口中所有find开头的带有一个参数的方法

    ​ 2 … :多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写

    execution(public User com..UserService.findById(..))
    

    ​ 匹配com包下的任意包中的UserService类或接口中所有名称为findById的方法

    ​ 3 +:专用于匹配子类类型

    execution(* *..*Service+.*(..))
    
    • 逻辑运算符

      && :连接两个切入点表达式,表示两个切入点表达式同时成立的匹配

      || :连接两个切入点表达式,表示两个切入点表达式成立任意一个的匹配

      ! :连接单个切入点表达式,表示该切入点表达式不成立的匹配

切入点的三种配置方式
<aop:config>
	<!--配置公共切入点--> 
    <aop:pointcut id="pt1" expression="execution(* *(..))"/>
	<aop:aspect ref="myAdvice">
	<!--配置局部切入点--> 
        <aop:pointcut id="pt2" expression="execution(* *(..))"/>
	<!--引用公共切入点--> 
        <aop:before method="logAdvice" pointcut-ref="pt1"/>
	<!--引用局部切入点--> 
        <aop:before method="logAdvice" pointcut-ref="pt2"/>
	<!--直接配置切入点--> 
        <aop:before method="logAdvice" pointcut="execution(* *(..))"/>
	</aop:aspect>
</aop:config>
五种通知类型

当同一个切入点配置了多个通知时,通知会存在运行的先后顺序,该顺序以通知配置的顺序为准

  • 前置通知:原始方法执行前执行,如果通知中抛出异常,阻止原始方法运行

    aop:before标签

    • method属性::在通知类中设置当前通知类别对应的方法
    • pointcut属性 :设置当前通知对应的切入点表达式,与pointcut-ref属性冲突
    • pointcut-ref 属性:设置当前通知对应的切入点id,与pointcut属性冲突

    应用:数据校验

  • 后置通知:原始方法执行后执行,无论原始方法中是否出现异常,都将执行通知

    aop:after标签(属性同上)

    应用:现场清理

  • 返回后通知:原始方法正常执行完毕并返回结果后执行,如果原始方法中抛出异常,无法执行

    aop:after-returning标签(属性同上)

    应用:返回值相关数据处理

  • 抛出异常后通知:原始方法抛出异常后执行,如果原始方法没有抛出异常,无法执行

    aop:after-throwing标签(属性同上)

    应用:对原始方法中出现的异常信息进行处理

  • 环绕通知:在原始方法执行前后均有对应执行执行,还可以阻止原始方法的执行

    aop:around标签(属性同上)

    应用:十分强大,可以做任何事情

<!----------------五种通知类型----------------->    
<aop:config>  
    <aop:pointcut id="pt" expression="execution(* *..*(..))"/>        
    <aop:aspect ref="myAdvice">            
        <!--<aop:before method="before" pointcut-ref="pt"/>-->           
        <!--<aop:after method="after" pointcut-ref="pt"/>-->            
        <!--<aop:after-returning method="afterReturing" pointcut-ref="pt"/>--            
        <!--<aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>-->           
        <aop:around method="around" pointcut-ref="pt"/>       
    </aop:aspect>  
</aop:config>
通知中获取参数,返回值,异常对象
<!----------------通知获取原始方法参数信息----------------->
<aop:config>
    <aop:pointcut id="pt" expression="execution(* *..*(..))"/>
    <aop:aspect ref="myAdvice">
        <aop:before method="before" pointcut-ref="pt"/>
        <aop:around method="around" pointcut-ref="pt"/>
        <aop:after-returning method="afterReturing" pointcut-ref="pt"/>
        <aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>
        <aop:after method="after" pointcut-ref="pt"/>

        <aop:before                  
                method="before1"
                <!-- 控制方法中x,y的对应 -->    
                arg-names="y,x"
        		<!-- x,y与方法中的参数强绑定,参数一致-->
                pointcut="execution(* *..*(int,int)) &amp;&amp; args(x,y)"/>
    </aop:aspect>
</aop:config>
<!----------------通知获取原始方法返回值信息----------------->
<aop:config>
    <aop:pointcut id="pt" expression="execution(* *..*(..))"/>
    <aop:aspect ref="myAdvice">
        <!-- 对应通知类方法中的ret -->
        <aop:after-returning method="afterReturing" pointcut-ref="pt" returning="ret"/>
        <aop:around method="around" pointcut-ref="pt"/>
    </aop:aspect>
</aop:config>
 <!----------------通知获取原始方法异常信息----------------->
<aop:config>
    <aop:pointcut id="pt" expression="execution(* *..*(..))"/>
    <aop:aspect ref="myAdvice">
        <aop:around method="around" pointcut-ref="pt"/>
        <aop:after-throwing method="afterThrowing" pointcut-ref="pt" throwing="t"/>
    </aop:aspect>
</aop:config
public class AOPAdvice {
	//通过JoinPoint获取参数
    public void before(JoinPoint jp){
        Object[] args = jp.getArgs();
        System.out.println("before..."+args[0]);
    }

    //直接获取参数,需修改配置文件
    public void before1(int x,int y){
        System.out.println("before(int)..."+x+","+y);
    }

	
    public void after(JoinPoint jp){
        Object[] args = jp.getArgs();
        System.out.println("after..."+args[0]);
    }
	//获取返回值,ret对应配置文件中的ret
    public void afterReturing(Object ret){
        System.out.println("afterReturing..."+ret);
    }
	//获取异常对象
    public void afterThrowing(Throwable t){
        System.out.println("afterThrowing..."+t.getMessage());
    }
	//环绕通知获取返回值
    public Object around(ProceedingJoinPoint pjp) {
        System.out.println("around before...");
        Object ret = null;
        try {
            //对原始方法的调用
            ret = pjp.proceed();
        } catch (Throwable throwable) {
            System.out.println("around...exception...."+throwable.getMessage());
        }
        System.out.println("around after..."+ret);
        return ret;
    }
注解开发

AOP注解

  • 类注解@Aspect:设置当前类为切面类
  • 方法注解@Pointcut:使用当前方法名作为切入点引用名称
  • 方法注解@Before:标注当前方法作为前置通知
  • 方法注解@After:标注当前方法作为后置通知
  • 方法注解@AfterReturning:标注当前方法作为返回后通知
  • 方法注解@AfterThrowing:标注当前方法作为异常后通知
  • 方法注解@Arround:标注当前方法作为环绕通知
<!-- 开启spring注解驱动 -->
<context:component-scan base-package="com"/>
<!-- 开始AOP注解驱动支持 -->
<aop:aspectj-autoproxy/>
@Component
@Aspect
public class AOPAdvice {

    @Pointcut("execution(* *..*(..))")
    public void pt1(){}

    @Before("AOPPointcut.pt1()")
    public void before(){
       System.out.println("前置before...");
    }

    @After("AOPPointcut.pt1()")
    public void after(){
        System.out.println("后置after...");
    }

    @AfterReturning("AOPPointcut.pt1()")
    public void afterReturing(){
        System.out.println("返回后afterReturing...");
    }
   
    @AfterThrowing("AOPPointcut.pt1()")
    public void afterThrowing(){
        System.out.println("抛出异常后afterThrowing...");
    }

    @Around("AOPPointcut.pt1()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕前around before...");
        Object ret = pjp.proceed();
        System.out.println("环绕后around after...");
        return ret;
    }
    
}
注解驱动

Spring注解配置类@EnableAspectAutoProxy:设置当前类开启AOP注解驱动的支持,加载AOP注解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值