zoukankan      html  css  js  c++  java
  • Spring_9_AspectJ-Advice定义及实例

    =Advice定义及实例===================================================
    Before advice


    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;

    @Component
    @Aspect
    public class MoocAspect {
     
     @Before("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..))")//在执行com.imooc.aop.aspectj包下以Biz结尾的类所有方法时匹配Advice
     public void before() {
      System.out.println("Before.");
     } 
    }

    =============================================
    After Returning advice

    @Aspect
    public class AfterReturningExample {
     @AfterReturning("com.xyz.myapp.SystemArchitecture.dateAccessOperation()")
     public void doAccessCheck() {
     //...
     }
    }
    ·有时又需要在通知体内得到返回的实际值,可以使用@AfterReturning绑定返回值的形式
    @Aspect
    public class AfterReturningExample {
     @AfterReturning(
         pointcut="com.xyz.myapp.SystemArchitecture.dateAccessOperation()",
         returning="retVal")
     public void doAccessCheck(Object retVal) //不确定返回值类型,使用Object,确定时可使用相应类型
     {
     //...
     }
    }
    ====================================================
    After Throwing advice

    @Aspect
    public class AfterThrowingExample {
     @AfterThrowing("com.xyz.myapp.SystemArchitecture.dateAccessOperation()")
     public void doAccessCheck() {
     //...
     }
    }
    ·有时又需要在通知体内得到返回的实际值,可以使用@AfterThrowing绑定返回值的形式
    @Aspect
    public class AfterThrowingExample {
     @AfterThrowing(
         pointcut="com.xyz.myapp.SystemArchitecture.dateAccessOperation()",
         throwing="ex")
     public void doAccessCheck(DateAccessException ex) //不确定返回值类型,使用Object,确定时可使用相应类型
     {
     //...
     }
    }
    ====================================================
    After (finally) advice
    最终通知必须准备处理正常和异常两种返回情况,它通常用于释放资源
    像是java的try catch finally代码块的finally 通常用于释放资源
    @Aspect
    public class AfterFinallyExample {
     @After("com.xyz.myapp.SystemArchitecture.dateAccessOperation()")
     public void doReleaseLock() {
     //...
     }
    }
    ====================================================
    Around advice
    ·环绕通知使用@Around注解来生命,通知方法的第一个参数必ProceedingJoinPoint类型
    ·在通知内部调用ProceedingJoinPoint的proceed()方法导致执行真正的方法,传到一个Object[]对象,
    数组中的值将作为参数传递给方法 proceed[proʊˈsi:d]vi.进行;前进;尤指打断后)继续说 n收入获利
    @Aspect
    public class AroundExample {
     @Around("com.xyz.myapp.SystemArchitecture.dateAccessOperation()")
     public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Trowable {//pjp.proceed()可能会抛出异常处理方式1.throws 该exception2.catch该异常
     //start stopwatch
     Object retVal = pjp.proceed();//真正执行方法的步骤,不知道真正的方法是否有返回值,
     //所以用通用类型Object接收(void也是特殊类型的返回值)
     //stop  stopwatch
     }
    }
    ==Advicer扩展==================================================
    给advice传递参数
    方式1 用来获取相应的参数进行判断或记录
    @Before("com.xyz.myapp.SystemArchitecture.dateAccessOperation() && args(account,..)")//account与方法参数的名称一致
    public void validateAccount(Account account) {
     System.out.println("Before.");
    }
    方式2(与方式1等效)
    @Pointcut("com.xyz.myapp.SystemArchitecture.dateAccessOperation() && args(account,..)")//account与方法参数的名称一致
    public void accountDataAccessPoeration(Account account) {}

    @Before("accountDataAccessPoeration(account)")
    public void validateAccount(Account account) {
     System.out.println("Before.");
    }

    方式3:作用1 记录 2 判断方法用了哪些注解或者注解的值,根据注解的不同或注解value的不同,可以做一些前置的操作
    1)定义一个注解
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface Auditable { 
     AuditCode value();
    }
    2)使用该注解
    @Before("com.xyz.lib.Pointcuts.anyPublicMethod() && @annotation(auditable)")
    public void auditAuditable auditable){
     AuditCode code = auditable.value();
     //System.out.println("Before.");
    }

    ===Advice的参数及泛型=================================================
    ·Spring AOP可以处理泛型类的声明和使用方法的参数
    public interface Sample<T> {
     void sampleGenericMethod(T param);
     void sampleGenericCollectionMethod(Collection<T> param);
    }

    @Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
    public void beforeSampleMethod(MyType param) {
     //advice implementation
    }
    @Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)")
    public void beforeSampleGenericCollectionMethod(Collection<MyType> param) {
     //advice implementation
    }
    ===Advice参数名称=================================================
    通知和切入点注解有一个额外的"argNames"属性,它可以用来指定所注解的方法的参数名

    @Before(value = "com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditble)",
     argNames="bean,auditable")
    public void audit(Object bean,Auditable auditable){
     AuditCode code = auditable.value();
     //...use code and bean
    }
    如果第一个参数是JoinPoint,ProceedingJoinPoint,JoinPoint.StaticPart,那么可以忽略它
    @Before(value = "com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditble)",
     argNames="bean,auditable")
    public void audit(JoinPoint jp,Object bean,Auditable auditable){
     AuditCode code = auditable.value();
     //...use code and bean
    }
    ===Introductions=======================================================
    ·允许一个切面声明一个通知对象实现指定接口,并且提供了一个接口实现类来代表这些对象
    ·introduction使用@DeclareParents进行注解,这个注解用来定义匹配的类型拥有ige新的parent
    例如:给定一个接口UsageTracked,并且该接口拥有DefaultUsageTracked的实现,
    接下来的切面声明了所有service皆苦的实现都实现了UsageTracked接口

    @Aspect
    public class UsageTracking {
     @DeclareParents(value="com.xzy.myapp.service.*+",defaultImpl="DefaultUsageTracked.class")
     public static UsageTracked mixin;
     @Before("com.xyz.myapp.SystemArchitecture.bussinessService() && this(usageTracked)")
     public void recordUsage(UsageTracked usageTracked) {
      usageTracked.incrementUseCount();
     }
    }
    ====切面实例化模型===================================
    ·这是一个高级主题
    ·"perthis"切面通过指定@Aspect注解perthis子句实现
    ·每个独立的service对象执行时都会创建一个切面实例
    ·service对象的每个方法在第一次执行的时候创捷切面实例,切面在service对象失效的同事失效

    @Aspect("perthis(com.xyz.myapp.SystemArchitecture.businessService())")
    public class MyAspect {

     private int someState;

     @Before("com.xyz.myapp.SystemArchitecture.bussinessService()")
     public void recordServiceUsage () {
      //...
     }
    }


    ====================================================
    ====================================================

    定义注解

     1 package com.imooc.aop.aspectj;
     2 import java.lang.annotation.ElementType;
     3 import java.lang.annotation.Retention;
     4 import java.lang.annotation.RetentionPolicy;
     5 import java.lang.annotation.Target;
     6 @Retention(RetentionPolicy.RUNTIME)
     7 @Target(ElementType.METHOD)
     8 public @interface MoocMethod {
     9  
    10  String value();
    11 }


    ====================================================
    例子

     1 package com.imooc.aop.aspectj;
     2 
     3 import org.aspectj.lang.ProceedingJoinPoint;
     4 import org.aspectj.lang.annotation.After;
     5 import org.aspectj.lang.annotation.AfterReturning;
     6 import org.aspectj.lang.annotation.AfterThrowing;
     7 import org.aspectj.lang.annotation.Around;
     8 import org.aspectj.lang.annotation.Aspect;
     9 import org.aspectj.lang.annotation.Before;
    10 import org.aspectj.lang.annotation.Pointcut;
    11 import org.springframework.stereotype.Component;
    12 
    13 @Component
    14 @Aspect
    15 public class MoocAspect {
    16     
    17     //a    @Pointcut("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..)) && @annotation(moocMethod)")
    18     //a    public void pointcut(MoocMethod moocMethod) {}
    19     @Pointcut("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..))")
    20     public void pointcut() {}
    21     
    22     @Pointcut("within(com.imooc.aop.aspectj.biz.*)")
    23     public void bizPointcut() {}
    24     
    25     @Before("pointcut()")// pointcut()方法上面声明了一种类型的pointcut,此处可以使用代替@Before("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..))")表达式
    26     public void before() {
    27         System.out.println("Before.");
    28     }
    29     
    30     @Before("pointcut() && args(arg)")
    31     public void beforeWithParam(String arg) {
    32         System.out.println("BeforeWithParam." + arg);
    33     }
    34     
    35     @Before("pointcut() && @annotation(moocMethod)")
    36     //a    @Before("pointcut(moocMethod)")
    37     public void beforeWithAnnotaion(MoocMethod moocMethod) {
    38         System.out.println("BeforeWithAnnotation." + moocMethod.value());
    39     }
    40     
    41     @AfterReturning(pointcut="bizPointcut()", returning="returnValue")
    42     public void afterReturning(Object returnValue) {
    43         System.out.println("AfterReturning : " + returnValue);
    44     }
    45     
    46     @AfterThrowing(pointcut="pointcut()", throwing="e")
    47     public void afterThrowing(RuntimeException e) {
    48         //e.printStackTrace();//调试时,可以打印出堆栈信息
    49         System.out.println("AfterThrowing : " + e.getMessage());
    50     }
    51     
    52     @After("pointcut()")
    53     public void after() {
    54         System.out.println("After.");
    55     }
    56 
    57     @Around("pointcut()")
    58     public Object around(ProceedingJoinPoint pjp) throws Throwable {
    59         System.out.println("Around 1.");
    60         Object obj = pjp.proceed();
    61         System.out.println("Around 2.");
    62         System.out.println("Around : " + obj);
    63         return obj;
    64     }
    65     
    66 }
     


    ==xml

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xmlns:context="http://www.springframework.org/schema/context"
     5     xmlns:aop="http://www.springframework.org/schema/aop"
     6     xsi:schemaLocation="http://www.springframework.org/schema/beans 
     7         http://www.springframework.org/schema/beans/spring-beans.xsd  
     8         http://www.springframework.org/schema/context
     9         http://www.springframework.org/schema/context/spring-context.xsd
    10         http://www.springframework.org/schema/aop 
    11         http://www.springframework.org/schema/aop/spring-aop.xsd">
    12         
    13         <context:component-scan base-package="com.imooc.aop.aspectj"/>
    14       <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    15  </beans>

    ==biz

     1 package com.imooc.aop.aspectj.biz;
     2 import org.springframework.stereotype.Service;
     3 import com.imooc.aop.aspectj.MoocMethod;
     4 @Service
     5 public class MoocBiz {
     6  
     7  @MoocMethod("MoocBiz save with MoocMethod.")//给注解赋值
     8  public String save(String arg) {
     9   System.out.println("MoocBiz save : " + arg);
    10 //  throw new RuntimeException(" Save failed!");
    11   return " Save success!";
    12  }
    13 }


    ==Test

     1 package com.imooc.test.aop.aspectj;
     2 import org.junit.Test;
     3 import org.junit.runner.RunWith;
     4 import org.junit.runners.BlockJUnit4ClassRunner;
     5 import com.imooc.aop.aspectj.biz.MoocBiz;
     6 import com.imooc.test.base.UnitTestBase;
     7 @RunWith(BlockJUnit4ClassRunner.class)
     8 public class TestAspectJ extends UnitTestBase {
     9  
    10  public TestAspectJ() {
    11   super("classpath:spring-aop-aspectj.xml");
    12  }
    13  
    14  @Test
    15  public void test() {
    16   MoocBiz biz = getBean("moocBiz");
    17   biz.save("This is test.");
    18  }
    19  
    20 }

  • 相关阅读:
    随笔2
    随笔
    关于updateElement接口
    随笔1
    本地访问正常,服务器访问乱码 记录
    Redis (error) NOAUTH Authentication required.解决方法
    tomcat启动很慢 停留在 At least one JAR was scanned for TLDs yet contained no TLDs.
    微信公众号消息回复
    微信公众号 报token验证失败
    idea中web.xml报错 Servlet should have a mapping
  • 原文地址:https://www.cnblogs.com/charles999/p/6672443.html
Copyright © 2011-2022 走看看