關(guān)于Spring源碼深度解析(AOP功能源碼解析)
前言
有關(guān)于Spring,我們最常用的兩個功能就是IOC和AOP,前幾篇文章從源碼級別介紹了Spring容器如何為我們生成bean及bean之間的依賴關(guān)系
下面我們接著來看AOP的源碼實(shí)現(xiàn)。
有關(guān)于AOP,我們在面試中也被無數(shù)次問到,AOP是什么?AOP有什么作用與優(yōu)勢?AOP在項(xiàng)目中是如何用到的?
這些還都是比較簡單的,有些可能會問你AOP的實(shí)現(xiàn)是怎樣的?
哪怕沒有看過源碼的同學(xué)也應(yīng)該知道,AOP是通過動態(tài)代理實(shí)現(xiàn)的,動態(tài)代理又分為兩個部分:JDK動態(tài)代理和CGLIB動態(tài)代理
確實(shí),Spring也就是通過這兩種方式來實(shí)現(xiàn)AOP相關(guān)功能,下面就通過源碼來簡單求證下
1.AOP功能簡單實(shí)現(xiàn)
1)引入maven依賴(筆者使用SpringBoot開發(fā))
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> </parent> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
2)創(chuàng)建接口及其實(shí)現(xiàn)類
public interface Person { void say(); } public class Student implements Person{ public void say(){ System.out.println("這是一個苦逼的程序員"); } }
3)創(chuàng)建切面類
@Aspect public class AspectJTest { @Pointcut("execution(* *.say(..))") public void test(){} @Before("test()") public void before(){ System.out.println("before test.."); } @After("test()") public void after(){ System.out.println("after test.."); } @Around("test()") public Object around(ProceedingJoinPoint p){ System.out.println("before1"); Object o = null; try { o = p.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("after1"); return o; } }
4)創(chuàng)建beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <aop:aspectj-autoproxy/> <bean id="student" class="test.Student"/> <bean class="test.AspectJTest"/> </beans>
5)測試類
public class Test { public static void main(String[] args) { ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml"); Person bean2 = (Person)ac.getBean("student"); bean2.say(); } // 結(jié)果如下: before1 before test.. 這是一個苦逼的程序員 after1 after test..
總結(jié):AOP功能的使用還是比較簡單的,把相關(guān)bean注入到Spring容器中,編寫好相應(yīng)的Aspect類即可
2.寫在分析AOP功能源碼之前
1)在使用ApplicationContext相關(guān)實(shí)現(xiàn)類加載bean的時候,會針對所有單例且非懶加載的bean,在構(gòu)造ApplicationContext的時候就會創(chuàng)建好這些bean,而不會等到使用的時候才去創(chuàng)建。這也就是單例bean默認(rèn)非懶加載的應(yīng)用
2)讀者需要了解BeanPostProcessor的相關(guān)使用,所有實(shí)現(xiàn)BeanPostProcessor接口的類,在初始化bean的時候都會調(diào)用這些類的方法,一般用于在bean初始化前或后對bean做一些修改。而AOP的功能實(shí)現(xiàn)正式基于此,在bean初始化后創(chuàng)建針對該bean的proxy,然后返回給用戶該proxy
3)結(jié)合以上兩點(diǎn),被代理后的bean,實(shí)際在ApplicationContext構(gòu)造完成之后就已經(jīng)被創(chuàng)建完成,getBean()的操作直接從singletonObjects中獲取即可
3.AOP源碼架構(gòu)分析
1)尋找 <aop:aspectj-autoproxy/> 注解對應(yīng)的解析器
但凡注解都有對應(yīng)的解析器,以用來解析該注解的行為。全局搜索之后可發(fā)現(xiàn)
org.springframework.aop.config.AopNamespaceHandler類中有對應(yīng)的解析行為,代碼如下: public class AopNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { // In 2.0 XSD as well as in 2.1 XSD. registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());// 就是該段代碼 registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator()); // Only in 2.0 XSD: moved to context namespace as of 2.1 registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); } }
2)了解AspectJAutoProxyBeanDefinitionParser對應(yīng)的行為
class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser { @Override public BeanDefinition parse(Element element, ParserContext parserContext) { // 1.注冊proxy creator AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element); extendBeanDefinition(element, parserContext); return null; } ... // registerAspectJAnnotationAutoProxyCreatorIfNecessary() public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary( ParserContext parserContext, Element sourceElement) { // 注冊行為主要內(nèi)容 BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary( parserContext.getRegistry(), parserContext.extractSource(sourceElement)); useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); registerComponentIfNecessary(beanDefinition, parserContext); } // registerAspectJAnnotationAutoProxyCreatorIfNecessary() public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) { // 主要就是為了注冊AnnotationAwareAspectJAutoProxyCreator類 return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); } // 注冊類相關(guān)代碼 private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); if (!cls.getName().equals(apcDefinition.getBeanClassName())) { int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); if (currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); } } return null; } // 類似于我們在使用BeanFactory.getBean()時候的操作,生成一個RootBeanDefinition,然后放入map中 RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; }
總結(jié):通過以上的代碼分析,可知,AspectJAutoProxyBeanDefinitionParser主要的功能就是將AnnotationAwareAspectJAutoProxyCreator注冊到Spring容器中,把bean交給Spring去托管。
AnnotationAwareAspectJAutoProxyCreator的功能我們大膽猜測一下:應(yīng)該也就是生成對象的代理類的相關(guān)功能,這個我們接下來再看。
問題:
那么問題來了,我們最開始的類AopNamespaceHandler.init()方法是在什么時候被調(diào)用的呢?什么時候生效的?這個決定了我們注冊到Spring的AnnotationAwareAspectJAutoProxyCreator的生效時間?讀者可自行思考下。
3)分析AnnotationAwareAspectJAutoProxyCreator主要行為
通過查看AnnotationAwareAspectJAutoProxyCreator的類層次結(jié)構(gòu),可知,其實(shí)現(xiàn)了BeanPostProcessor接口,實(shí)現(xiàn)類為AbstractAutoProxyCreator
類層次結(jié)構(gòu)如下:
4)AbstractAutoProxyCreator主要方法
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) { return bean; } // 主要看這個方法,在bean初始化之后對生產(chǎn)出的bean進(jìn)行包裝 @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } // wrapIfNecessary protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (beanName != null && 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. // 意思就是如果該類有advice則創(chuàng)建proxy, Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); // 1.通過方法名也能簡單猜測到,這個方法就是把bean包裝為proxy的主要方法, Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); // 2.返回該proxy代替原來的bean return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
總結(jié):
1)通過AspectJAutoProxyBeanDefinitionParser類將AnnotationAwareAspectJAutoProxyCreator注冊到Spring容器中
2)AnnotationAwareAspectJAutoProxyCreator類的postProcessAfterInitialization()方法將所有有advice的bean重新包裝成proxy
4.創(chuàng)建proxy過程分析
通過之前的代碼結(jié)構(gòu)分析,我們知道,所有的bean在返回給用戶使用之前都需要經(jīng)過AnnotationAwareAspectJAutoProxyCreator類的postProcessAfterInitialization()方法,而該方法的主要作用也就是將所有擁有advice的bean重新包裝為proxy,那么我們接下來直接分析這個包裝為proxy的方法即可,看一下bean如何被包裝為proxy,proxy在被調(diào)用方法時,是具體如何執(zhí)行的
以下是AbstractAutoProxyCreator.wrapIfNecessary(Object bean, String beanName, Object cacheKey)中的createProxy()代碼片段分析
protected Object createProxy( Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } // 1.創(chuàng)建proxyFactory,proxy的生產(chǎn)主要就是在proxyFactory做的 ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { evaluateProxyInterfaces(beanClass, proxyFactory); } } // 2.將當(dāng)前bean適合的advice,重新封裝下,封裝為Advisor類,然后添加到ProxyFactory中 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); for (Advisor advisor : advisors) { proxyFactory.addAdvisor(advisor); } proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } // 3.調(diào)用getProxy獲取bean對應(yīng)的proxy return proxyFactory.getProxy(getProxyClassLoader()); }
1)創(chuàng)建何種類型的Proxy?JDKProxy還是CGLIBProxy?
// getProxy()方法 public Object getProxy(ClassLoader classLoader) { return createAopProxy().getProxy(classLoader); } // createAopProxy()方法就是決定究竟創(chuàng)建何種類型的proxy protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } // 關(guān)鍵方法createAopProxy() return getAopProxyFactory().createAopProxy(this); } // createAopProxy() public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { // 1.config.isOptimize()是否使用優(yōu)化的代理策略,目前使用與CGLIB // config.isProxyTargetClass() 是否目標(biāo)類本身被代理而不是目標(biāo)類的接口 // hasNoUserSuppliedProxyInterfaces()是否存在代理接口 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."); } // 2.如果目標(biāo)類是接口或者是代理類,則直接使用JDKproxy if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } // 3.其他情況則使用CGLIBproxy return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } }
2)getProxy()方法
由1)可知,通過createAopProxy()方法來確定具體使用何種類型的Proxy
針對于該示例,我們具體使用的為JdkDynamicAopProxy,下面來看下JdkDynamicAopProxy.getProxy()方法
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable// JdkDynamicAopProxy類結(jié)構(gòu),由此可知,其實(shí)現(xiàn)了InvocationHandler,則必定有invoke方法,來被調(diào)用,也就是用戶調(diào)用bean相關(guān)方法時,此invoke()被真正調(diào)用 // getProxy() public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); } Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); // JDK proxy 動態(tài)代理的標(biāo)準(zhǔn)用法 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }
3)invoke()方法
以上的代碼模式可以很明確的看出來,使用了JDK動態(tài)代理模式,真正的方法執(zhí)行在invoke()方法里,下面我們來看下該方法,來看下bean方法如何被代理執(zhí)行的
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation invocation; Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; Class<?> targetClass = null; Object target = null; try { // 1.以下的幾個判斷,主要是為了判斷method是否為equals、hashCode等Object的方法 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { // The target does not implement the equals(Object) method itself. return equals(args[0]); } else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { // The target does not implement the hashCode() method itself. return hashCode(); } else if (method.getDeclaringClass() == DecoratingProxy.class) { // There is only getDecoratedClass() declared -> dispatch to proxy config. return AopProxyUtils.ultimateTargetClass(this.advised); } else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { // Service invocations on ProxyConfig with the proxy config... return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal; 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 = targetSource.getTarget(); if (target != null) { targetClass = target.getClass(); } // 2.獲取當(dāng)前bean被攔截方法鏈表 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // 3.如果為空,則直接調(diào)用target的method if (chain.isEmpty()) { Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } // 4.不為空,則逐一調(diào)用chain中的每一個攔截方法的proceed else { // We need to create a method invocation... invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. retVal = invocation.proceed(); } ... return retVal; } ... }
4)攔截方法真正被執(zhí)行調(diào)用invocation.proceed()
public Object proceed() throws Throwable { // We start with an index of -1 and increment early. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // Evaluate dynamic method matcher here: static part will already have // been evaluated and found to match. InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // Dynamic matching failed. // Skip this interceptor and invoke the next in the chain. return proceed(); } } else { // It's an interceptor, so we just invoke it: The pointcut will have // been evaluated statically before this object was constructed. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
總結(jié)4:依次遍歷攔截器鏈的每個元素,然后調(diào)用其實(shí)現(xiàn),將真正調(diào)用工作委托給各個增強(qiáng)器
心得
縱觀以上過程可知:實(shí)際就是為bean創(chuàng)建一個proxy,JDKproxy或者CGLIBproxy,然后在調(diào)用bean的方法時,會通過proxy來調(diào)用bean方法
重點(diǎn)過程可分為:
1)通過AspectJAutoProxyBeanDefinitionParser類將AnnotationAwareAspectJAutoProxyCreator注冊到Spring容器中
2)AnnotationAwareAspectJAutoProxyCreator類的postProcessAfterInitialization()方法將所有有advice的bean重新包裝成proxy
3)調(diào)用bean方法時通過proxy來調(diào)用,proxy依次調(diào)用增強(qiáng)器的相關(guān)方法,來實(shí)現(xiàn)方法切入
總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Netty分布式高性能工具類FastThreadLocal和Recycler分析
這篇文章主要為大家介紹了Netty分布式高性能工具類FastThreadLocal和Recycler分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03SpringBoot中YAML語法及幾個注意點(diǎn)說明
這篇文章主要介紹了SpringBoot中YAML語法及幾個注意點(diǎn)說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02