Spring_aop

AOP

基本术语

切面:横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象
通知:切面必须要完成的工作
目标:被通知的对象
代理:向目标对象应用通知之后创建的对象
连接点:程序执行的某个特定位置
切点:AOP通过切点定位到特定的连接点

:切点和连接点不是一一对应关系,而是一个切点匹配多个连接点

SPring AOP基于注解的方式开发

步骤:基于注解的方式

1.额外导包

Spring-aop包,Spring-aspects包,springsource.org.aoplliance包,springsource.org.aspectj.weaver包       

2.配置XML

为了使Aspjectj注解起作用,自动为匹配的类生成代理对象
需要在xml文件中添加aop的命名空间
xmlns:aop="http://www.springframework.org/chema/aop"
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

3.编写切面类

把横切关注点的代码抽象到切面的类中
   i.切面首先是一个IOC中的bean,即加入@Component 注解
   ii.为类添加注解@Aspject表示这是一个切面类

3.1 @Order(数字)

定义切面类的优先级
数字越小,优先级越高

4.声明各种通知

为需要添加到代理对象中的方法 添加注解

**理解思路**:
try{
    //前置通知
    //返回通知
}
catch(Exception e)
{
    //异常通知
}
//后置通知

1.前置通知:@Before:代表作用在被代理的对象方法使用之前

  如果需要让被代理类的所有方法都被代理,将方法名换成 * 就可以了
*举例*: @Before("execution(public 方法类型 包名.类名.方法名(参数))")//也可以将"public 方法类型" 换成 * 代表任意修饰符和任意返回值         
       public void AspectMethod(JoinPoint joinPoint)
       {
          String methodName = joinPoint.getSignature().getName();
          List<Object> args = Arrays.asList(joinPoint.getArgs());
          System.out.println("方法名是"+methodName+"参数是"+args);
       }

2.后置通知:@After:代表作用在被代理的对象方法使用之后

无论过程中有没有发生异常,都会执行后置通知
因为可能会出现异常,所以在后置通知中不能访问目标方法执行的结果

3.返回通知:@AfterReturning

 可以访问到方法的返回值结果
*举例*:@AfterReturning(value = "execution(public 方法类型 包名.类名.方法名(参数))" , returning = "result(返回值名:自定义的)")
     public void afterReturning(JoinPoint joinPoint , Object result)
     {
         String methodName = joinPoint.getSignature().getName();
         System.out.println("方法名是"+methodName+"参数是"+args+"结果是"+result);
     }

4.异常通知:@AfterThrowing

 在目标方法出现异常时会执行的代码
   可以访问到异常对象,且可以自己指定在出现特定异常时在执行通知代码
*举例*:@AfterThrowing(value = "execution(public 方法类型 包名.类名.方法名(参数))" , throwing = "e(异常对象名:自定义的)")         
    public void afterThrowing(JoinPoint joinPoint , Exception e)
    {
         String methodName = joinPoint.getSignature().getName();
         System.out.println("方法名是"+methodName+"参数是"+args+"出现了异常"+e);
    }

5.环绕通知:@Around

 环绕通知需要携带ProceedingJoinPoint类型的参数
 环绕通知类似于动态代理的全过程:参数可以决定是否执行目标方法
 环绕通知必须有返回值,返回值即为目标方法的返回值
*举例*:@Around("execution(public 方法类型 包名.类名.方法名(参数))")
        public object aroundMethod(ProceedingJoinPoint pjd)
        {
           object result = null;
           String methodName = pjd.getSignature().getName();
           try{
                //前置通知
                System.out.println("前置通知"+Arrays.asList(pjd.getArgs()));
                //执行目标方法
                result = pjd.proceed();
                //返回通知
                System.out.println("返回通知"+result);
            }
           catch(Throwable e)
           {
                //异常通知
                System.out.println("异常"+e);
           }
           //后置通知
           System.out.println("后置通知");
        }

切点表达式的重用

execution(public 方法类型 包名.类名.方法名(参数))
为了代码的复用性提高,避免修改的时候太复杂
使用 @Pointcut 
自定义一个方法专门用来表示,方法内部什么都不需要写
举例:@Pointcut("execution(public 方法类型 包名.类名.方法名(参数))")
      public void JoinPointExpression(){}
     (使用样例) @Before("类名.JoinPointExpression()")

Spring AOP基于xml配置开发

步骤:

1. <!-- 配置bean -->
  <bean id = "bean接口类名" class = "包名.bean对象名"></bean>
  ......

2.<!-- 配置切面的bean -->
  <bean id = "切面类名"  class = "包.类.切面对象"></bean>
  ......

3.<!-- 配置AOP -->
  <aop:config>
      <!--配置切面表达式-->
      <aop:pointcut expression = "execution(public 方法类型 包名.类名.方法名(参数))" id="pointcut(自己指定的)"/>

      <!--配置切面及通知-->
      <aop:aspect ref = "切面类名" order = "数字">
          <aop:before(前置通知) method = "前置方法名" pointcut-ref = "pointcut" />
          <aop:after(后置通知) method = "后置方法名" pointcut-ref = "pointcut" />
          <aop:after-throwing(异常通知) method = "异常方法名" pointcut-ref = "pointcut" throwing = "e" />
          <aop:after-returning(返回通知) method = "返回方法名" pointcut-ref = "pointcut" returning = “result” />
      </aop:aspect>

            <!--环绕通知-->
       <aop:aspect ref = "切面类名" order = "数字">
          <aop:around method = "环绕方法名" pointcut-ref = "pointcut" />
      </aop:aspect>
  </aop:config>