前置通知和后置通知

87 阅读4分钟

前置说明

    AspectJ 的通知类型

             AspectJ 中常用的通知有四种类型:

            (1)前置通知@Before

            (2)后置通知@AfterReturning

            (3)环绕通知@Around

            (4)最终通知@After

            (5)定义切入点@Pointcut(了解)

格式

    execution(访问权限 方法返回值 方法声明(参数) 异常类型)

    切入点表达式要匹配的对象就是目标方法的方法名。所以,execution 表达式中明显就是方法的签名。注意,表达式中黑色文字表示可省略部分,各部分间用空格分开。在其中可以使用以下符号:

举例说明

execution(public * *(..))

指定切入点为:任意公共方法。

execution(* set*(..))

指定切入点为:任何一个以“set”开始的方法。

execution(* com.xyz.service.impl..(..))

指定切入点为:定义在 service 包里的任意类的任意方法。

execution(* com.xyz.service...(..)) * com.xyz.service.power2.aa..(..)

指定切入点为:定义在 service 包或者子包里的任意类的任意方法。“..”出现在类名中时,后面必须跟“*”,表示包、子包下的所有类。

execution(* ..service..(..)) a.b.service..(..) a.b.c.d.service..*(..)

指定所有包下的 serivce 子包下所有类(接口)中所有方法为切入点

execution(* .service..*(..))

指定只有一级包下的 serivce 子包下所有类(接口)中所有方法为切入点

execution(* .ISomeService.(..))

指定只有一级包下的 ISomeSerivce 接口中所有方法为切入点

execution(* ..ISomeService.(..))

指定所有包下的 ISomeSerivce 接口中所有方法为切入点

execution(* com.xyz.service.IAccountService.*(..))

指定切入点为:IAccountService 接口中的任意方法。

execution(* com.xyz.service.IAccountService+.*(..))

指定切入点为:IAccountService 若为接口,则为接口中的任意方法及其所有实现类中的任意方法;若为类,则为该类及其子类中的任意方法。

execution(* joke(String,int)))

指定切入点为:所有的 joke(String,int)方法,且 joke()方法的第一个参数是 String,第二个参数是 int。如果方法中的参数类型是 java.lang 包下的类,可以直接使用类名,否则必须使用全限定类名,如 joke( java.util.List, int)。

execution(* joke(String,*)))

指定切入点为:所有的 joke()方法,该方法第一个参数为 String,第二个参数可以是任意类型,如joke(String s1,String s2)和joke(String s1,double d2)都是,但joke(String s1,double d2,String

s3)不是。

execution(* joke(String,..)))

指定切入点为:所有的 joke()方法,该方法第一个参数为 String,后面可以有任意个参数且参数类型不限,如 joke(String s1)、joke(String s1,String s2)和 joke(String s1,double d2,String s3) 都是。

execution(* joke(Object))

指定切入点为:所有的 joke()方法,方法拥有一个参数,且参数是 Object 类型。joke(Object ob)是,但,joke(String s)与 joke(User u)均不是。

execution(* joke(Object+)))

指定切入点为:所有的 joke()方法,方法拥有一个参数,且参数是 Object 类型或该类的子类。不仅 joke(Object ob)是,joke(String s)和 joke(User u)也是。

第一步

    导依赖

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.3.18</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
  <version>5.3.18</version>
</dependency>

第二步



创建接口、接口实现类、代理的Aspect类

        接口

public interface SomeService {
    String doSome(String name,int age);
 
}
        实现类

/**
 * 业务实现类
 */
public class SomeServiceImpl implements SomeService {
    @Override
    public String doSome(String name, int age) {
        System.out.println("dosome的业务功能实现..............");
        return "asdf";
    }
}
        代理类

/**
 * 此类为切面类,包含各种切面方法
 */
@Aspect     //交给AspectJ的框架去识别切面类
public class MyAspect {
    /**
     * 所有的切面的功能都是由切面方法来实现的
     * 可以将各种切面都在此类中进行开发
     *
     * 前置通知的切面方法的规范
     * 1)访问权限是public
     * 2)方法的返回值是void
     * 3)方法名称自定义
     * 4)方法没有参数,如果有也只能是JoinPoint类型
     * 5)必须使用@Before注解来声明切入的时机是前切功能和切入点
     *      参数:value  指定切入点表达式
     *
     *      业务方法
     *      public String doSome(String name,int age)
     */
    @Before(value="execution(public  String com.wzx.s01.impl.SomeServiceImpl.doSome(String,int))")
    public void myBefore() {
        System.out.println("切面方法中的前置通知功能的实现.................");
    }
 
}

第三步

     写配置

                创建applcationContext.xml

<?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 https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--创建业务对象-->
    <bean id="someService" class="com.wzx.s01.impl.SomeServiceImpl"></bean>
    <!--创建切面对象-->
    <bean id="myaspect" class="com.wzx.s01.MyAspect"></bean>
    <!--绑定-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
   第四步

```js
     测试类

  @Test
    public void test(){
                 //步骤
                 //1.启动容器
                 //2.取出对象
                 //3.掉出属性
       ApplicationContext ac=new ClassPathXmlApplicationContext("s01/applicationContext.xml");
        SomeService someService= (SomeService) ac.getBean("someService");
        String password = someService.doSome("a", 5);
        System.out.println(password);
 
 
    }
切换JDK动态dialing和CGLib动态代理

        再绑定后面加入proxy-target-class="true"就编程CGLib动态代理

  <!--创建业务对象-->
    <bean id="someService" class="com.wzx.s01.impl.SomeServiceImpl"></bean>
    <!--创建切面对象-->
    <bean id="myaspect" class="com.wzx.s01.MyAspect"></bean>
    <!--绑定-->
    <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
   
   
前置可以绑定数据

```js
 @Before(value="execution(public  String com.wzx.s01.impl.SomeServiceImpl.doSome(String,int))")
    public void myBefore(JoinPoint jp) {
        System.out.println("切面方法中的前置通知功能的实现.................");
        System.out.println("目标方法的签名:"+jp.getSignature());
        System.out.println("目标方法的参数:"+ Arrays.toString(jp.getArgs()));