最近在研究 Spring 源碼,Spring 最核心的功能就是 IOC 容器
和 AOP
。本文定位是以最簡的方式,分析 Spring AOP 源碼。html
上面的思惟導圖可以歸納了 Spring AOP,其最重要的是 Spring AOP 只能做用於 Bean
,而 AspectJ 可以在編譯期、類加載期對字節碼進行更改。java
Spring AOP 的實現原理是動態代理
,可是具體又是怎麼實現的呢?git
在 Spring 容器中,咱們使用的每一個 bean 都是 BeanDefinition 的實例,容器會在合適的時機根據 BeanDefinition 的基本信息實例化 bean 對象。github
因此比較簡單的作法是,Spring 會自動生成代理對象的代理類。咱們在獲取 bean 時,Spring 容器返回代理類對象,而不是實際的 bean。web
本文使用的代碼,安裝了 lombok
,並基於 Spring Boot
,是一個徹底基於註解的最簡調試代碼。spring
註解配置類 AopConfig:express
@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:api
@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:app
INFO 96257 --- [io-11111-exec-1] com.life.demo.AopConfig : this is point cut...
驗證出成功配置了代理。
@Pointcut("execution(* transfer(..))")// the pointcut expression private void anyOldTransfer() {}// the pointcut signature
@Pointcut 中使用了 execution 來正則匹配方法簽名,這也是最經常使用的,除了 execution,咱們再看看其餘的幾個比較經常使用的匹配方式:
如 @Pointcut("within(com.javadoop.springaoplearning.service..*)")
如 @Pointcut("execution(* .(..)) && @annotation(com.javadoop.annotation.Subscribe)")
如 @Pointcut("bean(*Service)")
Tips:上面匹配中,一般 "." 表明一個包名,".." 表明包及其子包,方法參數任意匹配使用兩個點 ".."。
@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() 調用。
在建立 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()); }
@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!