摘要: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 生成),用于织入切面逻辑。