源码分析之前,先搭建源码分析环境这里引用的是org.springframework4.3.12.RELEASE版本分析的,debug之前github上下载相关源码–地址 打断点的位置如下标注,同时,为了查看AbstractAutoProxyCreator代理对象创建器的处理逻辑,在其postProcessBeforeInstantiation与postProcessAfterInitialization方法处打上断点。
@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {
//业务逻辑类加入容器中
@Bean
public MathCalculator calculator(){
//设置断点
return new MathCalculator();
}
//切面类加入到容器中
@Bean
public LogAspects logAspects(){
//设置断点
return new LogAspects();
}
}
/**
* 切面类
* @Aspect: 告诉Spring当前类是一个切面类
*
*/
@Aspect
public class LogAspects {
//抽取公共的切入点表达式
//1、本类引用
//2、其他的切面引用
@Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))")
public void pointCut(){};
//@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入)
@Before("pointCut()")
public void logStart(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
System.out.println(""+joinPoint.getSignature().getName()+"运行。。。@Before:参数列表是:{"+Arrays.asList(args)+"}");
}
@After("com.atguigu.aop.LogAspects.pointCut()")
public void logEnd(JoinPoint joinPoint){
System.out.println(""+joinPoint.getSignature().getName()+"结束。。。@After");
}
//JoinPoint一定要出现在参数表的第一位
@AfterReturning(value="pointCut()",returning="result")
public void logReturn(JoinPoint joinPoint,Object result){
System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:{"+result+"}");
}
@AfterThrowing(value="pointCut()",throwing="exception")
public void logException(JoinPoint joinPoint,Exception exception){
System.out.println(""+joinPoint.getSignature().getName()+"异常。。。异常信息:{"+exception+"}");
}
}
public class MathCalculator {
public int div(int i,int j){
//设置断点
System.out.println("MathCalculator...div...");
return i/j;
}
}
public class IOCTest_AOP {
@Test
public void test01(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);
//1、不要自己创建对象
// MathCalculator mathCalculator = new MathCalculator();
// mathCalculator.div(1, 1);
MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);
//设置断点
mathCalculator.div(1, 0);
applicationContext.close();
}
}
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
执行debug方法,进入断点

现在来分析调用栈
首先分析refresh中的finishBeanFactoryInitialization方法,此方法主要是完成BeanFactory初始化工作;创建剩下的单实例bean,创建代理对象也是通过此方法实现的,仔细观察下一步调用栈







因为我们主要是查看代理对象的生成过程,所以只用查看这个代理对象生成器的前置与后置方法即可。
代理对象生成器前置处理逻辑
debug到bean为我们要调试的对象calculator,发现postProcessBeforeInstantiation方法返回的是空,其实主要逻辑是postProcessAfterInitialization方法处理的,但是我们可以看看前置处理器的逻辑
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
//判断当前bean是否在advisedBeans中(保存了所有需要增强bean)
if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
//判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean,或者是否是切面(@Aspect)
//获取候选的增强器(切面里面的通知方法)【List<Advisor> candidateAdvisors】每一个封装的通知方法的增强器是InstantiationModelAwarePointcutAdvisor;判断每一个增强器是否是 AspectJPointcutAdvisor 类型的;返回true
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
if (beanName != null) {
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
this.targetSourcedBeans.add(beanName);
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
}
return null;
}
因为前置处理器返回空,所以又回到这里,要执行创建bean的逻辑


继续debug断点,next就到了真正返回代理对象的逻辑上了,代理对象生成器的postProcessAfterInitialization方法
这里主要看wrapIfNecessary方法

后面就不一一debug截图了,有兴趣可以试试,这里直接写流程吧,比较简单
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
//和刚才的那个befor的前置处理器一样,返回false
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
//获取当前bean的所有增强器(通知方法) Object[] specificInterceptors
// 1、找到候选的所有的增强器(找哪些通知方法是需要切入当前bean方法的)
// 2、获取到能在bean使用的增强器。
// 3、给增强器排序
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
//保存当前bean在advisedBeans中;
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//如果当前bean需要增强,创建当前bean的代理对象;
// 1)、获取所有增强器(通知方法)
// 2)、保存到proxyFactory
// 3)、创建代理对象:Spring自动决定
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
//
this.proxyTypes.put(cacheKey, proxy.getClass());
//给容器中返回当前组件使用cglib增强了的代理对象;
//以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
这里面可以看到的一点是,如果类有接口,spring是会创建jdk的动态代理对象的

总结:


1万+

被折叠的 条评论
为什么被折叠?



