spring-使用aspectj实现aop

1.目的

使用aop:目的是给已经存在的一些类和方法,增加额外功能。前提是不改变原来的类的代码。

2.使用aspectj实现aop的基本步骤

2.1.新建maven项目

添加新的模块ch06-aop-aspectj

2.2.加入依赖

  • 1)spring依赖
	<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.14.RELEASE</version>
    </dependency>
  • 2)aspectj依赖
	<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
  • 3)junit单元测试
	<dependency>
     <groupId>junit</groupId>
     <artifactId>junit</artifactId>
     <version>4.11</version>
     <scope>test</scope>
   </dependency>

2.3.创建目标类:接口和他的实现类

要做的是给类中的方法增加功能

package com.putao.ba01;

public interface SomeSercice {
    void doSome(String name,Integer age);

    void doOther(String name,Integer age);
}
package com.putao.ba01;

//目标类
public class SomeSerciceImpl implements SomeSercice {
    @Override
    public void doSome(String name,Integer age) {
        //给doSome方法增加一个功能,在doSome()执行之前,输出方法的执行时间
        System.out.println("===目标方法doSome()===");
    }

    @Override
    public void doOther(String name,Integer age) {
        //给doSome方法增加一个功能,在doSome()执行之前,输出方法的执行时间
        System.out.println("===目标方法doSome()===");
    }
}

2.4.创建切面类:普通类

  • 1)在类的上面加入@Aspect
    @Aspect: 是aspectj框架中的注解
    作用:表示当前类是切面类。
    切面类:是用来给业务方法增加功能的类,在这个类中有切面的功能代码
    位置:在类定义的上面

  • 2)在类中定义方法,方法就是切面要执行的功能代码
    定义方法,方法是实现切面功能的。
    方法的定义要求:

    • 1.公共方法 public
    • 2.方法没有返回值
    • 3.方法名称自定义
    • 4.方法可以有参数,也可以没有参数。
    • 如果有参数,参数不是自定义的,有几个参数类型可以使用
  • 3)在方法的上面加入aspectj中的通知注解,例如@Before
    还需要指定切入点表达式execution()

package com.putao.ba01;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import java.util.Date;

@Aspect
public class MyAspect {
   /**
    * 定义方法,方法是实现切面功能的。
    * 方法的定义要求:
    * 1.公共方法 public
    * 2.方法没有返回值
    * 3.方法名称自定义
    * 4.方法可以有参数,也可以没有参数。
    *   如果有参数,参数不是自定义的,有几个参数类型可以使用
    */

   /**
    * @Before: 前置通知注解
    *    属性:value,是切入点表达式,表示切面的功能执行的位置
    *    位置:在方法的上面
    * 特点:
    * 1.在目标方法之前先执行的
    * 2.不会改变目标方法的执行结果
    * 3.不会影响目标方法的执行
    */
//    @Before(value = "execution(public void com.putao.ba01.SomeSerciceImpl.doSome(String,Integer))")
//    public void myBefore(){
//        //就是你切面要执行的功能代码
//        System.out.println("前置通知,切面功能:在目标方法之前输出执行时间:"+ new Date());
//    }


//    @Before(value = "execution(void com.putao.ba01.SomeSerciceImpl.doSome(String,Integer))")
//    public void myBefore(){
//        //就是你切面要执行的功能代码
//        System.out.println("1====前置通知,切面功能:在目标方法之前输出执行时间:"+ new Date());
//    }


//    @Before(value = "execution(void *..SomeSerciceImpl.doSome(String,Integer))")
//    public void myBefore(){
//        //就是你切面要执行的功能代码
//        System.out.println("2====前置通知,切面功能:在目标方法之前输出执行时间:"+ new Date());
//    }


//    @Before(value = "execution(* *..SomeSerciceImpl.do*(..))")
//    public void myBefore(){
//        //就是你切面要执行的功能代码
//        System.out.println("3====前置通知,切面功能:在目标方法之前输出执行时间:"+ new Date());
//    }

//    @Before(value = "execution(* do*(..))")
//    public void myBefore2(){
//        //就是你切面要执行的功能代码
//        System.out.println("4====前置通知,切面功能:在目标方法之前输出执行时间:"+ new Date());
//    }

//    @Before(value = "execution(* com.putao.ba01.*SerciceImpl.*(..))")
//    public void myBefore2(){
//        //就是你切面要执行的功能代码
//        System.out.println("2====前置通知,切面功能:在目标方法之前输出执行时间:"+ new Date());
//    }

   /**
    * 指定通知方法中的参数:JoinPoint
    * JoinPoint;业务方法,要加入切面功能的业务方法
    *  作用是:可以在通知方法中获取方法执行的信息,例如方法名称,方法的实参。
    *  如果你的切面功能中需要用到方法的信息,就加入JoinPoint。
    *  这个JoinPoint参数的值是由框架赋予,必须是第一个位置的参数
    */
   @Before(value = "execution(void *..SomeSerciceImpl.doSome(String,Integer))")
   public void myBefore(JoinPoint jp){
       //获取方法的完整定义
       System.out.println("方法的签名(定义)="+jp.getSignature());
       System.out.println("方法的名称="+jp.getSignature().getName());
       //获取方法的实参
       Object[] args = jp.getArgs();
       for (Object arg : args) {
           System.out.println("参数="+arg);
       }
       //就是你切面要执行的功能代码
       System.out.println("2====前置通知,切面功能:在目标方法之前输出执行时间:"+ new Date());
   }
}

2.5.创建spring的配置文件:声明对象,把对象交给容器统一管理。

声明对象你可以使用注解或者xml配置文件<bean>

  • 1)声明目标对象
  • 2)声明切面类对象
  • 3)声明aspectj框架中的自动代理生成器标签。
    自动代理生成器:用来完成代理对象的自动创建功能的。
<?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">

<!--    把对象交给spring容器,由spring容器统一创建,管理对象-->
<!--    声明目标对象-->
    <bean id="someService" class="com.putao.ba01.SomeSerciceImpl" />

<!--    声明切面对象-->
    <bean id="myAspect" class="com.putao.ba01.MyAspect" />

<!--    声明自动代理生成器:使用aspectj框架内部的功能,创建目标对象的代理对象
        创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象
        所有目标对象就是被修改后的代理对象

        aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象
-->
   <aop:aspectj-autoproxy />
</beans>

2.6.创建测试类,从spring容器中获取目标对象(实际上就是代理对象)

通过代理执行方法,实现aop的功能增强。

package com.putao;

import com.putao.ba01.SomeSercice;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest01 {

   @Test
   public void test01(){
       String config = "applicationContext.xml";
       ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
       //从容器中获取目标对象
       SomeSercice proxy = (SomeSercice) ctx.getBean("someService");
       //com.sun.proxy.$Proxy6:jdk动态代理
       //com.sun.proxy.$Proxy0
       System.out.println("proxy:"+proxy.getClass().getName());
       //通过代理对象执行方法,实现目标方法执行时,增强了功能
       proxy.doSome("lisi",20);
   }
}

3.前置通知

@Before: 前置通知注解

  • 属性:value,是切入点表达式,表示切面的功能执行的位置
  • 位置:在方法的上面
  • 特点:
    1.在目标方法之前先执行的
    2.不会改变目标方法的执行结果
    3.不会影响目标方法的执行

例子如2.使用aspectj实现aop的基本步骤中所示

4.后置通知

@AfterReturning: 后置通知

  • 属性:1.value 切入点表达式
    2.returning 自定义的变量,表示目标方法的返回值的。
    自定义变量名必须和通知方法的形参名一样。

  • 位置:在方法定义的上面

  • 特点:
    1.在目标方法之后执行的。
    2.能够获取到目标方法的返回值,可以根据这个返回值做不同的处理功能
    Object res = doOther();
    3.可以修改这个返回值

  • 后置通知的执行
    Object res = doOther();
    参数传值:传值,传引用
    myAfterReturning(res);
    System.out.println(“res=”+res)

  • 1) 目标类:接口和他的实现类

	String doOther(String name, Integer age);

    Student doOther2(String name,Integer age);
  @Override
    public String doOther(String name,Integer age) {
        System.out.println("===目标方法doOther()===");
        return "abcd";
    }

    @Override
    public Student doOther2(String name, Integer age) {
        Student student = new Student();
        student.setName(name);
        student.setAge(age);
        return student;
    }
package com.putao.ba02;

public class Student {

    private String name;
    private int age;

    public Student() {
        System.out.println("spring会调用类的无参数构造方法创建对象");
    }

    public void setEmail(String email){
        System.out.println("setEmail="+email);
    }

    /**
     * 需要有set方法,没有set方法是报错的
     * Bean property 'name' is not writable or has an invalid setter method
     *
     */

    public void setName(String name) {
        System.out.println("setName:"+name);
        this.name = name.toUpperCase();
    }

    public void setAge(int age) {
        System.out.println("setAge:"+age);
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

  • 2) 切面类:普通类
package com.putao.ba02;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import java.util.Date;

@Aspect
public class MyAspect {
   
    @AfterReturning(value = "execution(* *..SomeSerciceImpl.doOther(..))",
            returning = "res")
    public void myAfterReturning(JoinPoint jp,Object res){
        //Object res:是目标方法执行后的返回值,根据返回值做你的切面的功能处理
        System.out.println("后置通知:方法的定义"+jp.getSignature());
        System.out.println("后置通知:在目标方法之后执行的,获取的返回值是:"+res);
        if (res.equals("abcd")){
            //做一些功能
        }else {
            //做其他功能
        }
        //修改目标方法的返回值,看一下是否会影响 最后的方法调用结果
        if (res != null){
            res = "Hello Aspectj";
        }
    }

    @AfterReturning(value = "execution(* *..SomeSerciceImpl.doOther2(..))",
            returning = "res")
    public void myAfterReturning2(Object res){
        //Object res:是目标方法执行后的返回值,根据返回值做你的切面的功能处理
        System.out.println("后置通知:在目标方法之后执行的,获取的返回值是:"+res);

        //修改目标方法的返回值,看一下是否会影响最后的方法调用结果
        //如果修改了res的内容,属性值等,是不是会影响最后的调用结果呢
        if (res != null){
            res = "Hello Aspectj";
            System.out.println("res==="+res);
        }
    }
}
  • 3) 配置文件:声明对象,把对象交给容器统一管理
<?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">

<!--    把对象交给spring容器,由spring容器统一创建,管理对象-->
<!--    声明目标对象-->
    <bean id="someService" class="com.putao.ba02.SomeSerciceImpl" />

<!--    声明切面对象-->
    <bean id="myAspect" class="com.putao.ba02.MyAspect" />

<!--    声明自动代理生成器:使用aspectj框架内部的功能,创建目标对象的代理对象
        创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象
        所有目标对象就是被修改后的代理对象

        aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象
-->
  <aop:aspectj-autoproxy />
</beans>
  • 4)测试类
package com.putao;

import com.putao.ba02.SomeSercice;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest02 {

    @Test
    public void test01(){
        String config = "applicationContext.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象
        SomeSercice proxy = (SomeSercice) ctx.getBean("someService");
        //通过代理对象执行方法,实现目标方法执行时,增强了功能
        String str = proxy.doOther("zs", 28);
        System.out.println("str==="+str);
    }
}

5.环绕通知

@Around: 环绕通知
* 属性:value 切入点表达式
* 位置:在方法的上面
* 特点:
* 1.它是功能最强的通知
* 2.在目标方法的前和后都能增强功能。
* 3.控制目标方法是否被调用执行
* 4.修改原来的目标方法的执行结果。影响最后的调用结果
*
* 环绕通知,等同于jdk动态代理的InvocationHandler接口
*
* 参数:ProceedingJoinPoint 就等同于 Method
* 作用:执行目标方法的
* 返回值:就是目标方法的执行结果,可以被修改
*
* 环绕通知:经常做事物,在目标方法之前开启事务,执行目标方法,在目标方法之后提交事物

  • 1) 目标类:接口和他的实现类
String doFirst(String name,Integer age);
@Override
    public String doFirst(String name, Integer age) {
        System.out.println("===业务方法doFirst()===");
        return "doFirst";
    }
  • 2) 切面类:普通类
package com.putao.ba03;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import java.util.Date;
@Aspect
public class MyAspect {
   
    @Around(value = "execution(* *..SomeSerciceImpl.doFirst(..))")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {

        String name = "";
        //获取第一个参数值
        Object[] args = pjp.getArgs();
        if (args!=null && args.length>1){
            Object arg = args[0];
            name = (String)arg;
        }
        //实现环绕通知
        Object result = null;
        System.out.println("环绕通知:在目标方法之前,输出时间:"+ new Date());
        //1.目标方法调用
        if ("zhangsan".equals(name)){
            //符合条件,调用目标方法
            result = pjp.proceed();//method.invoke(); Object result = doFirst();
        }
        System.out.println("环绕通知:在目标方法之后,提交事物");
        //2.在目标方法的前或者后加入功能

        //修改目标方法的执行结果,影响方法最后的调用结果
        if (result!=null){
            result = "Hello AspectJ AOP";
        }

        //返回目标方法的执行结果
        return result;
    }
}
  • 3) 配置文件:声明对象,把对象交给容器统一管理
<?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">

<!--    把对象交给spring容器,由spring容器统一创建,管理对象-->
<!--    声明目标对象-->
    <bean id="someService" class="com.putao.ba03.SomeSerciceImpl" />

<!--    声明切面对象-->
    <bean id="myAspect" class="com.putao.ba03.MyAspect" />

<!--    声明自动代理生成器:使用aspectj框架内部的功能,创建目标对象的代理对象
        创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象
        所有目标对象就是被修改后的代理对象

        aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象
-->
 <aop:aspectj-autoproxy />
</beans>
  • 4)测试类
package com.putao;

import com.putao.ba03.SomeSercice;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest03 {

    @Test
    public void test01(){
        String config = "applicationContext.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象
        SomeSercice proxy = (SomeSercice) ctx.getBean("someService");
        //通过代理对象执行方法,实现目标方法执行时,增强了功能
        String str = proxy.doFirst("zhangsan", 20);//myAround
        //String str = proxy.myAround("zhangsan", 20);
        System.out.println("str==="+str);
    }
}

6.异常通知

@AfterThrowing: 异常通知
* 属性:1.value 切入点表达式
* 2.throwing 自定义的变量,表示目标方法抛出的异常对象。
* 变量名必须和方法的参数名一样
*特点:
* 1.在目标方法抛出异常时执行的
* 2.可以做异常的监控程序,监控目标方法执行时是不是有异常。
* 如果有异常,可以发送邮件,短信进行通知
*
* 执行就是:
* try{
* SomeSerciceImpl.doSecond(…)
* }catch(Exception e){
* myAfterThrowing(e)
* }

  • 1) 目标类:接口和他的实现类
void doSecond();
	@Override
    public void doSecond() {
        System.out.println("执行业务方法doSecond()"+(10/0));
    }
  • 2) 切面类:普通类
package com.putao.ba04;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import java.util.Date;

@Aspect
public class MyAspect {
    @AfterThrowing(value = "execution(* *..SomeSerciceImpl.doSecond(..))",
            throwing = "ex")
    public void myAfterThrowing(Exception ex) {
        System.out.println("异常通知:方法发生异常时,执行:"+ex.getMessage());
        //发送邮件,短信,通知开发人员
    }

}

  • 3) 配置文件:声明对象,把对象交给容器统一管理
<?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">

<!--    把对象交给spring容器,由spring容器统一创建,管理对象-->
<!--    声明目标对象-->
    <bean id="someService" class="com.putao.ba04.SomeSerciceImpl" />

<!--    声明切面对象-->
    <bean id="myAspect" class="com.putao.ba04.MyAspect" />

<!--    声明自动代理生成器:使用aspectj框架内部的功能,创建目标对象的代理对象
        创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象
        所有目标对象就是被修改后的代理对象

        aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象
-->
 <aop:aspectj-autoproxy />
</beans>
  • 4)测试类
package com.putao;

import com.putao.ba04.SomeSercice;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest04 {

    @Test
    public void test01(){
        String config = "applicationContext.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象
        SomeSercice proxy = (SomeSercice) ctx.getBean("someService");
        //通过代理对象执行方法,实现目标方法执行时,增强了功能
        proxy.doSecond();
    }
}

7.最终通知

最终通知方法的定义格式
* 1.public
* 2.没有返回值
* 3.方法名称自定义
* 4.方法没有参数,如果有就是JoinPoint
@After: 最终通知
* 属性:value 切入点表达式
* 位置:在方法的上面
* 特点:
* 1.总是在执行
* 2.在目标方法之后执行的
*
* try{
* SomeSerciceImpl.doThird(…)
* }catch(Exception e){
*
* }finally{
* myAfter()
* }

  • 1) 目标类:接口和他的实现类
void doThird();
@Override
    public void doThird() {
        System.out.println("执行业务方法doThird()"+(10/0));
    }
  • 2) 切面类:普通类
package com.putao.ba05;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class MyAspect {
    @After(value = "execution(* *..SomeSerciceImpl.doThird(..))")
    public void myAfter(){
        System.out.println("执行最终通知,总是会被执行的代码");
        //一般是做资源清除工作的。
    }

}

  • 3) 配置文件:声明对象,把对象交给容器统一管理
<?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">

<!--    把对象交给spring容器,由spring容器统一创建,管理对象-->
<!--    声明目标对象-->
    <bean id="someService" class="com.putao.ba05.SomeSerciceImpl" />

<!--    声明切面对象-->
    <bean id="myAspect" class="com.putao.ba05.MyAspect" />

<!--    声明自动代理生成器:使用aspectj框架内部的功能,创建目标对象的代理对象
        创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象
        所有目标对象就是被修改后的代理对象

        aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象
-->
 <aop:aspectj-autoproxy />
</beans>
  • 4)测试类
package com.putao;

import com.putao.ba05.SomeSercice;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest05 {

    @Test
    public void test01(){
        String config = "applicationContext.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象
        SomeSercice proxy = (SomeSercice) ctx.getBean("someService");
        //通过代理对象执行方法,实现目标方法执行时,增强了功能
        proxy.doThird();
    }
}

8.@Pointcut定义切入点

@PointCut: 定义和管理切入点,如果你的项目中有多个切入点表达式是重复的,可以复用的。
* 可以使用@PointCut
* 属性:value 切入点表达式
* 位置:在自定义的方面上面
* 特点:
* 在使用@PointCut定义在一个方法的上面,此时这个方法的名称就是切入点表达式的别名。
* 其他的通知中,value属性就可以使用这个方法名称,代替切入点表达式了。

package com.putao.ba06;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class MyAspect {

    @After(value = "mypt()")
    public void myAfter(){
        System.out.println("执行最终通知,总是会被执行的代码");
        //一般是做资源清除工作的。
    }

    @Before(value = "mypt()")
    public void myBefore(){
        System.out.println("前置通知,在目标方法之前先执行的");

    }
   
    @Pointcut(value = "execution(* *..SomeSerciceImpl.doThird(..))")
    private void mypt(){
        //无需代码
    }

}

9.cglib代理(无接口-自动)

  • 1)目标类
package com.putao.ba07;

//目标类
public class SomeSerciceImpl{

    public void doThird() {
        System.out.println("执行业务方法doThird()");
    }
}
  • 2)切面类
package com.putao.ba07;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class MyAspect {

    @After(value = "mypt()")
    public void myAfter(){
        System.out.println("执行最终通知,总是会被执行的代码");
        //一般是做资源清除工作的。
    }

    @Before(value = "mypt()")
    public void myBefore(){
        System.out.println("前置通知,在目标方法之前先执行的");

    }
 
    @Pointcut(value = "execution(* *..SomeSerciceImpl.doThird(..))")
    private void mypt(){
        //无需代码
    }

}
  • 3)配置文件
<?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">

<!--    把对象交给spring容器,由spring容器统一创建,管理对象-->
<!--    声明目标对象-->
    <bean id="someService" class="com.putao.ba08.SomeSerciceImpl" />

<!--    声明切面对象-->
    <bean id="myAspect" class="com.putao.ba08.MyAspect" />

<!--    声明自动代理生成器:使用aspectj框架内部的功能,创建目标对象的代理对象
        创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象
        所有目标对象就是被修改后的代理对象

        aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象
-->
  <aop:aspectj-autoproxy />

</beans>
  • 4)测试
package com.putao;

import com.putao.ba07.SomeSerciceImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest07 {

    @Test
    public void test01(){
        String config = "applicationContext.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象
        SomeSerciceImpl proxy = (SomeSerciceImpl) ctx.getBean("someService");

        /**
         * 目标类没有接口,使用cglib动态代理,spring框架会自动应用cglib
         */
        System.out.println("proxy:"+proxy.getClass().getName());
        //通过代理对象执行方法,实现目标方法执行时,增强了功能
        proxy.doThird();
    }
}

10.cglib代理(有接口-手动)

  • 1)目标类
package com.putao.ba08;

public interface SomeSercice {

    void doThird();
}
package com.putao.ba08;

//目标类
public class SomeSerciceImpl implements SomeSercice {
   
    @Override
    public void doThird() {
        System.out.println("执行业务方法doThird()");
    }
}

  • 2)切面类
package com.putao.ba08;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class MyAspect {

    @After(value = "mypt()")
    public void myAfter(){
        System.out.println("执行最终通知,总是会被执行的代码");
        //一般是做资源清除工作的。
    }

    @Before(value = "mypt()")
    public void myBefore(){
        System.out.println("前置通知,在目标方法之前先执行的");

    }

    @Pointcut(value = "execution(* *..SomeSerciceImpl.doThird(..))")
    private void mypt(){
        //无需代码
    }

}
  • 3)配置文件
<?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">

<!--    把对象交给spring容器,由spring容器统一创建,管理对象-->
<!--    声明目标对象-->
    <bean id="someService" class="com.putao.ba08.SomeSerciceImpl" />

<!--    声明切面对象-->
    <bean id="myAspect" class="com.putao.ba08.MyAspect" />

    <!--
        如果你期望目标类有接口,使用cglib代理
        proxy-target-class="true":告诉框架,要使用cglib动态代理
    -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>
  • 4)测试
package com.putao;

import com.putao.ba08.SomeSercice;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest08 {

    @Test
    public void test01(){
        String config = "applicationContext.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象
        SomeSercice proxy = (SomeSercice) ctx.getBean("someService");

        System.out.println("proxy:"+proxy.getClass().getName());
        //通过代理对象执行方法,实现目标方法执行时,增强了功能
        proxy.doThird();
    }
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值