Spring Aop 源码 debug

使用的是spring boot
大致流程 : getSingleton(重点)→singletonFactory.getObject→createBean→doCreateBean(重点)→initizlizeBean→后置处理器(AnnotationAwareAspectjAutoProxyCreator)的处理方法→wrapIfNecessary→createProxy→proxyFactory.getProxy→createAopProxy(重点)

首先是基本配置

pom.xml

<!--aop-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--aspectj-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.6.11</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.6.11</version>
</dependency>
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.1</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.1.7.RELEASE</version>
</dependency>

main方法

@RunWith(SpringRunner.class)
@SpringBootTest
@ComponentScan("com.example.demo")
public class DemoApplicationTests {

    @Test
    public void contextLoads() {
    }

    @Test
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(DemoApplicationTests.class);
        UserDao dao = (UserDao) annotationConfigApplicationContext.getBean("dao");
        dao.query();
    }

}

dao 和 daoImpl

public interface UserDao {
    public void query();
}

@Component("dao")
public class UserDaoImpl implements UserDao {
    @Override
    public void query() {
        System.out.println("I want to ask you a question!");
    }
}

切面类

@Component
@Aspect
public class WebLogAspect {

    @Pointcut("execution(* com.example.demo.Dao..*.*(..))")
    public void sayHello() {

    }

    @Before("sayHello()")
    public void doBefore() {
        System.out.println("before : hello");
    }
}

大致的目录(没有标记的是非相关的)
在这里插入图片描述
实现效果
在这里插入图片描述

Debug流程和思想

aop的实现以代理为基础,要么jdk,要么cglib
如果proxyTargetClass为true,cglib;否则如果有接口,jdk;否则cglib

由上面的main方法可得
要么在容器初始化的时候完成代理
要么getBean的时候完成代理

先测试getBean
在第二行打断点
在这里插入图片描述
进入内部
在这里插入图片描述
再进入getBeanFactory().getBean(name)的getBean方法

在这里插入图片描述
进入doGetBean方法
在这里插入图片描述
已经完成代理
在deGetBean方法中的Object sharedInstance = getSingleton(beanName)已经完成代理;于是在该处打上条件断点(这里有个坑,先到了main方法的第二行再启动这个断点,后续有解释)
在这里插入图片描述
进入getSingleton方法
在这里插入图片描述
其中第一行会直接获得代理对象,说明是在容器初始化时完成代理的。
之后的debug有个技巧,我们可以在map.put方法打个断点。
选择第一个,第三个是相关jndi的
在这里插入图片描述
同样的条件断点beanName.equal(“dao”)
在这里插入图片描述
进入这个断点,分析现象,此时是addSingleton方法
已经完成代理,通过左下角的堆栈查找完成代理的方法
在这里插入图片描述
在getSingleton方法打个条件断点
在这里插入图片描述
进入这个方法
这里没有完成代理
完成代理
于是在singletonObject = singletonFactory.getObject();打上断点,并进入getObject方法,getObject方法会进入createBean方法
在这里插入图片描述

createBean会在doCreateBean方法完成代理
在这里插入图片描述
进入doCreateBean方法,代理在initializeBean方法中完成
在这里插入图片描述
进入initializeBean方法,代理会通过applyBeanPostProcessorsAfterInitialization(后置处理器相关)方法完成
在这里插入图片描述
进入applyBeanPostProcessorsAfterInitialization方法,这的下标4是跟aspectj相关的,也是在这一步完成代理的
在这里插入图片描述
进入i = 4 的postProcessAfterInitialization方法
在这里插入图片描述再进入wrapIfNecessary方法
在这里插入图片描述
再进入createProxy方法
在这里插入图片描述
再进入proxyFroxy.getProxy方法
在这里插入图片描述
getProxy方法会进入createAopProxy方法
在这里插入图片描述
最后的就是这creaetAopProxy方法
如果proxytargetclass = true,使用cglib

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);
   }
}

到此,我要说的基本没了
上面我说
在deGetBean方法中的Object sharedInstance = getSingleton(beanName)已经完成代理;于是在该处打上条件断点(这里有个坑,先到了main方法的第二行再启动这个断点,后续有解释)
是因为在容器初始化时完成代理,那么如果直接在getSingleton打了断点会先执行getSingleton方法,在执行main方法的第二行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值