SpringAOP源码走读

Spring AOP源码走读

简介

Spring的两大核心就是IOC和AOP,了解其机制可以有效的提高我们对于spring的理解和运用。在上一篇SpringIOC源码走读中我们已经大致了解了Spring IOC的原理。现在我们可以继续学习一下AOP了,因为AOP的实现其实也是依赖于IOC的。为了方便起见,这里我们使用注解式的方式。

spring aop面向切面编程的实际就是对bean进行代理,并把代理对象交给spring管理。
spring代理对象的方式有两种java动态代理和cglib代理。

准备工作

导入AOP相关依赖,这里不赘述

定义一个切面类和通知类

public class Calculate {
    public int add(int a, int b) {
        System.out.println("invoke Calculate.add()");
        return a + b;
    }
}

很简单,就是一个加法,打印一条语句便于查看方法运行。

@Aspect
public class CalculateAdvisor {
    @Pointcut("execution(public int com.liyanan.springmvc.Calculate.add(..))")
    public void pointCut() {}
    @Before("pointCut()")
    public void before(JoinPoint joinPoint) {
        System.out.println(String.format("before method [%s], args[%d,%d]"
                , joinPoint.getSignature(), joinPoint.getArgs()[0], joinPoint.getArgs()[1]));
    }
    @After("pointCut()")
    public void after(JoinPoint joinPoint) {
        System.out.println(String.format("after method [%s], args[%d,%d]"
                , joinPoint.getSignature(), joinPoint.getArgs()[0], joinPoint.getArgs()[1]));
    }
}

使用@Aspect告知Spring这是一个通知类,使用@Pointcut定义切入点。使用@Before等定义前置通知等等。
spring aop有五种通知形式:
1.@Before 前置通知
2.@After 后置通知
3.@AfterReturning 返回通知
4.@AfterThrowing 异常通知
5.@Around 环绕通知

这里我们就使用前置和后置两个简单的通知。

定义Configuration java配置类

@EnableAspectJAutoProxy
@Component
public class CalculateConfiguration {
    @Bean
    public Calculate calculate() {
        return new Calculate();
    }
    @Bean
    public CalculateAdvisor calculateAdvisor() {
        return new CalculateAdvisor();
    }
}

@Component表示这是一个java配置类,没有使用过的朋友可以把它当成一个spring xml配置文件中的根标签。里面的@Bean告知spring容器要注入这个bean,可以当成spring xml中的标签。
@EnableAspectJAutoProxy表示spring开启代理。

编写单元测试

public class CalculateTest {
    @Test
    public void testAdd() {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(CalculateConfiguration.class);
        Calculate calculate = context.getBean(Calculate.class);
        calculate.add(1, 2);
    }
}

运行结果

before method [int com.liyanan.springmvc.Calculate.add(int,int)], args[1,2]
invoke Calculate.add()
after method [int com.liyanan.springmvc.Calculate.add(int,int)], args[1,2]
可以看到,虽然我们从context中获取的是calculate对象,但是运行后的结果是我们的通知成功的被织入了。

开始阅读源码

SpringAOP的核心@EnableAspectJAutoProxy

点进去EnableAspectJAutoProxy我们可以发现@Import(AspectJAutoProxyRegistrar.class),说明EnableAspectJAutoProxy注解导入了AspectJAutoProxyRegistrar这个类对象。

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
			AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
		}
		if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
			AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
		}
	}
}

他通过AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary()向容器中注入一个name为internalAutoProxyCreator的AnnotationAwareAspectJAutoProxyCreator类对象。

也就是AOP的核心处理逻辑在AnnotationAwareAspectJAutoProxyCreator中。

梳理AnnotationAwareAspectJAutoProxyCreator的继承关系如下:

  • ==> {@link org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator}
  •  ==> {@link org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator}
    
  •      ==> {@link org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator}
    
  •          ==> {@link org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator}
    
  •              ==> {@link org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor}
    
  •                  ==> {@link org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor}
    
  •                      ==> {@link org.springframework.beans.factory.config.BeanPostProcessor}
    

可以看出AnnotationAwareAspectJAutoProxyCreator其实就是一个bean后置处理器, 根据我们在上一篇Spring IOC的源码可以知道,beanPostProcessor是在bean初始化前后对bean进行一些我们想要的操作。所以我们可以追踪后置处理器的前处理方法和后处理方法
我们找到AbstractAutoProxyCreator重写了postProcessAfterInitialization后置处理方法。可以在这里打上断点追踪。

跟踪上面的断点,可以看到在spring ioc注入Calculate对象的时候,
AbstractAutowireCapableBeanFactory#initializeBean(String, Object, org.springframework.beans.factory.support.RootBeanDefinition)
执行AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization(Object, String)后置bean后置处理器方法。

代理逻辑:
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
postProcessAfterInitialization

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (!this.earlyProxyReferences.contains(cacheKey)) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

wrapIfNecessary

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;
		}
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

createProxy

	protected Object createProxy(
			Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);
		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);
		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}
		return proxyFactory.getProxy(getProxyClassLoader());
	}

buildAdvisors 找到所有用于该对象的通知

proxyFactory.getProxy(getProxyClassLoader()) 获取代理对象

public Object getProxy(ClassLoader classLoader) {
   	return createAopProxy().getProxy(classLoader);
   }

createAopProxy()确定使用cglib还是jdk动态代理生成代理对象

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
	@Override
	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);
		}
	}

从这里可以看出spring判断Calculate是否实现接口,如果实现优先使用java动态代理生成代理对象,否则使用cglib代理对象

总结

Spring AOP的核心就是AnnotationAwareAspectJAutoProxyCreator这个后置处理器在创建bean对象的时候在后置处理方法中对该bean对象进行代理,最后吧代理对象返回交给Spring容器

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值