Spring的AOP和动态代理

发布于:2025-08-06 ⋅ 阅读:(19) ⋅ 点赞:(0)

摘要:AOP和动态代理的关系:

简单来说,动态代理是实现 AOP 的核心技术手段,二者是 “技术实现” 与 “编程思想” 的关系:

  • AOP(面向切面编程) 是一种思想,目的是将日志、事务等 “横切逻辑” 从业务代码中分离出来,实现代码解耦。
  • 动态代理是一种技术,能在运行时动态生成代理对象,在不修改原代码的情况下,对目标方法进行增强(比如在方法执行前后插入额外逻辑)。

AOP 的核心需求(在目标方法中 “织入” 横切逻辑),正是通过动态代理技术来实现的。例如 Spring AOP 框架,底层就是通过 JDK 动态代理或 CGLIB 动态代理,为目标对象创建代理,从而自动执行切面中定义的增强逻辑。

一:引出AOP

1.需求说明


有Vehicle(交通工具接口,有一个run方法),面有两个实现类Car和 Ship2.当运行Car对象 的 run方法和 Ship对象的rul方法时。输入如下内容,注意观察前后有统一的输出。

交通工具开始运行了....
小汽车在路上 running....
交通工具停止运行了....
交通工具开始运行了....
大轮船在水上 running....
交通工具停止运行了....

1).解决方案-----传统方案

Vehicle接口:
package com.zzy.spring.AOP;

public interface Vehicle {
    public void run();
}
Car类:
package com.zzy.spring.AOP;

public class Car implements Vehicle{
    @Override
    public void run() {
        System.out.println("交通工具开始运行了....");
        System.out.println("小汽车在路上 running....");
        System.out.println("交通工具停止运行了....");
    }
}
Ship类:
package com.zzy.spring.AOP;


public class Ship implements Vehicle{
    @Override
    public void run() {
        System.out.println("交通工具开始运行了....");
        System.out.println("大轮船在水上 running....");
        System.out.println("交通工具停止运行了....");
    }

}
TestVehicle类:
package com.zzy.spring.AOP;

import org.junit.Test;

public class TestVehicle {

    @Test
    public void run() {
        Vehicle vehicle=new Ship();
        vehicle.run();
    }
}

2)解决方案----动态代理方式

解决思路:在调用方法时,使用反射机制,根据方法去决定调用哪个对象方法

Vehicle接口:
package com.zzy.spring.AOP;

public interface Vehicle {
    public void run();
    public String fly(int height);
}
Car类:
package com.zzy.spring.AOP;

public class Car implements Vehicle{
    @Override
    public void run() {
        System.out.println("交通工具开始运行了....");
        System.out.println("小汽车在路上 running....");
        System.out.println("交通工具停止运行了....");
    }

    @Override
    public String fly(int height) {
        System.out.println("小汽车可以飞翔 高度=" + height);
        return "小汽车可以飞翔 高度=" + height;
    }
}
Ship类:
package com.zzy.spring.AOP;


public class Ship implements Vehicle{
    @Override
    public void run() {
       // System.out.println("交通工具开始运行了....");
        System.out.println("大轮船在水上 running....");
      //  System.out.println("交通工具停止运行了....");
    }

    @Override
    public String fly(int height) {
        System.out.println("轮船可以飞翔 高度=" + height);
        return "轮船可以飞翔 高度=" + height;
    }

}
VehicleAopProvider类:
package com.zzy.spring.AOP;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/*
*  VehicleAopProvider 该类可以返回一个代理对象.
 */
public class VehicleAopProvider {


    //定义一个属性
    //target_vehicle 表示真正要执行的对象
    //该对象实现了Vehicle接口
    private Vehicle target_vehicle;

    //构造器
    public VehicleAopProvider(Vehicle target_vehicle) {
        this.target_vehicle = target_vehicle;
    }

    //编写一个方法,可以返回一个代理对象, 该代理对象可以通过反射机制调用到被代理对象的方法
    public Vehicle getProxy() {

        //得到类加载器
        ClassLoader classLoader =
                target_vehicle.getClass().getClassLoader();

        //得到要代理的对象/被执行对象 的接口信息,底层是通过接口来完成调用
        Class<?>[] interfaces = target_vehicle.getClass().getInterfaces();

        //创建InvocationHandler 对象
        //因为 InvocationHandler 是接口,所以我们可以通过 ”匿名对象“ 的方式来创建该对象 !!!!!
        /**
        源代码:
         *
         * public interface InvocationHandler {
         *  public Object invoke(Object proxy, Method method, Object[] args)
         *         throws Throwable;
         * }
         * invoke 方法是将来执行我们的target_vehicle的方法时,会调用到
         *
         */

        InvocationHandler invocationHandler = new InvocationHandler() {
            /*
             * invoke 方法是将来执行我们的target_vehicle的方法时,会调用到
             * @param o 表示代理对象
             * @param method 就是通过代理对象调用方法时,的哪个方法 代理对象.run()
             * @param args : 表示调用 代理对象.run(xx) 传入的参数
             * @return 表示 代理对象.run(xx) 执行后的结果.
             * @throws Throwable
             */
            @Override
            public Object invoke(Object o, Method method, Object[] args)
                    throws Throwable {

                System.out.println("交通工具开始运行了....");
                //这里是我们的反射基础 => OOP
                //method 是?: public abstract void com.zzy.spring.AOP.Vehicle.run()
                //target_vehicle 是? Ship对象
                //args 是null
                //这里通过反射+动态绑定机制,就会执行到被代理对象的方法
                //执行完毕就返回
                Object result = method.invoke(target_vehicle, args);
                System.out.println("交通工具停止运行了....");
                return result;
            }
        };



         /**
          源代码:
          public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        解决代  码:
          1. Proxy.newProxyInstance() 可以返回一个代理对象
          2. ClassLoader loader: 类的加载器.
          3. Class<?>[] interfaces 就是将来要代理的对象的接口信息
          4. InvocationHandler h 调用处理器/对象 有一个非常重要的方法invoke
         */
        Vehicle proxy =
                (Vehicle) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);

        return proxy;
    }

}
TestVehicle类:
package com.zzy.spring.AOP;

import org.junit.Test;

public class TestVehicle {

    @Test
    public void run() {
        Vehicle vehicle=new Ship();
        vehicle.run();
    }


    @Test
    public void AOP_Run() {
        //创建Ship对象
        Vehicle vehicle = new Ship();

        //创建VehicleProxyProvider对象, 并且我们传入的要代理的对象
         VehicleAopProvider vehicleAopProvider=
                new VehicleAopProvider(vehicle);

        //获取代理对象, 该对象可以代理执行方法
        //1.  proxy 编译类型 Vehicle
        //2. 运行类型 是代理类型 class com.sun.proxy.$Proxy4

        Vehicle proxy = vehicleAopProvider.getProxy();

        System.out.println("proxy的编译类型是 Vehicle");
        System.out.println("proxy的运行类型是 " + proxy.getClass());
        //proxy的编译类型是 Vehicle, 运行类型是 class com.sun.proxy.$Proxy4
        //所以当执行run方法时,会执行到 代理对象的invoke
        //如何体现动态 [1. 被代理的对象(vehicle可以变化,传入哪个对象,就执行哪个对象) 2. 方法]
        proxy.run();
        System.out.println("---------------------------------------------------");
        String result = proxy.fly(10000);
        System.out.println("result=" + result);
    }
}
运行结果:
proxy的编译类型是 Vehicle
proxy的运行类型是 class com.sun.proxy.$Proxy4
交通工具开始运行了....
大轮船在水上 running....
交通工具停止运行了....
---------------------------------------------------
交通工具开始运行了....
轮船可以飞翔 高度=10000
交通工具停止运行了....
result=轮船可以飞翔 高度=10000

2.自己用 动态代理 解决一个问题

1):需求

有一个SmartAnimal 接口,可以完成简单的加减法,要求在执行getSum ()和getSub ()时,输出执行前,执行过程,执行后的日志输出,请思考如何实现 。

方法执行前-日志-方法名-getSum-参数 [10.0, 2.0]
方法内部打印result = 8.0
方法执行正常结束-日志-方法名-getSum-结果result= 8.0
方法最终结束-日志-方法名-getSum
-----------------------------
方法执行前-日志-方法名-getSub-参数 [10.0, 2.0]
方法内部打印result = 12.0
方法执行正常结束-日志-方法名-getSub-结果result= 12.0
方法最终结束-日志-方法名-getSub

1))用传统方案写

(自己写,这里就不写了)

优点:实现简单直接!!!

缺点:日志代码维护不方便,代码重复性差!!!

2))用动态代理方式写

SmartAnimalable接口
package com.zzy.spring.AOP.HomeWork;

public interface SmartAnimalable{
    float getSum(float i,float j);
    float getSub(float i,float j);
}
SmartDog类
package com.zzy.spring.AOP.HomeWork;

public class SmartDog implements SmartAnimalable{
    @Override
    public float getSub(float i, float j) {
        float result = i+j;
        System.out.println("方法内部打印result = " + result);
        return result;
    }

    @Override
    public float getSum(float i, float j) {
        float result = i-j;
        System.out.println("方法内部打印result = " + result);
        return result;
    }
}
MyAopProvider类
package com.zzy.spring.AOP.HomeWork;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class MyAopProvider {
    private SmartAnimalable target_obj;

    public MyAopProvider(SmartAnimalable target_obj) {
        this.target_obj = target_obj;
    }

    public SmartAnimalable getProxy() {
        //1. 得到类加载器
        ClassLoader classLoader = target_obj.getClass().getClassLoader();
        //2. 得到要执行的目标对象的接口信息
        Class<?>[] interfaces = target_obj.getClass().getInterfaces();
        //3. 创建InvocationHandler
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object result = null;
                try {
                    System.out.println("方法执行前-日志-方法名-" + method.getName() + "-参数 "
                            + Arrays.asList(args)); //这里从AOP看,就是一个横切关注点-前置通知
                    //使用反射调用方法
                    result = method.invoke(target_obj, args);
                    System.out.println("方法执行正常结束-日志-方法名-" + method.getName() + "-结果result= "
                            + result);//从AOP看, 也是一个横切关注点-返回通知

                } catch (Exception e) {
                    e.printStackTrace();
                    //如果反射执行方法时,出现异常,就会进入到catch{}
                    System.out.println("方法执行异常-日志-方法名-" + method.getName()
                            + "-异常类型=" + e.getClass().getName());//从AOP看, 也是一个横切关注点-异常通知
                } finally {//不管你是否出现异常,最终都会执行到finally{}
                    //从AOP的角度看, 也是一个横切关注点-最终通知
                    System.out.println("方法最终结束-日志-方法名-" + method.getName());
                }

                return result;
            }
        };
        //创建代理对象
        SmartAnimalable proxy=(SmartAnimalable) Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);
        return proxy;
    }
}
AopTest类
package com.zzy.spring.AOP.HomeWork;

import org.junit.Test;

public class AopTest {
   @Test
    public void smartDogTestByAop() {

        SmartAnimalable smartAnimalable=new SmartDog();

       //创建 myAopProvider 对象, 并且我们传入的要代理的对象
        MyAopProvider myAopProvider=new MyAopProvider(smartAnimalable);
       SmartAnimalable proxy = myAopProvider.getProxy();

       //System.out.println("proxy的 getName: "+proxy.getClass());proxy的 getName: class com.sun.proxy.$Proxy4
       proxy.getSum(10,2);
       System.out.println("-----------------------------");
       proxy.getSub(10,2);

   }
}
运行结果
方法执行前-日志-方法名-getSum-参数 [10.0, 2.0]
方法内部打印result = 8.0
方法执行正常结束-日志-方法名-getSum-结果result= 8.0
方法最终结束-日志-方法名-getSum
-----------------------------
方法执行前-日志-方法名-getSub-参数 [10.0, 2.0]
方法内部打印result = 12.0
方法执行正常结束-日志-方法名-getSub-结果result= 12.0
方法最终结束-日志-方法名-getSub

3.问题提出并解决

1)在MyAopProvider.java中,我们的输出语句功能比较弱,在实际开发中,我们希望是以一个方法的形式,嵌入真实执行的目标方法前,如这部分内容(硬编码方式)和其他类似的一小部分,怎么办?

System.out.println("方法执行前-日志-方法名-" + method.getName() + "-参数 "+ Arrays.asList(args));
System.out.println("方法执行正常结束-日志-方法名-" + method.getName() + "-结果result= "
                            + result);
解决:把上面的  MyAopProvider.java 代码稍微修改一下
package com.zzy.spring.AOP.HomeWork_Version2;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class MyAopProvider {
    private SmartAnimalable target_obj;

    public MyAopProvider(SmartAnimalable target_obj) {
        this.target_obj = target_obj;
    }

    //这个方法,在目标对象执行前执行
    public void before(Object proxy, Method method, Object[] args){
        System.out.println("before---方法执行前-日志-方法名-" + method.getName() + "-参数 "
                + Arrays.asList(args)); //这里从AOP看,就是一个横切关注点-前置通知
    }
    //这个方法,在目标对象执行后执行
    public void after( Method method,Object result){
        System.out.println("after---方法执行正常结束-日志-方法名-" + method.getName() + "-结果result= "
                + result);//从AOP看, 也是一个横切关注点-返回通知
    }


    public SmartAnimalable getProxy() {
        //1. 得到类加载器
        ClassLoader classLoader = target_obj.getClass().getClassLoader();
        //2. 得到要执行的目标对象的接口信息
        Class<?>[] interfaces = target_obj.getClass().getInterfaces();
        //3. 创建InvocationHandler
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object result = null;
                try {

                    before(proxy, method, args);
                    //使用反射调用方法
                    result = method.invoke(target_obj, args);
                    after(method, result);

                } catch (Exception e) {
                    e.printStackTrace();
                    //如果反射执行方法时,出现异常,就会进入到catch{}
                    System.out.println("方法执行异常-日志-方法名-" + method.getName()
                            + "-异常类型=" + e.getClass().getName());//从AOP看, 也是一个横切关注点-异常通知
                } finally {//不管你是否出现异常,最终都会执行到finally{}
                    //从AOP的角度看, 也是一个横切关注点-最终通知
                    System.out.println("方法最终结束-日志-方法名-" + method.getName());
                }

                return result;
            }
        };
        //创建代理对象
        SmartAnimalable proxy=(SmartAnimalable) Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);
        return proxy;
    }
}
运行结果:
before---方法执行前-日志-方法名-getSum-参数 [10.0, 2.0]
方法内部打印result = 8.0
after---方法执行正常结束-日志-方法名-getSum-结果result= 8.0
方法最终结束-日志-方法名-getSum
-----------------------------
before---方法执行前-日志-方法名-getSub-参数 [10.0, 2.0]
方法内部打印result = 12.0
after---方法执行正常结束-日志-方法名-getSub-结果result= 12.0
方法最终结束-日志-方法名-getSub

2)上面(MyAopProvider.java 代码稍微修改一下)代码有问题:耦合度高

解决:解耦——开发最简单的AOP
ZzyAOP(新创建的java类)
package com.zzy.spring.AOP.HomeWork_Version3;

import java.lang.reflect.Method;
import java.util.Arrays;

public class ZzyAOP {

    //这个方法,在目标对象执行前执行
    public static void before(Object proxy, Method method, Object[] args){
        System.out.println("ZzyAOP---方法执行前-日志-方法名-" + method.getName() + "-参数 "
                + Arrays.asList(args)); //这里从AOP看,就是一个横切关注点-前置通知
    }
    //这个方法,在目标对象执行后执行
    public static void after( Method method,Object result){
        System.out.println("ZzyAOP---方法执行正常结束-日志-方法名-" + method.getName() + "-结果result= "
                + result);//从AOP看, 也是一个横切关注点-返回通知
    }


}
MyAopProvider(把before和after方法移到新创建的ZzyAOP类里)
package com.zzy.spring.AOP.HomeWork_Version3;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class MyAopProvider {
    private SmartAnimalable target_obj;

    public MyAopProvider(SmartAnimalable target_obj) {
        this.target_obj = target_obj;
    }


    public SmartAnimalable getProxy() {
        //1. 得到类加载器
        ClassLoader classLoader = target_obj.getClass().getClassLoader();
        //2. 得到要执行的目标对象的接口信息
        Class<?>[] interfaces = target_obj.getClass().getInterfaces();
        //3. 创建InvocationHandler
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object result = null;
                try {

                    ZzyAOP.before(proxy, method, args);
                    //使用反射调用方法
                    result = method.invoke(target_obj, args);
                    ZzyAOP.after(method, result);

                } catch (Exception e) {
                    e.printStackTrace();
                    //如果反射执行方法时,出现异常,就会进入到catch{}
                    System.out.println("方法执行异常-日志-方法名-" + method.getName()
                            + "-异常类型=" + e.getClass().getName());//从AOP看, 也是一个横切关注点-异常通知
                } finally {//不管你是否出现异常,最终都会执行到finally{}
                    //从AOP的角度看, 也是一个横切关注点-最终通知
                    System.out.println("方法最终结束-日志-方法名-" + method.getName());
                }

                return result;
            }
        };
        //创建代理对象
        SmartAnimalable proxy=(SmartAnimalable) Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);
        return proxy;
    }
}
其他的不变
运行结果:
ZzyAOP---方法执行前-日志-方法名-getSum-参数 [10.0, 2.0]
方法内部打印result = 8.0
ZzyAOP---方法执行正常结束-日志-方法名-getSum-结果result= 8.0
方法最终结束-日志-方法名-getSum
-----------------------------
ZzyAOP---方法执行前-日志-方法名-getSub-参数 [10.0, 2.0]
方法内部打印result = 12.0
ZzyAOP---方法执行正常结束-日志-方法名-getSub-结果result= 12.0
方法最终结束-日志-方法名-getSub

3)简易AOP实现的两大缺陷(缺乏反射机制和注解体系支撑):

① 灵活性不足(强制切入类的所有方法单个方法,无法精准控制),
如示例中SmartDog类的多个方法被before()同时切入,无法实现仅作用于getSum()等单方法。
② 复用性差(仅支持特定接口的实现类),
仅能作用于SmartAnimalable等特定接口实现类,无法适配其他接口(如USBInterface的work()方法)。
解决:通过AspectJ框架整合反射与注解技术,实现方法级精准切入和跨接口动态代理,彻底解决传统硬编码模式的局限性。————也就是Spring AOPP的核心价值!!!

注意:Spring AOP本质:基于AspectJ的元编程范式升级,实现声明式编程转型

二:AOP

1.基本介绍

1)什么是 AOP


AOP 的全称(aspect oriented programming) ,面向切面编程

2)一张详细图说明 AOP

3)AOP 实现方式


1)). 基于动态代理的方式[内置 aop 实现]
2)). 使用框架 aspectj 来实现

4)基本说明

1)) 需要引入核心的 aspect 包
2)) 在切面类中声明通知方法
3)) 前置通知:@Before
4)) 返回通知:@AfterReturning
5)) 异常通知:@AfterThrowing
6)) 后置通知:@After
7)) 环绕通知:@Around

2.入门实例

1)需求说明

我们使用 aop 编程的方式,来实现手写的动态代理案例效果,就以上一个案例为例来讲解

(如图)

2)代码实现步骤

1)) 导入 AOP 编程需要的包

2))  创建所需要的类和接口
SmartAnimalable接口
package com.zzy.spring.AOP.Aspectj;

public interface SmartAnimalable{
    float getSum(float i,float j);
    float getSub(float i,float j);
}
SmartDog类
package com.zzy.spring.AOP.Aspectj;

import org.springframework.stereotype.Component;

@Component  //使用 @Component 当spring容器启动时,将 SmartDog注入到容器
public class SmartDog implements SmartAnimalable {
    @Override
    public float getSub(float i, float j) {
        float result = i+j;
        System.out.println("方法内部打印result = " + result);
        return result;
    }

    @Override
    public float getSum(float i, float j) {
        float result = i-j;
        System.out.println("方法内部打印result = " + result);
        return result;
    }
}
SmartAnimalAspect类
package com.zzy.spring.AOP.Aspectj;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 切面类 , 类似于我们以前自己写的MyAopProvider,但是功能强大很多
 */
@Aspect //表示是一个切面类[底层切面编程的支撑(动态代理+反射+动态绑定...)]
@Component //会注入SmartAnimalAspect到容器
public class SmartAnimalAspect {

    //希望将 showBeginLog 方法切入到SmartDog-getSum前执行-前置通知

    /**
     * 1. @Before 表示前置通知:即在我们的目标对象执行方法前执行
     * 2. value = "execution(public float com.zzy.spring.AOP.aspectj.SmartDog.getSum(float, float)
     * 指定切入到哪个类的哪个方法  形式是: 访问修饰符 返回类型 全类名.方法名(形参列表)
     * 3. showBeginLog方法可以理解成就是一个切入方法, 这个方法名是可以程序员指定  比如:showBeginLog
     * 4. JoinPoint joinPoint 在底层执行时,由AspectJ切面框架, 会给该切入方法传入 joinPoint对象
     * , 通过该方法,程序员可以获取到 相关信息
     *
     * @param joinPoint
     */
    @Before(value = "execution(public float com.zzy.spring.AOP.Aspectj.SmartDog.getSum(float, float))")
    public void showBeginLog(JoinPoint joinPoint) {
        //通过连接点对象joinPoint 可以获取方法签名
        Signature signature = joinPoint.getSignature();
        System.out.println("SmartAnimalAspect-切面类showBeginLog()方法执行前-日志-方法名-" + signature.getName() + "-参数 "
                + Arrays.asList(joinPoint.getArgs()));
    }

    //返回通知:即把showSuccessEndLog方法切入到目标对象方法正常执行完毕后的地方
    @AfterReturning(value = "execution(public float com.zzy.spring.AOP.Aspectj.SmartDog.getSum(float, float))")
    public void showSuccessEndLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        System.out.println("SmartAnimalAspect-切面类showSuccessEndLog()-方法执行正常结束-日志-方法名-" + signature.getName() );
    }

    //异常通知:即把showExceptionLog方法切入到目标对象方法执行发生异常的的catch{}
    @AfterThrowing(value = "execution(public float com.zzy.spring.AOP.Aspectj.SmartDog.getSum(float, float))")
    public void showExceptionLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        System.out.println("SmartAnimalAspect-切面类showExceptionLog()-方法执行异常-日志-方法名-" + signature.getName());
    }

    //最终通知:即把showFinallyEndLog方法切入到目标方法执行后(不管是否发生异常,都要执行 finally{})
    @After(value = "execution(public float com.zzy.spring.AOP.Aspectj.SmartDog.getSum(float, float))")
    public void showFinallyEndLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        System.out.println("SmartAnimalAspect-切面类showFinallyEndLog()-方法最终执行完毕-日志-方法名-" + signature.getName());
    }

}
smartDogTestByAop类
package com.zzy.spring.AOP.Aspectj;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AopAspectjTest {

    @Test
    public void smartDogTestByAop(){
        //得到Sring容器
        ApplicationContext ioc=new ClassPathXmlApplicationContext("beans_Aspectj.xml");
        //这里我们需要通过接口类型来获取到注入的SmartDog对象---(其实)就是代理对象
        SmartAnimalable smartAnimalable =
                ioc.getBean(SmartAnimalable.class);

        smartAnimalable.getSum(10,2);

    }
}
运行结果:
SmartAnimalAspect-切面类showBeginLog()方法执行前-日志-方法名-getSum-参数 [10.0, 2.0]
方法内部打印result = 8.0
SmartAnimalAspect-切面类showSuccessEndLog()-方法执行正常结束-日志-方法名-getSum
SmartAnimalAspect-切面类showFinallyEndLog()-方法最终执行完毕-日志-方法名-getSum

3)细节说明

1))JoinPoint joinPoint解释:

showBeginLog这个方法相当于放在了图片中圈后的位置,把这些参数(Object proxy, Method method, Object[] args)打包称joinPoint,放在proxy, method, args的位置上。

2))没有 xml文件里 如果写<aop:aspectj-autoproxy/>,那么SmartDog类中的 @Aspect 这个注解没有实际生效
3))关于切面类方法命名可以自己规范一下, 比如 showBeginLog() . showSuccessEndLog()
showExceptionLog(), showFinallyEndLog()                
4))切入表达式的更多配置,比如使用模糊配置
@Before(value="execution(* com.zzy.spring.AOP.Aspectj.SmartDog.*(..))")
5)) 表示所有访问权限,所有包的下所有有类的所方法,都会被执行该前置通知方法

    @Before(value="execution(* *.*(..))")
    6)) 当 spring 容器开启了 <!-- 开启基于注解的AOP功能--> <aop:aspectj-autoproxy/> , 我们获取注入的对象, 需要以接口的类型来获取, 因为你注入的对象.getClass() 已经是代理类型了!

    7)) 当 spring 容器开启了 <!-- 开启基于注解的AOP功能--> <aop:aspectj-autoproxy/> , 我们获取注入的对象, 也可以通过 id 来获取, 但是也要转成接口类型,解释如下:
    AopAspectjTest类中
    SmartAnimalable smartAnimalable =ioc.getBean(SmartAnimalable.class);

    可以换成

     SmartAnimalable smartAnimalable=(SmartAnimalable)ioc.getBean("smartDog");
    

    注:为什么不能写成:

     SmartDog smartAnimalable=(SmartDog)ioc.getBean("smartDog");
    

    因为:从编译角度看没有问题,但是 ioc.getBean 返回的是代理对象,这行代码是把代理对象转成类的类型;

    8))补充:

    ioc.getBean()是否返回代理对象,取决于是否对该 Bean 应用了 AOP 增强:

    • 若没有 AOP 切面(如日志、事务等),返回的是 Bean 本身;
    • 若有 AOP 切面且需要增强,返回的是代理对象(JDK 或 CGLIB 生成),用于织入切面逻辑。

    网站公告

    今日签到

    点亮在社区的每一天
    去签到