首先配置文件内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <!--横切逻辑--> <bean id= "logUtils" class = "com.test.circular.LogUtils" > </bean> <aop:config> <aop:aspect ref= "logUtils" > <aop:before method= "beforeMethod" pointcut= "execution(public void com.test.aop.AopBean.test())" /> <aop:after method= "alertMethod" pointcut= "execution(public void com.test.aop.AopBean.test())" /> <aop:around method= "aroundMethod" pointcut= "execution(public void com.test.aop.AopBean.test())" /> <aop:after-returning method= "afterReturning" pointcut= "execution(public void com.test.aop.AopBean.test())" /> <aop:after-throwing method= "afterThrowingMethod" pointcut= "execution(public void com.test.aop.AopBean.test())" /> </aop:aspect> </aop:config> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public class LogUtils { public void beforeMethod() { System.out.println( "前置通知" ); } public void alertMethod() { System.out.println( "最终通知" ); } public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable { System.out.println( "环绕通知-前" ); Object proceed = pjp.proceed(); System.out.println( "环绕通知-后" ); return proceed; } public void afterThrowingMethod() { System.out.println( "异常通知" ); } public void afterReturning() { System.out.println( "后置通知" ); } } |
public class AopBean implements AopBeanInf{
@Override
public void test() {
System.out.println("spring aop 测试");
}
}
通过SpringIOC源码中的源码分析过程,可以将切入点定位到如下图所示方法。
接着会遍历所有的初始化的bean,主要进入AbstractAutowireCapableBeanFactory的doCreateBean方法,会完成实例创建。
往下走会完成bean生命周期的管理,首先属性填充,调用初始化bean,重点分析这个方法。
1) 调用Bean中的BeanNameAware.setBeanName()方法,如果该Bean实现了BeanNameAware接口;调用Bean中的BeanFactoryAware.setBeanFactory()方法,如果该Bean实现了BeanFactoryAware接口,调用Bean中的BeanClassLoader.setBeanClassLoader()方法。
2)调用BeanPostProcessors.postProcessBeforeInitialization()方法
3)调用Bean中的afterPropertiesSet方法,如果该Bean实现了InitializingBean接口;
4)调用Bean中的init-method,通常是在配置bean的时候指定了init-method,例如:<beanclass="beanClass"init-method="init"></bean>
5)调用BeanPostProcessors.postProcessAfterInitialization()方法;
实现AOP主要在初始化后应用Bean后置处理器---在这一步生成代理对象
这个方法会遍历所有的后置处理器。
主要进入AbstractAutoProxyCreator类的postProcessAfterInitialization方法,如下红框所示对象进行包装即增强
将所有的通知拆分成数组。
如下图所示,通过createProxy方法创建代理对象。
进入的createProxy方法,该方法中主要有getProxy这个方法中会通过代理工厂生成对象
判断是否实现接口,用jdk还是cglib代理,默认采用jdk代理。
1 2 3 | public Object getProxy( @Nullable ClassLoader classLoader) { return createAopProxy().getProxy(classLoader); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null ) { throw new AopConfigException( "TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation." ); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } } |
1 | 创建代理对象后,这里采用JdkDynamicAopProxy,然后进入该类的getProxy执行代理方法 |
观察下JdkDynamicAopProxy这个类,本身实现了InvocationHandler,就是个代理对象,
作为Proxy对象的回调函数被触发,从而通过invoke()的具体实现来完成对目标对象的拦截或者说功能增强的工作。
执行代理对象的invoke方法。
得到拦截链。
递归进入了ReflectiveMethodInvocation类的proceed()
可以看到此时的methodName为beforeMethod
因此此时会执行MethodBeforeAdviceInterceptor类的invoke方法。
继续往下走,一直到AbstractAspectJAdvice类的如下方法:
通过反射执行Method
执行到DelegatingMethodAccessorImpl类的invoke方法。
执行到NativeMethodAccessorImpl类中invoke方法。
继续执行会到走到前置通知方法答应出具体内容。
返回,执行完前置通知后再调用mi.proceed()。
接着从执行链中再取一个执行。
进入AspectJAfterAdvice类执行最终通知
环绕通知,创建了连接点对象,执行到AspectJAroundAdvice类的invoke方法
进入proceed,执行后置通知
AfterReturningAdviceInterceptor
执行连接点之后进行后置通知,首先执行连接点方法
这时找到异常通知
在AspectJAfterThrowingAdvice类
执行目标方法
然后返回
执行后置通知
最后在finally中执行最终通知。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构