前言
最近在钻研 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@Aspectpublic 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@EnableAspectJAutoProxypublic 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@Slf4jpublic 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...
验证出胜利配置了代理。
应用阐明
- @EnableAspectJAutoProxy 开启 AOP。
- 应用 @Aspect 注解的 bean 都会被 Spring 当做用来实现 AOP 的配置类。
- 配置 Advice,不做具体介绍,具体参考 Spring AOP 官网文档。
- @Pointcut,用来匹配 Spring 容器中的所有 bean 的办法的。
@Pointcut("execution(* transfer(..))")// the pointcut expressionprivate 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 */@Overridepublic 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
@Overridepublic 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(...) 办法如下:
@Overridepublic 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!