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

0次阅读

共计 10169 个字符,预计需要花费 26 分钟才能阅读完成。

前言

最近在钻研 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!

正文完
 0