使用的是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方法的第二行