乐趣区

关于java:最简-Spring-AOP-源码分析

前言

最近在钻研 Spring 源码,Spring 最外围的性能就是 IOC 容器 AOP。本文定位是以最简的形式,剖析 Spring AOP 源码。

基本概念

下面的思维导图可能概括了 Spring AOP,其最重要的是 Spring AOP 只能作用于 Bean,而 AspectJ 可能在编译期、类加载期对字节码进行更改。

猜想实现原理

Spring AOP 的实现原理是 动静代理,然而具体又是怎么实现的呢?

在 Spring 容器中,咱们应用的每个 bean 都是 BeanDefinition 的实例,容器会在适合的机会依据 BeanDefinition 的根本信息实例化 bean 对象。

所以比较简单的做法是,Spring 会主动生成代理对象的代理类。咱们在获取 bean 时,Spring 容器返回代理类对象,而不是理论的 bean。

调试代码

本文应用的代码,装置了 lombok,并基于 Spring Boot,是一个齐全基于注解的最简调试代码。

注解配置类 AopConfig:

@Slf4j
@Component
@Aspect
public class AopConfig {@Pointcut("within(com.life.demo..*)")
    public void pointCut() {}

    @Before("com.life.demo.AopConfig.pointCut()")
    public void log() {log.info("this is point cut...");
    }
}

Spring 启动类 AppApplication:

@SpringBootApplication
@EnableAspectJAutoProxy
public class AppApplication {public static void main(String[] args) {SpringApplication.run(AppApplication.class, args);
    }
}

Controller HelloWorldController:

package com.life.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import lombok.extern.slf4j.Slf4j;

@RestController
@Slf4j
public class HelloWorldController {@GetMapping("/hello")
    public String greeting() {return "hello!";}
}

运行 Web 利用,在浏览器输出网址 http://localhost:11111/hello,会看到 log:

INFO 96257 --- [io-11111-exec-1] com.life.demo.AopConfig                  : this is point cut...

验证出胜利配置了代理。

应用阐明

  1. @EnableAspectJAutoProxy 开启 AOP。
  2. 应用 @Aspect 注解的 bean 都会被 Spring 当做用来实现 AOP 的配置类。
  3. 配置 Advice,不做具体介绍,具体参考 Spring AOP 官网文档。
  4. @Pointcut,用来匹配 Spring 容器中的所有 bean 的办法的。
@Pointcut("execution(* transfer(..))")// the pointcut expression
private void anyOldTransfer() {}// the pointcut signature

@Pointcut 中应用了 execution 来正则匹配办法签名,这也是最罕用的,除了 execution,咱们再看看其余的几个比拟罕用的匹配形式:

  • within:指定所在类或所在包上面的办法(Spring AOP 独有)

如 @Pointcut("within(com.javadoop.springaoplearning.service..*)")

  • @annotation:办法上具备特定的注解,如 @Subscribe 用于订阅特定的事件。

如 @Pointcut("execution(* .(..)) && @annotation(com.javadoop.annotation.Subscribe)")

  • bean(idOrNameOfBean):匹配 bean 的名字(Spring AOP 独有)

如 @Pointcut("bean(*Service)")

Tips:下面匹配中,通常 “.” 代表一个包名,”..” 代表包及其子包,办法参数任意匹配应用两个点 “..”。

源码深入分析

@EnableAspectJAutoProxy 开启 AOP

@EnableAspectJAutoProxy 注解定义:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {boolean proxyTargetClass() default false;
    boolean exposeProxy() default false;}
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

        AnnotationAttributes enableAspectJAutoProxy =
                AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        if (enableAspectJAutoProxy != null) {if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }

}

在 AppApplication 启动类上要退出 @EnableAspectJAutoProxy 注解开启 AOP,查看该注解源码,其 proxyTargetClass() 是在 AspectJAutoProxyRegistrar 类中调用,而 AspectJAutoProxyRegistrar 是一个 ImportBeanDefinitionRegistrar。再往上追根溯源,能够看到是在接口 ConfigurableApplicationContext 中 void refresh() 调用。

IOC 容器治理 AOP 实例

在创立 bean 时,会调用 AbstractAutowireCapableBeanFactory#doCreateBean(…)。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
            throws BeanCreationException {

    // 初始化 bean
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        // 1. 创立实例
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    ...

    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
        // 2. 装载属性
        populateBean(beanName, mbd, instanceWrapper);
        if (exposedObject != null) {
            // 3. 初始化
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
    }
    ...
}

着重看第 3 步 initializeBean(…) 办法:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
        // 执行每个 BeanPostProcessor 的 postProcessAfterInitialization 办法!wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

Spring IOC 容器创立 bean 实例时,最初都会对 bean 进行解决,来实现加强。对于 Spring AOP 来说,就是创立代理类。

下面代码中函数 applyBeanPostProcessorsAfterInitialization(…) 最终调用了 AbstractAutoProxyCreator 实现的 postProcessAfterInitialization() 办法。

/**
 * Create a proxy with the configured interceptors if the bean is
 * identified as one to proxy by the subclass.
 * @see #getAdvicesAndAdvisorsForBean
 */
@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;
}

wrapIfNecessary(...)办法在须要时返回了代理类。

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

    // 1. Create proxy if we have advice.
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 2. 外围!重点!重要!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;
}

上述代码第 1 步 getAdvicesAndAdvisorsForBean(…) 办法是返回某个 beanName 下的 Advice 和 Advisor,如果返回后果不为空的话,才会创立代理。其外围办法就是 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);
    }

    // 1. 获取适合的 ProxyFactory
    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);
    }

    // 2. 创立并返回适合的 AOP 对象
    return proxyFactory.getProxy(getProxyClassLoader());
}

ProxyFactory

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

查看代码最终发现是在 DefaultAopProxyFactory#createAopProxy(…) 办法中实现。

AopProxy 接口的 2 个实现类:CglibAopProxy 和 JdkDynamicAopProxy。这里就不剖析 JdkDynamicAopProxy 类,仅剖析 CglibAopProxy 类。CglibAopProxy 类实现的 getProxy(…) 办法如下:

@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 (ClassUtils.isCglibProxyClass(rootClass)) {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 ClassLoaderAwareUndeclaredThrowableStrategy(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.
        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);
    }
}

CGLIB 生成代理的外围是 Enhancer,详情见 Enhancer API 文档、cglib 官网。

总结

Spring AOP 应用了动静代理,作用于 IOC 容器治理的 bean。在获取 bean 时会依据须要创立代理类,并返回代理类。在 Spring Boot 中应用 Spring AOP 时应该先用 @EnableAspectJAutoProxy 注解开启代理,定义代理类和代理规定,不须要 XML 或其余配置。

Spring 的源码太庞杂,调用链太深,在钻研源码的时候应该明确指标,把握外围原理。就像学汉语字典,并不需要把握其中的每一个汉字(况且 Spring 源码更新频率很快)。

公众号

coding 笔记、点滴记录,当前的文章也会同步到公众号(Coding Insight)中,心愿大家关注 ^_^

代码和思维导图在 GitHub 我的项目中,欢送大家 star!

退出移动版