- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) > 編程語(yǔ)言 >
- spring aop底層原理及如何實(shí)現
相信每天工作都要用spring框架的大家一定使用過(guò)spring aop,aop的概念是面向切面編程,相對與傳統的面向對象編程oop,aop更關(guān)注的是橫向的邏輯,比如說(shuō)一個(gè)大型系統中的日志記錄,異常處理,性能監控等等,都是各個(gè)模塊都需要的操作,那樣代表著(zhù)這些操作會(huì )散落在系統的各個(gè)地方,不易管理且雜亂無(wú)章,而aop就是關(guān)注的這些,aop將這些操作與業(yè)務(wù)代碼分離,統一成一個(gè)個(gè)的切面,針對這些個(gè)切面進(jìn)行編程處理。spring aop使得我們的aop開(kāi)發(fā)工作變得簡(jiǎn)單,這次我就給大家講講spring aop的底層原理和實(shí)現
要分析spring aop的底層原理,首先要會(huì )使用,先創(chuàng )建一個(gè)普通maven webapp項目,引入spring-context依賴(lài),版本為5.1.1RELEASE
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.1.RELEASE</version> </dependency>
然后我使用aspectj作為aop的語(yǔ)法實(shí)現,和spring整合起來(lái)
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency>
接下來(lái)我全稱(chēng)用注解的形式來(lái)模擬spring aop的使用,先創(chuàng )建一個(gè)配置類(lèi)去掃描包,開(kāi)啟aspectJ的自動(dòng)代理支持
@Configuration @EnableAspectJAutoProxy @ComponentScan("com.ww") public class Wconfig { }
然后新建一個(gè)接口和接口的實(shí)現類(lèi)
public interface Dao { void query(); } @Component public class IndexDao implements Dao{ @Override public void query() { System.out.println("query......"); } }
創(chuàng )建切面
//代表是一個(gè)切面 @Aspect @Component public class WAspect { /** * execution表達式,可以百度寫(xiě)法 */ @Pointcut("execution(* com.ww.dao.*.*(..))") public void point(){ } /** * 在切點(diǎn)上進(jìn)行前置通知 */ @Before("point()") public void beforeAd(){ System.out.println("before-------------"); } }
創(chuàng )建測試方法
public class TestAspect { public static void main(String[] args) { AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext(Wconfig.class); Dao dao = configApplicationContext.getBean(Dao.class); dao.query(); } }
執行方法,可以看到在打印query...之前打印了before----------
這個(gè)時(shí)候我們很想知道為什么這句before會(huì )打印在query之前呢,稍微對spring aop有所了解的人應該知道,spring是通過(guò)動(dòng)態(tài)代理和字節碼技術(shù)來(lái)實(shí)現aop操作的,也就是經(jīng)常說(shuō)的jdk動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理兩種模式,那么,spring究竟是怎么創(chuàng )建的代理對象,又是什么時(shí)候產(chǎn)生的代理對象呢,下面我們來(lái)一起探究一下源碼,來(lái)揭開(kāi)這個(gè)謎底
首先我們透過(guò)現象看本質(zhì),我先把斷點(diǎn)打在測試方法的最后一行,我們來(lái)看這個(gè)時(shí)候的dao對象
那么接下來(lái)我們就要去找到什么時(shí)候這個(gè)dao對象變成了動(dòng)態(tài)代理對象的,既然在最后一行的時(shí)候對象已經(jīng)變成了代理對象,那么我門(mén)自然就猜想是在上一句代碼的位置spring執行了創(chuàng )建代理對象的操作,我們把斷點(diǎn)移到上一行,debug進(jìn)去
再往下走
這行代碼我看方法名覺(jué)得應該是有用的代碼,方法意思應該是spring處理好的bean,跟進(jìn)去看看
@Nullable private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) { //這行代碼最有用,處理有beanName的bean,debug進(jìn)入看一下 NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull); if (namedBean != null) { return namedBean.getBeanInstance(); } BeanFactory parent = getParentBeanFactory(); if (parent instanceof DefaultListableBeanFactory) { return ((DefaultListableBeanFactory) parent).resolveBean(requiredType, args, nonUniqueAsNull); } else if (parent != null) { ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType); if (args != null) { return parentProvider.getObject(args); } else { return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable()); } } return null; }
@SuppressWarnings("unchecked") @Nullable private <T> NamedBeanHolder<T> resolveNamedBean( ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException { Assert.notNull(requiredType, "Required type must not be null"); Class<?> clazz = requiredType.getRawClass(); Assert.notNull(clazz, "Required type must have a raw Class"); //候選name列表,直覺(jué)告訴我這行代碼比較重要 String[] candidateNames = getBeanNamesForType(requiredType); if (candidateNames.length > 1) { List<String> autowireCandidates = new ArrayList<>(candidateNames.length); for (String beanName : candidateNames) { if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) { autowireCandidates.add(beanName); } } if (!autowireCandidates.isEmpty()) { candidateNames = StringUtils.toStringArray(autowireCandidates); } } //因為我的代碼里只有一個(gè)bean,所以我覺(jué)得應該會(huì )執行這里的代碼 if (candidateNames.length == 1) { String beanName = candidateNames[0]; return new NamedBeanHolder<>(beanName, (T) getBean(beanName, clazz, args)); } else if (candidateNames.length > 1) { Map<String, Object> candidates = new LinkedHashMap<>(candidateNames.length); for (String beanName : candidateNames) { if (containsSingleton(beanName) && args == null) { Object beanInstance = getBean(beanName); candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance)); } else { candidates.put(beanName, getType(beanName)); } } String candidateName = determinePrimaryCandidate(candidates, clazz); if (candidateName == null) { candidateName = determineHighestPriorityCandidate(candidates, clazz); } if (candidateName != null) { Object beanInstance = candidates.get(candidateName); if (beanInstance == null || beanInstance instanceof Class) { beanInstance = getBean(candidateName, clazz, args); } return new NamedBeanHolder<>(candidateName, (T) beanInstance); } if (!nonUniqueAsNull) { throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet()); } } return null; }
執行完getBeanNamesForType(requiredType)后,我們看idea的變量顯示,果然有一個(gè)bean,name是IndexDao
那么接下來(lái)自然會(huì )進(jìn)到length==1的那個(gè)代碼塊,這時(shí)候我再debug進(jìn)入,這里還是一個(gè)getBean方法
在spring容器中還有一些沒(méi)有name的其他的bean需要被創(chuàng )建,所以這里我用上了條件斷點(diǎn),當beanName等于indexDao的時(shí)候,才會(huì )進(jìn)入斷點(diǎn),但是當我F8跑完這行代碼的時(shí)候,出乎意料的事情發(fā)生了
驚不驚喜,意不意外,getSingleton這行代碼執行結束之后,代理對象就已經(jīng)被創(chuàng )建了,所以需要debug進(jìn)入這行代碼去看
protected Object getSingleton(String beanName, boolean allowEarlyReference) { //spring所有的bean被放在ioc容器中的地方,就是這個(gè)singletonObjects,這是一個(gè)concorrentHashMap。 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; }
但是我在這里只看到了get方法,那么這些bean是什么時(shí)候放到singletonObjects里的呢,我來(lái)找找
protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }
在DefaultSingletonBeanRegistry注冊器中,我找到了singletonObjects.put方法,代表bean是這個(gè)時(shí)候被放到這個(gè)map里去的,接下來(lái)我在這行代碼上進(jìn)行條件斷點(diǎn),然后我們來(lái)看它的調用鏈,找出是什么時(shí)候執行的addSingleton方法,其實(shí)從這個(gè)時(shí)候我已經(jīng)知道,斷點(diǎn)打在測試方法的倒數第二行是不對的,在getBean之前其實(shí)代理對象已經(jīng)產(chǎn)生了
// Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { //創(chuàng )建bean,核心代碼 return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
在createBean方法上,我也加上條件斷點(diǎn),然后debug進(jìn)入
@Override protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { if (logger.isTraceEnabled()) { logger.trace("Creating instance of bean '" + beanName + "'"); } RootBeanDefinition mbdToUse = mbd; // Make sure bean class is actually resolved at this point, and // clone the bean definition in case of a dynamically resolved Class // which cannot be stored in the shared merged bean definition. Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } // Prepare method overrides. try { mbdToUse.prepareMethodOverrides(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", ex); } try { // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } } catch (Throwable ex) { throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", ex); } try { //核心代碼,創(chuàng )建bean實(shí)例,需要斷點(diǎn)進(jìn)入 Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isTraceEnabled()) { logger.trace("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { // A previously detected exception with proper bean creation context already, // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry. throw ex; } catch (Throwable ex) { throw new BeanCreationException( mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex); } }
接下來(lái)我debug進(jìn)入doCreateBean方法
debug跟進(jìn)initializeBean方法,條件斷點(diǎn)在兩個(gè)初始化處理器上,我隱約覺(jué)得代理對象就是從這兩個(gè)方法中產(chǎn)生的,我們拭目以待
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); } //包裝的bean Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { //執行前置初始化beanPostProcessor處理器 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處理器 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
執行完applyBeanPostProcessorsBeforeInitialization方法,這個(gè)時(shí)候我們看到warppedBean還是indexDao,并沒(méi)有產(chǎn)生代理對象
我猜想在下一個(gè)后置處理器中,代理對象將被創(chuàng )建,我debug進(jìn)去
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { //經(jīng)過(guò)處理器處理后的bean,我先看看有多少個(gè)處理器 Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }
可以看到我的猜想被證明是正確的,運行完這個(gè)后置處理器,代理對象就被創(chuàng )建出來(lái)了。 到了這里我們知道了代理對象是從哪里來(lái)的了,但是還是沒(méi)搞清楚代理對象是怎么創(chuàng )建出來(lái)的,這時(shí)候我們就需要debug進(jìn)入到這個(gè)處理器內部去瞧瞧了。
@Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { //獲取緩存key,不重要 Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { //重要方法,需要debug進(jìn)去看 return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
于是乎我又進(jìn)到了wrapIfNecessary這個(gè)方法內部
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; } // Create proxy if we have advice. //看到上面這行注釋?zhuān)梢源_定代理類(lèi)就是從這里產(chǎn)生的,下面這個(gè)方法得到的都是一些包括切點(diǎn)信息,通知類(lèi)型等等的信息 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); //顧名思義,創(chuàng )建代理,bebug進(jìn)入看看 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; }
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); } 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); } //重要的地方在這里,代理對象是通過(guò)這個(gè)方法生成的 return proxyFactory.getProxy(getProxyClassLoader()); } public Object getProxy(@Nullable ClassLoader classLoader) { //debug進(jìn)去看看 return createAopProxy().getProxy(classLoader); }
protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } //同樣需要debug進(jìn)入看看 return getAopProxyFactory().createAopProxy(this); }
我們看到這里有一個(gè)if語(yǔ)句,當config中的isOptimize和isProxyTargetClass還有hasNoUserSuppliedProxyInterfaces三個(gè)判斷條件只要有一個(gè)滿(mǎn)足的話(huà),spring就會(huì )選擇cglib的方式進(jìn)行動(dòng)態(tài)代理,而config中的兩個(gè)boolean變量的默認值都是false,而我們的被代理對象又是實(shí)現接口的,所以spring會(huì )選擇jdk動(dòng)態(tài)代理的實(shí)現形式來(lái)完成動(dòng)態(tài)代理,當然,我們也可以在這種情況下手動(dòng)的配置config值來(lái)讓spring選擇cglib作為動(dòng)態(tài)代理的實(shí)現方式,稍后我會(huì )演示
@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 { //現在知道為什么我們的代理類(lèi)是動(dòng)態(tài)代理了嗎 return new JdkDynamicAopProxy(config); } }
我以spring aop實(shí)現的調用鏈圖來(lái)結束這次的總結
以上就是spring aop底層原理及如何實(shí)現的詳細內容,更多關(guān)于spring aop原理及實(shí)現的資料請關(guān)注腳本之家其它相關(guān)文章!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。
Copyright ? 2009-2022 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 特網(wǎng)科技 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 百度云 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站