目录
- 前言
- AOP是什么
- AOP框架要做什么
- AOP技术元素分析
- Advice设计
- pointcut设计
- 表达式设计
- 类、接口设计
- aspect设计(advisor)
- weaving设计
- 织入要完成什么
- 织入时机
- 如何确定bean需要增强
- 如何实现织入
- 加入扩展点BeanPostProcessor
- 定义切面注册接口AdvisorRegistry
- 定义BeanFactory注册接口BeanFactoryAware
- 自动代理核心类AdvisorAutoProxyCreator
- Aop代理创建工厂
- Aop代理接口AopProxy
- jdk动态代理
- cglib动态代理
- Aop执行处理工具类
- 责任链模式处理所有advice
- 测试
- 测试类
- 通知类
前言
本篇基于(一)手写spring IOC容器手写AOP框架。采用问答形式,逐步梳理手写aop过程。
AOP是什么
Aspect Oriented Programming 面向切面编程,在不改变类的代码情况下,对类方法进行功能增强。
AOP框架要做什么
AOP框架要向使用用户提供AOP功能,让用户可以通过AOP技术实现对类方法进行功能增强。
AOP技术元素分析
包含
Advice:通知,增强的功能
joIn point:连接点,可选的方法点
pointcut:切入点,选择切入的方法点
aspect:切面,选择的(多个)方法点 + 增强的功能
introduction: 引入,添加新的方法、属性到已存在的类中
weaving:织入,不改变原类的的代码,加入功能增强,实现AOP
Advice设计
定义Advice接口
public interface Advice {
}
前置通知
/**
* 前置增强接口
*/
public interface MethodBeforeAdvice extends Advice {
/**
* 前置增强方法
* @param method 将要被执行的方法
* @param args 执行方法参数
* @param target 执行方法的目标对象
*/
void before(Method method, Object[] args, Object target);
}
后置通知
/**
* 后置增强接口
*/
public interface AfterReturningAdvice extends Advice {
/**
* 方法执行完毕后的增强接口
*
* @param returnValue 方法执行完后的返回值
* @param method 被执行的方法
* @param args 方法执行参数
* @param target 执行方法的对象
*/
void afterReturning(Object returnValue, Method method, Object[] args, Object target);
}
环绕通知
/**
* 方法环绕增强接口
*/
public interface MethodInterceptor extends Advice {
/**
* 对方法进行环绕(前置、后置)增强、异常处理增强,方法实现中需调用目标方法。
*
* @param method
* 被增强的方法
* @param args
* 方法的参数
* @param target
* 方法所属对象
* @return Object 返回值
* @throws Throwable
*/
Object invoke(Method method, Object[] args, Object target) throws Throwable;
}
pointcut设计
pointcut特点
- 用户性:由用户指定
- 变化性:用户可灵活指定
- 多点性:用户可在多个方法上进行增强
表达式设计
表达式可以表示一类方法的完整签名,比如AspectJ的pointcut表达式、正则表达式
类、接口设计
pointcut接口
/**
* 切点抽象接口
*/
public interface Pointcut {
/**
* 匹配类
* @param targetClass 将被匹配的目标类
* @return true,表示匹配规则;否则返回false。
*/
boolean matchsClass(Class<?> targetClass);
/**
* 匹配方法
* @param method 将要被匹配的方法
* @param targetClass 将要被匹配的目标类
* @return true,表示匹配规则;否则返回false。
*/
boolean matchsMethod(Method method, Class<?> targetClass);
}
AspectJExpressionPointcut 类
/**
*
* AspectJ表达式切点实现类
*/
public class AspectJExpressionPointcut implements Pointcut {
// 先获得切点解析器
private static PointcutParser pp = PointcutParser
.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();
// 切点表达式的字符串形式
private String expression;
// aspectj中的切点表达式实例pe
private PointcutExpression pe;
public AspectJExpressionPointcut(String expression) {
super();
this.expression = expression;
pe = pp.parsePointcutExpression(expression);
}
@Override
public boolean matchsClass(Class<?> targetClass) {
return pe.couldMatchJoinPointsInType(targetClass);
}
@Override
public boolean matchsMethod(Method method, Class<?> targetClass) {
ShadowMatch sm = pe.matchesMethodExecution(method);
return sm.alwaysMatches();
}
public String getExpression() {
return expression;
}
}
aspect设计(advisor)
advisor接口
/**
* 用户构建切面的接口,组合Advice和Pointcut
*/
public interface Advisor {
/**
* 通知bean的名称
* @return
*/
String getAdviceBeanName();
/**
* 表达式
* @return
*/
String getExpression();
}
PointcutAdvisor接口
/**
* 切点通知者,继承自Advisor扩展了Pointcut
*/
public interface PointcutAdvisor extends Advisor {
Pointcut getPointcut();
}
AspectJPointcutAdvisor类
/**
* 基于aspectj表达式切点的通知者实现
*/
public class AspectJPointcutAdvisor implements PointcutAdvisor {
private String adviceBeanName; // 通知bean名称
private String expression; // 切点表达式
private Pointcut pointcut; // aspectJ切点实例
/**
* 构造函数
* @param adviceBeanName 通知bean名称
* @param expression 切点表达式
*/
public AspectJPointcutAdvisor(String adviceBeanName, String expression) {
this.adviceBeanName = adviceBeanName;
this.expression = expression;
this.pointcut = new AspectJExpressionPointcut(this.expression);
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
@Override
public String getAdviceBeanName() {
return this.adviceBeanName;
}
@Override
public String getExpression() {
return this.expression;
}
}
weaving设计
织入要完成什么
将用户提供的增强功能加到指定方法上,需要我们在框架实现。
织入时机
创建bean实例的时候,完成初始化后,在对其增强
如何确定bean需要增强
对bean的类和方法挨个匹配用户指定的切面,如果有匹配的,那就应该增强
如何实现织入
动态代理
加入扩展点BeanPostProcessor
beanPostProcessor 接口
/**
* 后置处理器。
* Bean实例化完毕后及依赖注入完成后触发。
*/
public interface BeanPostProcessor {
/**
* bean初始化前的处理
* @param bean
* @param beanName
* @return
* @throws Exception
*/
default Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
return bean;
}
/**
* bean初始化后的处理
* @param bean
* @param beanName
* @return
* @throws Exception
*/
default Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
return bean;
}
}
定义切面注册接口AdvisorRegistry
AdvisorRegistry接口
/**
* 通知者注册接口
*/
public interface AdvisorRegistry {
/**
* 注册通知者
* @param ad
*/
public void registAdvisor(Advisor ad);
/**
* 获得通知者列表
* @return
*/
public List<Advisor> getAdvisors();
}
定义BeanFactory注册接口BeanFactoryAware
BeanFactoryAware接口
/**
* bean工厂构建通知接口
*/
public interface BeanFactoryAware extends Aware {
/**
* 接口实现者获得bean工厂方法
* @param bf
*/
void setBeanFactory(BeanFactory bf);
}
自动代理核心类AdvisorAutoProxyCreator
AdvisorAutoProxyCreator实现AdvisorRegistry、BeanPostProcessor、BeanFactoryAware接口
public class AdvisorAutoProxyCreator implements AdvisorRegistry, BeanPostProcessor, BeanFactoryAware {
// 通知者列表
private List<Advisor> advisors;
// 当前的bean工厂
private BeanFactory beanFactory;
public AdvisorAutoProxyCreator() {
this.advisors = new ArrayList<>();
}
// 注入通知者,级用户定义的切面内容
public void registAdvisor(Advisor ad) {
this.advisors.add(ad);
}
// 返回通知者列表
public List<Advisor> getAdvisors() {
return advisors;
}
// aware接口的实现,获得Bean工厂实例
@Override
public void setBeanFactory(BeanFactory bf) {
this.beanFactory = bf;
}
/**
* Bean初始化后进行增强功能。
* 需要在不改变代码的情况实现该功能,则通过代理模式进行增强。
* @param bean 需要增强的bean
* @param beanName bean名称
* @return 最终被增强的的bean,此时的bean已经经过了代理模式的增强。
* @throws Throwable
*/
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
// 在此判断bean是否需要进行切面增强,及获得增强的通知实现
List<Advisor> matchAdvisors = getMatchedAdvisors(bean, beanName);
// 如需要就进行增强,再返回增强的对象。
if (CollectionUtils.isNotEmpty(matchAdvisors)) {
// 通过代理模式进行功能增强
bean = this.createProxy(bean, beanName, matchAdvisors);
}
return bean;
}
private List<Advisor> getMatchedAdvisors(Object bean, String beanName) {
if (CollectionUtils.isEmpty(advisors)) {
return null;
}
// 得到类、所有的方法
Class<?> beanClass = bean.getClass();
List<Method> allMethods = this.getAllMethodForClass(beanClass);
// 存放匹配的Advisor的list
List<Advisor> matchAdvisors = new ArrayList<>();
// 遍历Advisor来找匹配的
for (Advisor ad : this.advisors) {
if (ad instanceof PointcutAdvisor) {
if (isPointcutMatchBean((PointcutAdvisor) ad, beanClass, allMethods)) {
matchAdvisors.add(ad);
}
}
}
return matchAdvisors;
}
private List<Method> getAllMethodForClass(Class<?> beanClass) {
List<Method> allMethods = new LinkedList<>();
Set<Class<?>> classes = new LinkedHashSet<>(ClassUtils.getAllInterfacesForClassAsSet(beanClass));
classes.add(beanClass);
for (Class<?> clazz : classes) {
// 通过spring framework提供的工具类找出所有方法,包括从父类继承而来的方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method m : methods) {
allMethods.add(m);
}
}
return allMethods;
}
/**
* 判断指定类中的方法是否有符合切点规则的。
* @param pa 方面信息,带有切点对象
* @param beanClass 指定的类
* @param methods 指定类中的所有方法
* @return
*/
private boolean isPointcutMatchBean(PointcutAdvisor pa, Class<?> beanClass, List<Method> methods) {
Pointcut p = pa.getPointcut();
// 首先判断类是否匹配
if (!p.matchsClass(beanClass)) {
return false;
}
// 再判断是否有方法匹配
for (Method method : methods) {
if (p.matchsMethod(method, beanClass)) {
return true;
}
}
return false;
}
/**
* 通过AopProxyFactory工厂去完成选择、和创建代理对象的工作。
* @param bean
* @param beanName
* @param matchAdvisors
* @return
* @throws Exception
*/
private Object createProxy(Object bean, String beanName, List<Advisor> matchAdvisors) throws Exception {
// 默认的代理工厂实现中获得代理工厂实现
return AopProxyFactory.getDefaultAopProxyFactory()
// 根据参数信息,选择创建代理工厂具体实现
.createAopProxy(bean, beanName, matchAdvisors, beanFactory)
// 从选择的代理工厂中,获得代理对象
.getProxy();
}
}
Aop代理创建工厂
AopProxyFactory接口
/**
* AOP代理接口的工厂模式接口
*/
public interface AopProxyFactory {
/**
* 根据参数获得AOP代理接口的实现
* @param bean
* @param beanName
* @param matchAdvisors
* @param beanFactory
* @return
* @throws Exception
*/
AopProxy createAopProxy(Object bean, String beanName, List<Advisor> matchAdvisors, BeanFactory beanFactory)
throws Exception;
/**
* 获得默认的AopProxyFactory实例
*
* @return AopProxyFactory
*/
static AopProxyFactory getDefaultAopProxyFactory() {
return new DefaultAopProxyFactory();
}
}
默认实现类DefaultAopProxyFactory类
public class DefaultAopProxyFactory implements AopProxyFactory {
@Override
public AopProxy createAopProxy(Object bean, String beanName, List<Advisor> matchAdvisors, BeanFactory beanFactory)
throws Exception {
// 是该用jdk动态代理还是cglib?
if (shouldUseJDKDynamicProxy(bean, beanName)) {
return new JdkDynamicAopProxy(beanName, bean, matchAdvisors, beanFactory);
} else {
return new CglibDynamicAopProxy(beanName, bean, matchAdvisors, beanFactory);
}
}
private boolean shouldUseJDKDynamicProxy(Object bean, String beanName) {
// 如何判断?
// 这样可以吗:有实现接口就用JDK,没有就用cglib?
// 请同学们在读spring的源码时看spring中如何来判断的
return false;
}
}
Aop代理接口AopProxy
AopProxy接口
/**
* AOP代理接口,用来创建获得代理对象
*/
public interface AopProxy {
/**
* Create a new proxy object.
* <p>
* Uses the AopProxy's default class loader (if necessary for proxy
* creation): usually, the thread context class loader.
*
* @return the new proxy object (never {@code null})
* @see Thread#getContextClassLoader()
*/
Object getProxy();
/**
* Create a new proxy object.
* <p>
* Uses the given class loader (if necessary for proxy creation).
* {@code null} will simply be passed down and thus lead to the low-level
* proxy facility's default, which is usually different from the default
* chosen by the AopProxy implementation's {@link #getProxy()} method.
*
* @param classLoader
* the class loader to create the proxy with (or {@code null} for
* the low-level proxy facility's default)
* @return the new proxy object (never {@code null})
*/
Object getProxy(ClassLoader classLoader);
}
jdk动态代理
JdkDynamicAopProxy类
/**
* JDk动态代理实现
*/
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
private static final Logger logger = LoggerFactory.getLogger(JdkDynamicAopProxy.class);
private String beanName; // bean名称
private Object target; // bean对象,需要被代理的对象
private List<Advisor> matchAdvisors; // 通知列表,需要被增强的一系列功能
private BeanFactory beanFactory; // bean工厂
public JdkDynamicAopProxy(String beanName, Object target, List<Advisor> matchAdvisors, BeanFactory beanFactory) {
this.beanName = beanName;
this.target = target;
this.matchAdvisors = matchAdvisors;
this.beanFactory = beanFactory;
}
/**
* InvocationHandler接口的实现。
* 进行代理功能增强后返回实际的结果。
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 调用代理增强
return AopProxyUtils.applyAdvices(target, method, args, matchAdvisors, proxy, beanFactory);
}
@Override
public Object getProxy() {
return this.getProxy(target.getClass().getClassLoader());
}
@Override
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("为" + target + "创建代理。");
}
return Proxy.newProxyInstance(classLoader, target.getClass().getInterfaces(), this);
}
}
cglib动态代理
CglibDynamicAopProxy
/**
* CGLIB动态代理实现
*/
public class CglibDynamicAopProxy implements AopProxy, MethodInterceptor {
private static final Logger logger = LoggerFactory.getLogger(CglibDynamicAopProxy.class);
private static Enhancer enhancer = new Enhancer();
private String beanName;
private Object target;
private List<Advisor> matchAdvisors;
private BeanFactory beanFactory;
public CglibDynamicAopProxy(String beanName, Object target, List<Advisor> matchAdvisors, BeanFactory beanFactory) {
this.beanName = beanName;
this.target = target;
this.matchAdvisors = matchAdvisors;
this.beanFactory = beanFactory;
}
@Override
public Object getProxy() {
return this.getProxy(target.getClass().getClassLoader());
}
@Override
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("为" + target + "创建cglib代理。");
}
Class<?> superClass = this.target.getClass();
enhancer.setSuperclass(superClass);
enhancer.setInterfaces(this.getClass().getInterfaces());
enhancer.setCallback(this);
Constructor<?> constructor = null;
try {
constructor = superClass.getConstructor(new Class<?>[] {});
} catch (NoSuchMethodException | SecurityException e) {
}
if (constructor != null) {
return enhancer.create();
} else {
BeanDefinition bd = ((DefaultBeanFactory) beanFactory).getBeanDefinition(beanName);
return enhancer.create(bd.getConstructor().getParameterTypes(), bd.getConstructorArgumentRealValues());
}
}
/**
* 进行方法增强后的代理类方法调用,并获得返回结果。
* @param proxy
* @param method
* @param args
* @param methodProxy
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
return AopProxyUtils.applyAdvices(target, method, args, matchAdvisors, proxy, beanFactory);
}
}
Aop执行处理工具类
AopProxyUtils
/**
* AOP代理工具类
*/
public class AopProxyUtils {
/**
* 对方法应用advices增强,获得最终返回结果。
*
* @param target bean对象,需要被增强的对象
* @param method 需要被增强的方法
* @param args 增强方法的参数
* @param matchAdvisors 匹配到的切面
* @param proxy bean对象功能增强后的代理对象
* @param beanFactory ioc容器
* @return 方法增强后的返回结果
* @throws Throwable
*/
public static Object applyAdvices(Object target, Method method, Object[] args, List<Advisor> matchAdvisors,
Object proxy, BeanFactory beanFactory) throws Throwable {
// 这里要做什么?
// 1、获取要对当前方法进行增强的advice Bean列表
List<Object> advices = AopProxyUtils.getShouldApplyAdvices(target.getClass(), method, matchAdvisors,
beanFactory);
// 2、如有增强的advice,责任链式增强执行
if (CollectionUtils.isEmpty(advices)) {
return method.invoke(target, args);
} else {
// 责任链式执行增强
AopAdviceChainInvocation chain = new AopAdviceChainInvocation(proxy, target, method, args, advices);
return chain.invoke();
}
}
/**
* 获取与方法匹配的切面的advices Bean对象列表
*
* @param beanClass
* @param method
* @param matchAdvisors
* @param beanFactory
* @return
* @throws Exception
*/
public static List<Object> getShouldApplyAdvices(Class<?> beanClass, Method method, List<Advisor> matchAdvisors,
BeanFactory beanFactory) throws Throwable {
if (CollectionUtils.isEmpty(matchAdvisors)) {
return null;
}
List<Object> advices = new ArrayList<>();
for (Advisor ad : matchAdvisors) {
if (ad instanceof PointcutAdvisor) {
if (((PointcutAdvisor) ad).getPointcut().matchsMethod(method, beanClass)) {
advices.add(beanFactory.getBean(ad.getAdviceBeanName()));
}
}
}
return advices;
}
}
责任链模式处理所有advice
AopAdviceChainInvocation类
/**
* AOP通知链调用类
*/
public class AopAdviceChainInvocation {
// AOP调用链执行方法
private static Method invokeMethod;
static {
try {
invokeMethod = AopAdviceChainInvocation.class.getMethod("invoke", null);
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
}
private Object proxy; // 代理类对象
private Object target; // 目标类对象
private Method method; // 调用执行的对象方法
private Object[] args; // 执行方法的参数
private List<Object> advices; // 方法被增强的功能-通知列表
public AopAdviceChainInvocation(Object proxy, Object target, Method method, Object[] args, List<Object> advices) {
this.proxy = proxy;
this.target = target;
this.method = method;
this.args = args;
this.advices = advices;
}
// 责任链执行记录索引号
private int i = 0;
public Object invoke() throws Throwable {
if (i < this.advices.size()) {
Object advice = this.advices.get(i++);
if (advice instanceof MethodBeforeAdvice) {
// 执行前置增强
((MethodBeforeAdvice) advice).before(method, args, target);
} else if (advice instanceof MethodInterceptor) {
// 执行环绕增强和异常处理增强。注意这里给入的method 和 对象 是invoke方法和链对象
return ((MethodInterceptor) advice).invoke(invokeMethod, null, this);
} else if (advice instanceof AfterReturningAdvice) {
// 当是后置增强时,先得得到结果,再执行后置增强逻辑
Object returnValue = this.invoke();
((AfterReturningAdvice) advice).afterReturning(returnValue, method, args, target);
return returnValue;
}
return this.invoke(); // 回调,遍历完advices列表
} else {
return method.invoke(target, args);
}
}
}
测试
测试类
public class AopTest {
static PreBuildBeanFactory bf = new PreBuildBeanFactory();
@Test
public void testCirculationDI() throws Throwable {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(Lad.class);
List<Object> args = new ArrayList<>();
args.add("sunwukong");
args.add(new BeanReference("baigujing"));
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("swk", bd);
bd = new GenericBeanDefinition();
bd.setBeanClass(MagicGril.class);
args = new ArrayList<>();
args.add("baigujing");
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("baigujing", bd);
bd = new GenericBeanDefinition();
bd.setBeanClass(Renminbi.class);
bf.registerBeanDefinition("renminbi", bd);
// 前置增强advice bean注册
bd = new GenericBeanDefinition();
bd.setBeanClass(MyBeforeAdvice.class);
bf.registerBeanDefinition("myBeforeAdvice", bd);
// 环绕增强advice bean注册
bd = new GenericBeanDefinition();
bd.setBeanClass(MyMethodInterceptor.class);
bf.registerBeanDefinition("myMethodInterceptor", bd);
// 后置增强advice bean注册
bd = new GenericBeanDefinition();
bd.setBeanClass(MyAfterReturningAdvice.class);
bf.registerBeanDefinition("myAfterReturningAdvice", bd);
// 往BeanFactory中注册AOP的BeanPostProcessor
AdvisorAutoProxyCreator aapc = new AdvisorAutoProxyCreator();
bf.registerBeanPostProcessor(aapc);
// 向AdvisorAutoProxyCreator注册Advisor
aapc.registAdvisor(
new AspectJPointcutAdvisor("myBeforeAdvice", "execution(* v2.di.MagicGril.*(..))"));
// 向AdvisorAutoProxyCreator注册Advisor
aapc.registAdvisor(
new AspectJPointcutAdvisor("myMethodInterceptor", "execution(* v2.di.Lad.say*(..))"));
// 向AdvisorAutoProxyCreator注册Advisor
aapc.registAdvisor(new AspectJPointcutAdvisor("myAfterReturningAdvice",
"execution(* v2.di.Renminbi.*(..))"));
bf.preInstantiateSingletons();
System.out.println("-----------------myBeforeAdvice---------------");
MagicGril gril = (MagicGril) bf.getBean("baigujing");
gril.getFriend();
gril.getName();
System.out.println("----------------myMethodInterceptor----------------");
Boy boy = (Boy) bf.getBean("swk");
boy.sayLove();
System.out.println("-----------------myAfterReturningAdvice---------------");
Renminbi rmb = (Renminbi) bf.getBean("renminbi");
rmb.pay();
}
}
通知类
public class MyAfterReturningAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) {
System.out.println(this + " 对 " + target + " 做了后置增强,得到的返回值=" + returnValue);
}
}
public class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) {
System.out.println(this + " 对 " + target + " 进行了前置增强!");
}
}
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(Method method, Object[] args, Object target) throws Throwable {
System.out.println(this + "对 " + target + "进行了环绕--前增强");
Object ret = method.invoke(target, args);
System.out.println(this + "对 " + target + "进行了环绕 --后增强。方法的返回值为:" + ret);
return ret;
}
}
运行结果
-----------------myBeforeAdvice---------------
2021-01-20 10:32:41.772 DEBUG main CglibDynamicAopProxy - 为MagicGril{name='baigujing'}创建cglib代理。
v3.aop.aspectj.advice.MyBeforeAdvice@3c72f59f 对 MagicGril{name='baigujing'} 进行了前置增强!
v3.aop.aspectj.advice.MyBeforeAdvice@3c72f59f 对 MagicGril{name='baigujing'} 进行了前置增强!
----------------myMethodInterceptor----------------
2021-01-20 10:32:41.817 DEBUG main CglibDynamicAopProxy - 为v2.di.Lad@77167fb7创建cglib代理。
调用了含有MagicGril参数的构造方法
v3.aop.aspectj.advice.MyMethodInterceptor@7a4ccb53对 edu.dongnao.courseware.aop.AopAdviceChainInvocation@309e345f进行了环绕--前增强
I love you, my gril! MagicGril{name='baigujing'}
v3.aop.aspectj.advice.MyMethodInterceptor@7a4ccb53对 edu.dongnao.courseware.aop.AopAdviceChainInvocation@309e345f进行了环绕 --后增强。方法的返回值为:null
-----------------myAfterReturningAdvice---------------
2021-01-20 10:32:41.822 DEBUG main CglibDynamicAopProxy - 为v2.di.Renminbi@18ce0030创建cglib代理。
使用人民币成功进行了支付
v3.aop.aspectj.advice.MyAfterReturningAdvice@4df50bcc 对 v2.di.Renminbi@18ce0030 做了后置增强,得到的返回值=null