摘要:在上文中,我實(shí)現(xiàn)了一個很簡單的和容器。比如,我們所熟悉的就是在這里將切面邏輯織入相關(guān)中的。初始化的工作算是結(jié)束了,此時處于就緒狀態(tài),等待外部程序的調(diào)用。其中動態(tài)代理只能代理實(shí)現(xiàn)了接口的對象,而動態(tài)代理則無此限制。
1. 背景
本文承接上文,來繼續(xù)說說 IOC 和 AOP 的仿寫。在上文中,我實(shí)現(xiàn)了一個很簡單的 IOC 和 AOP 容器。上文實(shí)現(xiàn)的 IOC 和 AOP 功能很單一,且 IOC 和 AOP 兩個模塊沒有整合到一起。IOC 在加載 bean 過程中,AOP 不能對 bean 織入通知。在本文中,我們詳細(xì)說一下升級版 IOC 和 AOP。這個版本的實(shí)現(xiàn)包含了在上篇中所說的功能,這里再重述一下,如下:
根據(jù) xml 配置文件加載相關(guān) bean
對 BeanPostProcessor 類型的 bean 提供支持
對 BeanFactoryAware 類型的 bean 提供支持
實(shí)現(xiàn)了基于 JDK 動態(tài)代理的 AOP
整合了 IOC 和 AOP,使得二者可很好的協(xié)同工作
上面羅列了5個功能點(diǎn),雖然看起來不多,但是對于新手來說,實(shí)現(xiàn)起來還是不很容易的。所以接下來,我將圍繞上面的功能點(diǎn)展開詳細(xì)的描述。如果大家有興趣,我還是很建議大家跟著寫一遍,因?yàn)楹芏鄷r候能看懂,但是寫的卻不一定能寫出來。仿寫一遍能夠加深對 Spring IOC 和 AOP 原理的理解,多動手是有好處的。
另外需要說明的是,黃億華前輩實(shí)現(xiàn)的 tiny-spring 項(xiàng)目時間節(jié)點(diǎn)是 2014.1,當(dāng)時應(yīng)該是參照 Spring 3.x 版本編寫的。部分類的設(shè)計(jì)思想可能會與現(xiàn)在最新穩(wěn)定版 4.3.10 有一定的出入,由于我暫時沒有閱讀 Spring 源碼的計(jì)劃,所以這里不能告知大家 tiny-spring 哪些類與 Spring 最新的源碼有出入,見諒。
好了,本章內(nèi)容先介紹到這,接下來進(jìn)入正文。
2. IOC 的實(shí)現(xiàn) 2.1 BeanFactory 的生命流程上面簡述了 toy-spring 項(xiàng)目的編碼背景,接下來,在本節(jié)中,我將向大家介紹 toy-spring 項(xiàng)目中 IOC 部分的實(shí)現(xiàn)原理。在詳細(xì)介紹 IOC 的實(shí)現(xiàn)原理前,這里先簡單說一下 BeanFactory 的生命流程:
BeanFactory 加載 Bean 配置文件,將讀到的 Bean 配置封裝成 BeanDefinition 對象
將封裝好的 BeanDefinition 對象注冊到 BeanDefinition 容器中
注冊 BeanPostProcessor 相關(guān)實(shí)現(xiàn)類到 BeanPostProcessor 容器中
BeanFactory 進(jìn)入就緒狀態(tài)
外部調(diào)用 BeanFactory 的 getBean(String name) 方法,BeanFactory 著手實(shí)例化相應(yīng)的 bean
重復(fù)步驟 3 和 4,直至程序退出,BeanFactory 被銷毀
上面簡單羅列了 BeanFactory 的生命流程,也就是 IOC 容器的生命流程。接下來就來圍繞上面的流程展開討論。
2.2 BeanDefinition 及其他一些類的介紹在詳細(xì)介紹 IOC 容器的工作原理前,這里先介紹一下實(shí)現(xiàn) IOC 所用到的一些輔助類,包括BeanDefinition、BeanReference、PropertyValues、PropertyValue。這些類與接下來的 2.3 節(jié) xml 的解析緊密相關(guān)。按照順序,先從 BeanDefinition 開始介紹。
BeanDefinition,從字面意思上翻譯成中文就是 “Bean 的定義”。從翻譯結(jié)果中就可以猜出這個類的用途,即根據(jù) Bean 配置信息生成相應(yīng)的 Bean 詳情對象。舉個例子,如果把 Bean 比作是電腦 ?,那么 BeanDefinition 就是這臺電腦的配置清單。我們從外觀上無法看出這臺電腦里面都有哪些配置,也看不出電腦的性能咋樣。但是通過配置清單,我們就可了解這臺電腦的詳細(xì)配置。我們可以知道這臺電腦是不是用了牙膏廠的 CPU,BOOM 廠的固態(tài)硬盤等。透過配置清單,我們也就可大致評估出這臺電腦的性能。
圖1 電腦和配置清單
上面那個例子還是比較貼切的,但是只是個例子,和實(shí)際還是有差距的。那么在具體實(shí)現(xiàn)中,BeanDefinition 和 xml 是怎么對應(yīng)的呢?答案在下面:
圖2 根據(jù) bean 配置生成 BeanDefinition
看完上圖,我想大家對 BeanDefinition 的用途有了更進(jìn)一步的認(rèn)識。接下來我們來說說上圖中的 ref 對應(yīng)的 BeanReference 對象。BeanReference 對象保存的是 bean 配置中 ref 屬性對應(yīng)的值,在后續(xù) BeanFactory 實(shí)例化 bean 時,會根據(jù) BeanReference 保存的值去實(shí)例化 bean 所依賴的其他 bean。
接下來說說 PropertyValues 和 PropertyValue 這兩個長的比較像的類,首先是PropertyValue。PropertyValue 中有兩個字段 name 和 value,用于記錄 bean 配置中的
public class PropertyValues { private final ListpropertyValueList = new ArrayList (); public void addPropertyValue(PropertyValue pv) { // 在這里可以對參數(shù)值 pv 做一些處理,如果直接使用 List,則就不行了 this.propertyValueList.add(pv); } public List getPropertyValues() { return this.propertyValueList; } }
好了,輔助類介紹完了,接下來我們繼續(xù) BeanFactory 的生命流程探索。
2.3 xml 的解析BeanFactory 初始化時,會根據(jù)傳入的 xml 配置文件路徑加載并解析配置文件。但是加載和解析 xml 配置文件這種臟活累活,BeanFactory 可不太愿意干,它只想高冷的管理容器中的 bean。于是 BeanFactory 將加載和解析配置文件的任務(wù)委托給專職人員 BeanDefinitionReader 的實(shí)現(xiàn)類 XmlBeanDefinitionReader 去做。那么 XmlBeanDefinitionReader 具體是怎么做的呢?XmlBeanDefinitionReader 做了如下幾件事情:
將 xml 配置文件加載到內(nèi)存中
獲取根標(biāo)簽
遍歷獲取到的
創(chuàng)建 BeanDefinition 對象,并將剛剛讀取到的 id,class 屬性值保存到對象中
遍歷
將
重復(fù)3、4、5、6步,直至解析結(jié)束
上面的解析步驟并不復(fù)雜,實(shí)現(xiàn)起來也不難,就是解析 xml 而已,這里就不過多敘述了。
2.4 注冊 BeanPostProcessorBeanPostProcessor 接口是 Spring 對外拓展的接口之一,其主要用途提供一個機(jī)會,讓開發(fā)人員能夠插手 bean 的實(shí)例化過程。通過實(shí)現(xiàn)這個接口,我們就可在 bean 實(shí)例化時,對bean 進(jìn)行一些處理。比如,我們所熟悉的 AOP 就是在這里將切面邏輯織入相關(guān) bean 中的。正是因?yàn)橛辛?BeanPostProcessor 接口作為橋梁,才使得 AOP 可以和 IOC 容器產(chǎn)生聯(lián)系。關(guān)于這一點(diǎn),我將會在后續(xù)章節(jié)詳細(xì)說明。
接下來說說 BeanFactory 是怎么注冊 BeanPostProcessor 相關(guān)實(shí)現(xiàn)類的。
XmlBeanDefinitionReader 在完成解析工作后,BeanFactory 會將它解析得到的
根據(jù) BeanDefinition 記錄的信息,尋找所有實(shí)現(xiàn)了 BeanPostProcessor 接口的類。
實(shí)例化 BeanPostProcessor 接口的實(shí)現(xiàn)類
將實(shí)例化好的對象放入 List
重復(fù)2、3步,直至所有的實(shí)現(xiàn)類完成注冊
上面簡述了 BeanPostProcessor 接口的用途以及注冊的過程。BeanPostProcessor 是一個比較常用接口,相信大家都很熟悉了,這里就不過多敘述了。
2.5 getBean 過程解析在完成了 xml 的解析、BeanDefinition 的注冊以及 BeanPostProcessor 的注冊過程后。BeanFactory 初始化的工作算是結(jié)束了,此時 BeanFactory 處于就緒狀態(tài),等待外部程序的調(diào)用。
外部程序一般都是通過調(diào)用 BeanFactory 的 getBean(String name) 方法來獲取容器中的 bean。BeanFactory 具有延遲實(shí)例化 bean 的特性,也就是等外部程序需要的時候,才實(shí)例化相關(guān)的 bean。這樣做的好處是比較顯而易見的,第一是提高了 BeanFactory 的初始化速度,第二是節(jié)省了內(nèi)存資源。下面我們就來詳細(xì)說說 bean 的實(shí)例化過程:
圖3 Spring bean實(shí)例化過程
上圖是一個完整的 Spring bean 實(shí)例化過程圖。在我的仿寫項(xiàng)目中,沒有做的這么復(fù)雜,簡化了 bean 實(shí)例化的過程,如下:
圖4 toy-spring bean實(shí)例化過程
接下來我將按照簡化后的 bean 實(shí)例化過程介紹,如果想了解完整的 bean 實(shí)例化過程,可以參考我的另一篇文章:Spring bean的生命流程。簡化后的實(shí)例化流程如下:
實(shí)例化 bean 對象,類似于 new XXObject()
將配置文件中配置的屬性填充到剛剛創(chuàng)建的 bean 對象中
檢查 bean 對象是否實(shí)現(xiàn)了 Aware 一類的接口,如果實(shí)現(xiàn)了則把相應(yīng)的依賴設(shè)置到 bean 對象中。toy-spring 目前僅對 BeanFactoryAware 接口實(shí)現(xiàn)類提供了支持
調(diào)用 BeanPostProcessor 前置處理方法,即 postProcessBeforeInitialization(Object bean, String beanName)
調(diào)用 BeanPostProcessor 后置處理方法,即 postProcessAfterInitialization(Object bean, String beanName)
bean 對象處于就緒狀態(tài),可以使用了
上面 6 步流程并不復(fù)雜,源碼實(shí)現(xiàn)的也較為簡單,這里就不在貼代碼說明了。大家如果想了解細(xì)節(jié),可以去 github 上下載 toy-spring 源碼閱讀。
3. 實(shí)現(xiàn) AOP 3.1 AOP 原理AOP 是基于動態(tài)代理模式實(shí)現(xiàn)的,具體實(shí)現(xiàn)上可以基于 JDK 動態(tài)代理或者 Cglib 動態(tài)代理。其中 JDK 動態(tài)代理只能代理實(shí)現(xiàn)了接口的對象,而 Cglib 動態(tài)代理則無此限制。所以在為沒有實(shí)現(xiàn)接口的對象生成代理時,只能使用 Cglib。在 toy-spring 項(xiàng)目中,暫時只實(shí)現(xiàn)了基于 JDK 動態(tài)代理的代理對象生成器。
關(guān)于 AOP 原理這里就不多說了,下面說說 toy-spring 中 AOP 的實(shí)現(xiàn)步驟。還是像上面一樣,先列流程:
AOP 邏輯介入 BeanFactory 實(shí)例化 bean 的過程
根據(jù) Pointcut 定義的匹配規(guī)則,判斷當(dāng)前正在實(shí)例化的 bean 是否符合規(guī)則
如果符合,代理生成器將切面邏輯 Advice 織入 bean 相關(guān)方法中,并為目標(biāo) bean 生成代理對象
將生成的 bean 的代理對象返回給 BeanFactory 容器,到此,AOP 邏輯執(zhí)行結(jié)束
對于上面的4步流程,熟悉 Spring AOP 的朋友應(yīng)該能很容易理解。如果有朋友不理解也沒關(guān)系,在后續(xù)章節(jié),我會詳細(xì)介紹相關(guān)流程的具體實(shí)現(xiàn)。
3.2 基于 JDK 動態(tài)代理的 AOP 實(shí)現(xiàn)本節(jié)說說基于 JDK 動態(tài)代理的代理對象生成器具體實(shí)現(xiàn)。在 toy-spring 項(xiàng)目中,代理對象生成器的邏輯主要寫在了 JdkDynamicAopProxy 類中,這個類的有兩個方法,其中 getProxy 方法用于生成代理對象。invoke 方法是 InvocationHandler 接口的具體實(shí)現(xiàn),包含了將通知(Advice)織入相關(guān)方法中,是3.1節(jié)所列流程中第3步流程的具體實(shí)現(xiàn)。好了,接下來,對著源碼講解 JdkDynamicAopProxy:
JdkDynamicAopProxy 實(shí)現(xiàn)代碼:
public abstract class AbstractAopProxy implements AopProxy { protected AdvisedSupport advised; public AbstractAopProxy(AdvisedSupport advised) { this.advised = advised; } } /** * 基于 JDK 動態(tài)代理的代理對象生成器 * Created by code4wt on 17/8/16. */ final public class JdkDynamicAopProxy extends AbstractAopProxy implements InvocationHandler { public JdkDynamicAopProxy(AdvisedSupport advised) { super(advised); } /** * 為目標(biāo) bean 生成代理對象 * @return bean 的代理對象 */ @Override public Object getProxy() { return Proxy.newProxyInstance(getClass().getClassLoader(), advised.getTargetSource().getInterfaces(), this); } /** * InvocationHandler 接口中的 invoke 方法具體實(shí)現(xiàn),封裝了具體的代理邏輯 * @param proxy * @param method * @param args * @return 代理方法或原方法的返回值 * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodMatcher methodMatcher = advised.getMethodMatcher(); // 1. 使用方法匹配器 methodMatcher 測試 bean 中原始方法 method 是否符合匹配規(guī)則 if (methodMatcher != null && methodMatcher.matchers(method, advised.getTargetSource().getTargetClass())) { // 獲取 Advice。MethodInterceptor 的父接口繼承了 Advice MethodInterceptor methodInterceptor = advised.getMethodInterceptor(); /* * 2. 將 bean 的原始方法 method 封裝在 MethodInvocation 接口實(shí)現(xiàn)類對象中, * 并把生成的對象作為參數(shù)傳給 Adivce 實(shí)現(xiàn)類對象,執(zhí)行通知邏輯 */ return methodInterceptor.invoke( new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args)); } else { // 2. 當(dāng)前 method 不符合匹配規(guī)則,直接調(diào)用 bean 的原始方法 method return method.invoke(advised.getTargetSource().getTarget(), args); } } }
上面貼的代碼,已經(jīng)對 JdkDynamicAopProxy 實(shí)現(xiàn)代碼進(jìn)行了逐行介解釋,這里不再多說。下面用個流程圖對通知織入邏輯進(jìn)行總結(jié):
圖5 toy-spring AOP 通知織入流程圖
最后對 JdkDynamicAopProxy 進(jìn)行簡單的測試,測試代碼及結(jié)果如下
測試類:
public class LogInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println(invocation.getMethod().getName() + " method start"); Object obj= invocation.proceed(); System.out.println(invocation.getMethod().getName() + " method end"); return obj; } } public class JdkDynamicAopProxyTest { @Test public void getProxy() throws Exception { System.out.println("---------- no proxy ----------"); HelloService helloService = new HelloServiceImpl(); helloService.sayHelloWorld(); System.out.println(" ----------- proxy -----------"); AdvisedSupport advisedSupport = new AdvisedSupport(); advisedSupport.setMethodInterceptor(new LogInterceptor()); TargetSource targetSource = new TargetSource( helloService, HelloServiceImpl.class, HelloServiceImpl.class.getInterfaces()); advisedSupport.setTargetSource(targetSource); advisedSupport.setMethodMatcher((Method method, Class beanClass) -> true); helloService = (HelloService) new JdkDynamicAopProxy(advisedSupport).getProxy(); helloService.sayHelloWorld(); } }
測試結(jié)果:
為了控制文章篇幅,上面代碼中用到的其他輔助類,這里就不貼出來了,想看的朋友可以到 github 上下載源碼。
3.3 AOP 與 IOC 協(xié)作上一節(jié)介紹了3.1節(jié)所列流程中第3步流程的具體實(shí)現(xiàn),這一節(jié)則會介紹1、2、4步流程的具體實(shí)現(xiàn)。在介紹之前,還要再次提一下 BeanPostProcessor接口。在之前2.4節(jié) 注冊 BeanPostProcessor 中我已經(jīng)介紹過 BeanPostProcessor 的作用,也說到了 AOP 是通過 BeanPostProcessor 接口與 IOC 產(chǎn)生聯(lián)系的。不過2.4節(jié),只是蜻蜓點(diǎn)水提了一下,沒有詳細(xì)展開說明。在本節(jié)中,我將詳細(xì)講解 toy-spring 項(xiàng)目中 AOP 和 IOC 是怎樣被整合到一起的。
Spring 從2.0版本開始集成 AspectJ,通過集成 AspectJ,也使得 Spring AOP 的功能得到了很大的增強(qiáng)。我們在平時開發(fā)中,很多時候是使用基于 AspectJ 表達(dá)式及其他配置來實(shí)現(xiàn)切面功能。所以我在編寫 toy-spring 項(xiàng)目時,也在項(xiàng)目中簡單集成了 AspectJ。通過集成 AspectJ,使得 toy-spring AOP 可以基于 AspectJ 表達(dá)式完成復(fù)雜的匹配邏輯。接下來就讓我們看看袖珍版 Spring AOP 是怎樣實(shí)現(xiàn)的吧。
在 toy-spring 中,AOP 和 IOC 產(chǎn)生聯(lián)系的具體實(shí)現(xiàn)類是 AspectJAwareAdvisorAutoProxyCreator(下面簡稱 AutoProxyCreator),這個類實(shí)現(xiàn)了 BeanPostProcessor 和 BeanFactoryAware 接口。BeanFactory 在注冊 BeanPostProcessor 接口相關(guān)實(shí)現(xiàn)類的階段,會將其本身注入到 AutoProxyCreator 中,為后面 AOP 給 bean 生成代理對象做準(zhǔn)備。BeanFactory 初始化結(jié)束后,AOP 與 IOC 橋梁類 AutoProxyCreator 也完成了實(shí)例化,并被緩存在 BeanFactory 中,靜待 BeanFactory 實(shí)例化 bean。當(dāng)外部產(chǎn)生調(diào)用,BeanFactory 開始實(shí)例化 bean 時。AutoProxyCreator 就開始悄悄的工作了,工作細(xì)節(jié)如下:
從 BeanFactory 查找實(shí)現(xiàn)了 PointcutAdvisor 接口的切面對象,切面對象中包含了實(shí)現(xiàn) Pointcut 和 Advice 接口的對象。
使用 Pointcut 中的表達(dá)式對象匹配當(dāng)前 bean 對象。如果匹配成功,進(jìn)行下一步。否則終止邏輯,返回 bean。
JdkDynamicAopProxy 對象為匹配到的 bean 生成代理對象,并將代理對象返回給 BeanFactory。
經(jīng)過上面3步,AutoProxyCreator 就悄無聲息的把原來的 bean 替換為代理對象了,是不是有種偷天換日的感覺。最后把 toy-spring AOP 剩余的實(shí)現(xiàn)代碼貼出來:
public class AspectJAwareAdvisorAutoProxyCreator implements BeanPostProcessor, BeanFactoryAware { private XmlBeanFactory xmlBeanFactory; @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception { return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception { /* 這里兩個 if 判斷很有必要,如果刪除將會使程序進(jìn)入死循環(huán)狀態(tài), * 最終導(dǎo)致 StackOverflowError 錯誤發(fā)生 */ if (bean instanceof AspectJExpressionPointcutAdvisor) { return bean; } if (bean instanceof MethodInterceptor) { return bean; } // 1. 從 BeanFactory 查找 AspectJExpressionPointcutAdvisor 類型的對象 Listadvisors = xmlBeanFactory.getBeansForType(AspectJExpressionPointcutAdvisor.class); for (AspectJExpressionPointcutAdvisor advisor : advisors) { // 2. 使用 Pointcut 對象匹配當(dāng)前 bean 對象 if (advisor.getPointcut().getClassFilter().matchers(bean.getClass())) { ProxyFactory advisedSupport = new ProxyFactory(); advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice()); advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher()); TargetSource targetSource = new TargetSource(bean, bean.getClass(), bean.getClass().getInterfaces()); advisedSupport.setTargetSource(targetSource); // 3. 生成代理對象,并返回 return advisedSupport.getProxy(); } } // 2. 匹配失敗,返回 bean return bean; } @Override public void setBeanFactory(BeanFactory beanFactory) throws Exception { xmlBeanFactory = (XmlBeanFactory) beanFactory; } }
ProxyFactory 實(shí)現(xiàn)代碼:
/** * AopProxy 實(shí)現(xiàn)類的工廠類 */ public class ProxyFactory extends AdvisedSupport implements AopProxy { @Override public Object getProxy() { return createAopProxy().getProxy(); } private AopProxy createAopProxy() { return new JdkDynamicAopProxy(this); } }
測試類:
public class XmlBeanFactoryTest { @Test public void getBean() throws Exception { System.out.println("--------- AOP test ----------"); String location = getClass().getClassLoader().getResource("spring.xml").getFile(); XmlBeanFactory bf = new XmlBeanFactory(location); HelloService helloService = (HelloService) bf.getBean("helloService"); helloService.sayHelloWorld(); } }
測試結(jié)果:
4. 寫在最后到此,本文的主要內(nèi)容寫完了。如果你耐心的讀完了文章,并感覺不錯的話,歡迎猛點(diǎn)贊和收藏按鈕。這篇文章花了我一天的時間,寫的實(shí)在有點(diǎn)累,也深感認(rèn)真寫博客的不易。本篇文章與 仿照 Spring 實(shí)現(xiàn)簡單的 IOC 和 AOP - 上篇,Spring bean的生命流程 共三篇文章,對 Spring IOC 和 AOP 的實(shí)現(xiàn)原理進(jìn)行了較為詳細(xì)的結(jié)束。也是通過認(rèn)真編寫這三篇文章,使得我對 Spring 框架原理有了更進(jìn)一步的認(rèn)識。當(dāng)然限于我的經(jīng)驗(yàn)和能力,以上三篇文章中可能存在著一些錯誤。如果這些錯誤給大家造成了干擾,我表示很抱歉。所以文章若有疏漏不妥之處,還請指出來,如果能不吝賜教,那就更好了。好了,最后感謝大家耐心讀完我的文章,下次再見。
參考:《Spring揭秘》
??tiny-spring
本文在知識共享許可協(xié)議 4.0 下發(fā)布,轉(zhuǎn)載請注明出處
作者:coolblog
為了獲得更好的分類閱讀體驗(yàn),
請移步至本人的個人博客:http://www.coolblog.xyz
本作品采用知識共享署名-非商業(yè)性使用-禁止演繹 4.0 國際許可協(xié)議進(jìn)行許可。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/70191.html
摘要:不過那個實(shí)現(xiàn)太過于簡單,和,相去甚遠(yuǎn)。在接下來文章中,我也將從易到難,實(shí)現(xiàn)不同版本的和。切面切面包含了通知和切點(diǎn),通知和切點(diǎn)共同定義了切面是什么,在何時,何處執(zhí)行切面邏輯。 1. 背景 我在大四實(shí)習(xí)的時候開始接觸 J2EE 方面的開發(fā)工作,也是在同時期接觸并學(xué)習(xí) Spring 框架,到現(xiàn)在也有快有兩年的時間了。不過之前沒有仿寫過 Spring IOC 和 AOP,只是宏觀上對 Spri...
摘要:本文是容器源碼分析系列文章的第一篇文章,將會著重介紹的一些使用方法和特性,為后續(xù)的源碼分析文章做鋪墊。我們可以通過這兩個別名獲取到這個實(shí)例,比如下面的測試代碼測試結(jié)果如下本小節(jié),我們來了解一下這個特性。 1. 簡介 Spring 是一個輕量級的企業(yè)級應(yīng)用開發(fā)框架,于 2004 年由 Rod Johnson 發(fā)布了 1.0 版本。經(jīng)過十幾年的迭代,現(xiàn)在的 Spring 框架已經(jīng)非常成熟了...
摘要:干貨點(diǎn)此處是好好面試系列文的第篇文章。而這也是出現(xiàn)的原因,沒錯,就是被設(shè)計(jì)出來彌補(bǔ)短板的。運(yùn)行結(jié)果如下運(yùn)行結(jié)果可想而知,的通過驗(yàn)證,的失敗。 【干貨點(diǎn)】此處是【好好面試】系列文的第10篇文章。看完該篇文章,你就可以了解Spring中Aop的相關(guān)使用和原理,并且能夠輕松解答Aop相關(guān)的面試問題。 在實(shí)際研發(fā)中,Spring是我們經(jīng)常會使用的框架,畢竟它們太火了,也因此Spring相關(guān)的知...
摘要:進(jìn)行異常的捕捉與錯誤信息頁面的定制。告訴,這是一個對象,該對象應(yīng)該被注冊為在應(yīng)用程序上下文中的。不同框架的不同配置這里以作為演示默認(rèn)情況下,保護(hù)已啟用。你必須配置包含令牌的所有的網(wǎng)頁來工作。該命名結(jié)構(gòu)旨在幫你找到需要的。 導(dǎo)讀: 在上篇文章中我們了解到Spring Boot 的一些常用的外部化配置,在本篇中我們將會繼續(xù)對類的配置進(jìn)行了解 一個簡單的例子[錯誤頁面定制]: 在 Spr...
摘要:構(gòu)造函數(shù)注入通過調(diào)用類的構(gòu)造函數(shù),將接口實(shí)現(xiàn)類通過構(gòu)造函數(shù)變量傳入。而在中,其使用橫切技術(shù),將這類代碼從原屬的封裝對象中提取出來,封裝到一個可重用模塊中,稱為。 最近實(shí)習(xí)用到Spring的開發(fā)框架,但是之前沒有接觸過,因此希望利用網(wǎng)上的資源來學(xué)習(xí)以下。 Spring官方給出了非常全面的介紹,非常適合我這種完全的小白……在這一系列學(xué)習(xí)中,我閱讀的主要資源是5.1.2 Reference ...
閱讀 1833·2021-11-18 13:21
閱讀 1966·2021-10-18 13:30
閱讀 1551·2021-10-12 10:13
閱讀 922·2021-10-09 09:43
閱讀 5436·2021-09-22 15:13
閱讀 3595·2021-08-11 10:22
閱讀 947·2019-08-30 13:46
閱讀 3527·2019-08-30 13:21