一.实现的原理简介
1.我们都只知道AOP是基于代理模式来实现的,这里我们来思考spring是如何基于动态代理来实现AOP?通过分析,他实现的大概的流程如下图:
接着,我们用代码来实现一个基于注解模式的简单的spring AOP,代码如下:
import org.springframework.stereotype.Component;
/**
* @author zhouyongquan
* @date 2019/10/21 上午11:15
* @description
*/
@Component
public class MicAop {
public void micWork() {
System.out.println("I do something");
}
}
/**
* @author zhouyongquan
* @date 2019/10/21 上午11:07
* @description
*/
@Component
@Aspect
public class MicAopConfig {
/**
* 配置切入点,理解:@Pointcut里面配置类被拦截的代理的对象的方法
*/
@Pointcut("execution(* mic.com.MicAop..*(..))")
public void micPointcut() {
}
/**
* 配置切面,理解:在这些切入点被调用前,我们统一做了什么的操作,一个切面
*/
@Before("micPointcut()")
public void micDoBefore() {
System.out.println("micDoBefore");
}
}
这样,在MicAop#micWork之前,就会执行切面micDoBefore的逻辑。
二.基于上面的流程,分析具体的实现原理
1.首先,我们需要报MicAopConfig里面配置的内容保存到BeanFactory里面,这个过程涉及到切面的解析。
(1)实现代理的关键的源头是:AnnotionAwareAspactAutoProxy这类,我们先来看看他的继承结构:
AnnotionAwareAspactAutoProxyCreator 继承了BeanPostProcessor,BeanPostProcessor这个里的实现类类里面有很多执行处理节点,其中一个节点就是关于Bean实例化之后的,AnnotionAwareAspactAutoProxyCreator 做的就是在Bean初始化的时候进行拦截,根据提前解析好的切面信息,对bean里面的方法进行匹配,如果匹配成功,则进行代理对象的创建。
(2)我们首先来分析AnnotionAwareAspactAutoProxyCreator ,在bean第一次实例化的时候,就会解析保存AOP的信息到实例中。
跟踪下面两个方法:
AbstractApplicationContext#refresh(bean初始化上下文的主干方法)、AbstractApplicationContext#registerBeanPostProcessors(执行实例化并保存所有实现BeanPostProcessor接口的类)
AnnotationAwareAspectJAutoProxyCreator是继承了BeanfactoryAware接口,所以在实例化时,会执行setFactory方法。而所有切面信息解析的执行者BeanFactoryAspectJAdvisorsBuilderAdapter初始化的时机也是在setFactory方法。
跟踪方法:
AnnotationAwareAspectJAutoProxyCreator#initBeanFactory
源码:
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
if (this.aspectJAdvisorFactory == null) {
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
}
this.aspectJAdvisorsBuilder =
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}
BeanFactoryAspectJAdvisorsBuilderAdapter这个实例会根据BeanFactory里面保存的AOP的信息进行解析保存,但是马上执行,他是在第一次初始化bean实力的时候,才会解析保存AOP配置信息。解析BeanFactory里面保存的AOP信息的方法是:BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors,他会在初次执行AnnotationAwareAspectJAutoProxyCreator调用postProcessBeforeInitialization时开始执行。
(2)解析保存AOP配置信息,需要解析缓存切面
InstantiationAwareBeanPostProcessor接口定义的postProcessBeforeInitialization方法是一个可以对已经注入依赖属性的bean对象实例进行编辑操作的接口,我们会在AbstractAutowireCapableBeanFactory#doCreateBean、AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)、AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation这几个方法里面调用到。在postProcessBeforeInitialization里面,会进行初次缓存切面信息。
进入InstantiationAwareBeanPostProcessor#postProcessBeforeInitialization方法分析代码。
AbstractAutoProxyCreator#postProcessBeforeInstantiation、
AspectJAwareAdvisorAutoProxyCreator#shouldSkip
进入如下代码AbstractAutoProxyCreator,这个实例也就是之前一开始初始化的AnnotationAwareAspectJAutoProxyCreator实例,进入实例的shouldSkip 方法。
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
//预先解析好缓存好的切面信息
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//遍历切面信息
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
进入预先解析好缓存好的切面信息的findCandidateAdvisors()方法
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
//所有切面的调用点
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
findCandidateAdvisors()方法负责预想解析切面信息,并且会进行缓存。
那么问题来了,首先它是如何进行解析的?
我们来看看这个调用:aspectJAdvisorsBuilder.buildAspectJAdvisors()
他的源码如下:
/**
* Look for AspectJ-annotated aspect beans in the current bean factory,
* and return to a list of Spring AOP Advisors representing them.
* <p>Creates a Spring Advisor for each AspectJ advice method.
* @return the list of {@link org.springframework.aop.Advisor} beans
* @see #isEligibleBean
*/
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
//1.首先获取bean的名字
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
//2.判断bean的类型是不是切面类型
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//3.如果是切面,就解析AOP配置,返回Advisor对象集合
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
判断是不是切面的方法源码:
@Override
public boolean isAspect(Class<?> clazz) {
//就是判断右面@Aspect这个注解
return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}
接着,我们关心他是如何解析等到Advisor对象集合的?
我们关注这两个过程
MetadataAwareAspectInstanceFactory factory =new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//获取Advisor对象集合
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
for (Method method : getAdvisorMethods(aspectClass)) {
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
///解析判断候选方法是否有@Before,@After,@Around等注解,如果有,就继续执行新建Advisor对象。
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
getAdvisor 遍历所有没被@PointCut注解标注的方法,获取有@Before,@After,@Around等注解的方法。
新建的Advisor都会保存在BeanFactoryAspectJAdvisorsBuilder#advisorsCache这个缓存里面,AnnotionAwareAspactAutoProxy在bean初始化的时候,需要在这个预先设置的切面缓存里面,进行匹配,匹配中了,才会进行代理对象的创建。
到目前为止的Advisor里面并没有对@PointCut注解进行处理。
追中代码,我们发现AnnotationAwareAspectJAutoProxyCreator#postProcessAfterInstantiation第一次执行时解析拦截表达式。
(3)接下来就是选择适配的切面了
在AbstractAutoProxyCreator#postProcessAfterInitialization时,会找到在缓存好的所有切面的信息,会进行切面适配,适配成功会创建代理对象,分析以下两个方法
AbstractAutoProxyCreator#postProcessAfterInitialization、
AbstractAutoProxyCreator#wrapIfNecessary
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && 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;
}
// Create proxy if we have advice.
//查找适配的切面
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;
}
分析查找适配切面的方法:Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
源码如下:
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
//从缓存里面取出所有的切面信息
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//根据advisor信息中的表达式进行方法对class的匹配
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
findEligibleAdvisors方法会取出切面缓存,然后根据advisor信息中的表达式进行方法对class的匹配,如果是第一次findAdvisorsThatCanApply方法的话,他的@Pointcut里面的信息并没有保存初始化,这时候,就需要初始化@Pointcut的信息,在findAdvisorsThatCanApply的时候,他就会初始化@Pointcut的值
方法调用链如下:
AopUtils#findAdvisorsThatCanApply(candidateAdvisors, beanClass);
AopUtils#canApply(Advisor advisor, Class<?> targetClass);
AspectJExpressionPointcut#getClassFilter
AspectJExpressionPointcut#checkReadyToMatch
源码如下:
private void checkReadyToMatch() {
if (getExpression() == null) {
throw new IllegalStateException("Must set property 'expression' before attempting to match");
}
if (this.pointcutExpression == null) {
this.pointcutClassLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
ClassUtils.getDefaultClassLoader());
//解析得到拦截表达式,例如根据@Before的value来关联查询出对应的表达式
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
}
}
匹配时就根据pointcutExpression循环进行匹配class的方法
(4)创建代理对象
如果发现有适配的切面,那么,我们需要创建代理对象,创建代理对象,我们还是回到wrapIfNecessary这个方法
部门源码如下:
// Create proxy if we have advice.
//1.首先查找匹配的切面
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, @Nullable String beanName,
@Nullable 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());
}
分析proxyFactory.getProxy(getProxyClassLoader());方法,他是如何创建代理对象的:
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
@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)) {
//基于JDK的方式来创建动态代理对象
return new JdkDynamicAopProxy(config);
}
//基于cglib方式来创建动态代理对象。
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
使用cglib代理,代理如下:
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
}
try {
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class<?> proxySuperClass = rootClass;
if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// Validate the class, writing log messages as necessary.
validateClassIfNecessary(proxySuperClass, classLoader);
// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
//获取拦截回调函数
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
//返回一个cglib代理对象
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
普通AOP采用的回调函数
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
cglib 的aop回调函数如下
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
//这里注入的advised就是之前创建的ProxyFactory对象
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool...
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
//根据切面信息创建切面内容调用链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
//创建一个方法调用对象,具体调用实现没分析,Before逻辑大概是先调用切面,在反射调用目标方法
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}