Spring Aop

一. Aop

Aspect Oriented Programming:面向切面编程 ,通过预编译或和运行期动态代理实现程序的统一维护的一种技术。如果多个类中出现重复的代码,可以考虑定义一个共同的抽象类,将这些共同的代码提取到抽象类中。AOP就是希望将这些分散在各个业务逻辑代码中的相同代码,通过横向切割的方式抽取到一个独立的模块中,让业务逻辑类依然保存最初的单纯。

主要的功能是:日志记录,性能统计,安全控制,事务处理和异常处理等等

AOP实现方式

.预编译 -AspectJ

.运行期动态代理(JDK动态代理、CGLib动态代理)

-SpringAOP 、JbossAOP

AOP的概念

1.切面(Aspect):一个关注点的模块化,这个模块可以横切多个对象。切面是通知和切点的结合,它既包括了横切逻辑的定义,也包括了连接点的定义

2.连接点(Joinpoint):程序执行过程的某个特定的点,如某个方法调用前,调用后,方法抛出异常后,这些代码中的特定点称为连接点。简单来说,就是在哪加入你的逻辑增强。连接点表示具体要拦截的方法,下面切点是定义一个范围,而连接点是具体到某个方法

3.切入点(Pointcut):匹配连接点的断言,每个程序的连接点有多个,如何定位到某个具体的连接点,就需要通过切点来定位。通常我们采用表达式的方式来设置,所以关键词是范围

4.通知(Advice):AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。

就是切面的某个特定的连接点上执行的动作,切面中的某个方法。

5.引入(Introduction):在不修改类代码的前提下,为类添加新的方法和属性

6.目标对象(Taret Objectt):被一个或多个切面所通知的对象,需要被加强的业务对象

7.织入(Weaving):将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。织入就是将增强添加到对目标类具体连接点上的过程。
织入是一个形象的说法,具体来说,就是生成代理对象并将切面内容融入到业务流程的过程。

织入分为:编译时织入,类加载时织入、执行时织入

8.AOP代理(AOP Proxy)一个类被AOP织入增强后,就产生了一个代理类。是AOP框架创建的对象,用来实现切面契约(aspect contract)(包括通知方式执行等功能)

二 。切面配置

Spring 中所有的切面和通知器都必须放在一个<aop:config>中(可以配置多个<aop:config>元素)每个<aop:config>中可以包含 Pointcut 、Advisors和aspect。当必须按顺序声明。

 切入点配置

    当<aop:pointcut>元素作为<aop:config>元素的子元素定义时,表示该切入点是全局切入点,它可被多个切面所共享;当<aop:pointcut>元素作为<aop:aspect>元素的子元素时,表示该切入点只对当前切面有效。
         定义<aop:pointcut>元素时,通常会指定id和expression两个属性。

属性名称解释
id用于指定切入点的唯一标识名称。
expression用于指定切入点关联的切入点表达式。

 

 

 

 通知配置
        使用<aop:aspect>的子元素可以配置5种常用通知,这5个子元素不支持使用子元素,但在使用时可以指定一些属性,其常用属性及其描述如下:
pointcut:    该属性用于指定一个切入点表达式,Spring将在匹配该表达式的连接点时织入该通知。
pointcut-ref  :  该属性指定一个已经存在的切入点名称,通常pointcut和pointcut-ref两个属性只需要使用其中之一。
method:    该属性指定一个方法名,指定将切面Bean中的该方法转换为增强处理。
throwing :   该属性只对<after-throwing>元素有效,用于指定一个形参名,异常通知方法可以通过该形参访问目标方法所抛出的异常。
returning:    该属性只对<after-returning>元素有效,用于指定一个形参名,后置通知方法可以通过该形参访问目标方法的返回值。

例子:创建用户管理接口UserDao接口以及实现类UserDaoImpl类

package com.example.aspectjxml;

public interface UserDao {
 public void addUser();
 public void delUser();
}
package com.example.aspectjxml;

public class UserDaoImpl implements UserDao{

 @Override
 public void addUser() {
  // TODO Auto-generated method stub
  System.out.println("添加用户");
 }
 
 @Override
 public void delUser() {
  // TODO Auto-generated method stub
  System.out.println("删除用户");
 }
 
}

 创建切面类MyAspect类。

package com.example.aspectjxml;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class MyAspect {
 //前置通知
 public void myBefore(JoinPoint joinPoint){
  System.out.println("前置通知:"+joinPoint);
  System.out.println("被植入增强处理的目标方法:"+joinPoint.getSignature().getName());
 }
 //后置通知
 public void myAfterReturrning(JoinPoint joinPoint){
  System.out.println("后置通知:"+joinPoint);
  System.out.println("被植入增强处理的目标方法:"+joinPoint.getSignature().getName());
 }
 /*
  * 环绕通知
  * proceedingJoinPoint是JoinPoint子接口,表示可以执行目标方法
  * 1.必须是Object类型的返回值
  * 2.必须接收一个参数,类型为ProceedingJoinPoint
  * 3.必须throws Throwable
  */
 public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
  System.out.println("环绕前通知");
  //执行当前目标方法
  Object obj = proceedingJoinPoint.proceed();
  System.out.println("环绕后通知");
  return obj;
 }
 //异常通知
 public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
  System.out.println("异常通知:"+e.getMessage());
 }
 //最终通知
 public void myAfter(){
  System.out.println("最终通知");
 }
}
<?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"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
 <!-- 目标类 -->
 <bean id="userDao" class="com.example.aspectjxml.UserDaoImpl"></bean>
 <!-- 切面 -->
 <bean id="myAspect" class="com.example.aspectjxml.MyAspect"></bean>
 <aop:config>
  <!-- 配置切面 -->
  <aop:aspect ref="myAspect">
   <!-- 配置切入点 -->
   <aop:pointcut expression="execution(* com.example.aspectjxml.*.*(..))" id="myPointCut"/>
   <!-- 前置通知 -->
   <aop:before method="myBefore" pointcut-ref="myPointCut"/>
   <!-- 后置通知      returning属性:用于设置后置通知的第二个参数的名称,类型是Object -->
   <aop:after-returning method="myAfterReturrning" pointcut-ref="myPointCut" returning="returnVal"/>
   <!-- 环绕通知 -->
   <aop:around method="myAround" pointcut-ref="myPointCut"/>
   <!-- 异常通知:如果没有异常,将不会执行增强
        throwing属性:用于设置通知第二个参数的的名称、类型-->
   <aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/>
   <!-- 最终通知 -->
   <aop:after method="myAfter" pointcut-ref="myPointCut"/>
  </aop:aspect>
 </aop:config>
</beans>

环绕通知,目标方法参数传入环绕通知方法中

注意:如果在同一个连接点有多个通知需要执行,那么在同一切面中,目标方法之前的前置通知和环绕通知的执行顺序是未知的,目标方法之后的后置通知和环绕通知的执行顺序是未知的

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值