springAop实现过程的debug追踪流程

本文通过一个例子介绍了Spring AOP的实现过程,从创建要织入的类和切面,到配置XML,展示了如何生成并替换代理对象。在debug过程中,发现对象在Spring容器初始化后即被转换为代理类,并存放在singletonObjects map中。通过源码追踪,揭示了bean的创建、初始化、代理对象的生成等步骤,特别指出在`createAopProxy`和`getProxy()`方法中完成具体代理对象的创建。整个流程涉及多个步骤,包括bean的生命周期管理和AOP代理的生成。

首先我们创建一个例子
创建要织入的类

@Service
public class UserService {
    public  void login() {
        System.out.println("登陆");
    }
}

创建切面
这里需要加上@Component注解,以便被spring扫描到
@Aspect表示这个是一个切面

@Aspect
@Component
public class UserServiceAop {

    @Pointcut("execution(* techermanager.Service.*.*(..))")
    private void log(){

    }

    @Before("techermanager.controller.aspect.UserServiceAop.log()")
    private void beforeLog(){
        System.out.println("before");
    }
}

在spring的xml配置文件里面加上配置

    <!-- 启用aspect注解 true表示支持基于类生成 这样需要用到cglib  false表示基于接口生成  -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>

注意这里
proxy-target-class="true" ,true表示支持基于类生成 这样需要用到cglib false表示基于接口生成 ,我们这里是为一个类生成代理切面 ,所以用true 。

运行

 public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                new String[]{"spring.xml"});
        UserService userService = (UserService)applicationContext.getBean("userService");
        userService.login();

    }

运行结果如下
在这里插入图片描述

这个时候去看userService
会发现这个对象并不是我们创建的UserService对象,而是一个新的对象,这个对象是用cglib生成的 UserService的代理对象。
在这里插入图片描述
那么接下来分析,是在什么时候进行的生成和替换。
那么就需要debug一步步看了,这里介绍下看源码的技巧,因为很多时候新手看源码都会被绕晕。
看源码的技巧
添加链接描述

点进去之后,看到getSingleton里面返回的就是我们的要的cglib代理对象
在这里插入图片描述
沿着以上思路一路找下去 会发现 ,在this.singletonObjects.get(beanName) 里面取出来的时候就已经是一个代理类了。
在这里插入图片描述
而singletonObjects 是一个map
在这里插入图片描述

意味着早在get之前,代理类就已经被初始化好了并放到了map里面,用到的时候再去get。

也就是说,在Spring容器初始化之后,这个代理类的bean就已经生成了,而不是在我们真正去使用的时候才生成。

那什么时候时候生成的代理类?
全局搜this.singletonObjects.put 可以找到一段代码,在这里加上条件断点,然后启动看下

在这里插入图片描述

当断点进来之后,看到调用栈
在这里插入图片描述

可以看到,在main函数的开始,一层层的调用栈。
选择中间的位置,进去之后打上断点,重启再看下

这一步还没变化
在这里插入图片描述

这一步就变化了
在这里插入图片描述

因此
getObjectForBeanInstance(sharedInstance, name, beanName, null) 这个方法里面发生了将对象转为代理对象的变化

里面继续追踪
在这里插入图片描述

createBean 返回的就是代理类
在这里插入图片描述一路往下看,经过n个弯之后,在DefaultAopProxyFactory里面的createAopProxy会返回具体的AopProxy ,然后调用其getProxy()方法就会返回代理对象。

在这里插入图片描述

在这里插入图片描述

流程非常长,因此省略了不少地方,主要是追踪源码的方式和要非常的耐心。

流程如下:

  • org.springframework.context.support.ClassPathXmlApplicationContext#ClassPathXmlApplicationContext(java.lang.String...)
  • 创建一个新的ClassPathXmlApplicationContext,从给定的XML文件加载bean并自动刷新上下文
  • org.springframework.context.support.AbstractApplicationContext#refresh
  • 加载或刷新容器
  • org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
  • 完成bean工厂的初始化和所有的单例bean
  • org.springframework.beans.factory.config.ConfigurableListableBeanFactory#preInstantiateSingletons
  • 确保所有非lazyinit单例都被实例化
  • org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)
  • 返回一个可以共享或独立于指定bean的实例
  • org.springframework.beans.factory.support.AbstractBeanFactory#createBean
  • bean的创建
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
  • 工厂回调、init方法和bean后处理器初始化给定的bean
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
  • 将链接BeanPostProcessor BeanPostProcessors应用到给定的现有bean实例中,调用它们的代码后置处理初始化方法。返回的bean实例可以是围绕原始的包装器。
  • org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
  • 如果子类将bean标识为一个代理,则使用配置的侦听器创建一个代理
  • org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
  • 必要时包装给定的bean(如有资格代理)
  • org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
  • 为给定的bean创建AOP代理
  • org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)
  • 根据此工厂中的设置创建新代理对象
  • org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
  • 创建给定的AOP代理工厂实例
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值