
第一,要形成的習(xí)慣:
1.有空時隔一段時間要做幾道算法題,C語言和JAVA都可以,主要是訓(xùn)練思維。
2.定期閱讀spring的源碼。因為spring是框架,重設(shè)計,能夠培養(yǎng)大局觀
3.閱讀底層的書籍,如linux方面,虛擬機方面,這是內(nèi)功。越高級的語言只是招式。
4.不要忘記做了一半的東西,如搜索引擎方面,redis方面,可以過一段時間再做,因為到時候自己的境界有提升,深入程度也會有所增加。
第二,進入正題,了解原理,再看源碼。
1.看源碼看熟了,以后再遇到問題,就可以通過源碼去了解原理了。
2.spring的AOP,原理懂了,代碼相當(dāng)簡單。這也是為什么我記得我還是個菜鳥的時候,面試人家經(jīng)常問我這個。
3.先有個大局觀,畫張整體的spring結(jié)構(gòu)圖。
? ? 以下是備受吐槽的手繪時間:
(如果你覺得我左手字寫的實在是不能再難看了的話,我有空可以展示一下右手字。)
AOP面向切面編程是面向?qū)ο蟮难a充。它利用一種橫切技術(shù),將一些公共行為封裝成叫做“方面”的可重用模塊,解耦,增加可維護性。
AOP將系統(tǒng)分為核心關(guān)注點和橫切關(guān)注點兩部分。核心關(guān)注點就是主業(yè)務(wù)流程,橫切關(guān)注點就是上面提到的“方面”。那么看AOP的源碼就是要看橫切關(guān)注點是怎樣和核心關(guān)注點整合來發(fā)揮作用的。
主業(yè)務(wù)流程歸根到底是一個java方法,而且是對象的方法。
在AOP中被稱為被通知或被代理對象POJO。AOP的作用就是將核心關(guān)注點和橫切關(guān)注點組合起來,術(shù)語叫做“增強”。最后實際用的是增強后的代理對象。
對核心關(guān)注點進行增強就涉及到在哪些地方增強的問題。如方法調(diào)用或者異常拋出時做增強這些時機叫做連接點Joinpoint。一個通知將被引發(fā)的連接點集合叫做切入點,理解時就可以想正則表達(dá)式,通配符來指定多個,而不是單單一個連接點。
在連接點都做了哪些增強呢?增強的內(nèi)容AOP術(shù)語叫“通知”Advice。
Spring里定義了四種Advice:BeforeAdvice,AfterAdvice,ThrowAdvice,DynamicIntroducationAdvice。
許多AOP框架包括spring都是以攔截器作為通知模型。維護一個圍繞連接點的攔截器鏈。其中DynamicIntroducationAdvice是可以引入方法或者字段到核心關(guān)注點。
這里有個Introduction,AOP術(shù)語叫引入。將增強后的AOP代理組裝到系統(tǒng)叫做織入。
上面就是AOP的核心概念了??偨Y(jié)一下:
AOP要做的事情就是:生成代理對象,然后織入。
生成代理對象是經(jīng)常會被問到的一個問題:Spring提供了兩種方式來生成代理對象,JDKProxy和Cglib。
具體使用哪種方式由AopProxyFactory根據(jù)AdvisedSupport對象的配置來決定。
默認(rèn)的策略是如果目標(biāo)類是接口,則使用JDK動態(tài)代理技術(shù),否則使用Cglib來生成代理。
Cglib是基于字節(jié)碼技術(shù)的,使用的是ASM。asm是一個java字節(jié)碼操縱框架,它能被用來動態(tài)生成類或者增強既有類的功能。
ASM可以直接產(chǎn)生二進制class文件,也可以在類被加載入JVM之前動態(tài)改變類行為。
下面重點來看看JDK動態(tài)代理技術(shù)。這是我還是個很菜很菜的菜鳥時為數(shù)不多能看懂的源碼。因為之前看過Java設(shè)計模式,寫過類似的例子,所以會比較順暢。今天先講這一部分。
下面是調(diào)用測試類:
package?dynamic.proxy;?
import?java.lang.reflect.InvocationHandler;
import?java.lang.reflect.Method;
import?java.lang.reflect.Proxy;
/**
?*?實現(xiàn)自己的InvocationHandler
?*?@author?zyb
?*?@since?2012-8-9
?*
?*/
public?class?MyInvocationHandler?implements?InvocationHandler?{
?//?目標(biāo)對象?
?private?Object?target;
?/**
?*?構(gòu)造方法
?*?@param?target?目標(biāo)對象?
?*/
?public?MyInvocationHandler(Object?target)?{
?super();
?this.target?=?target;
?}
?/**
?*?執(zhí)行目標(biāo)對象的方法
?*/
?public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{
?//?在目標(biāo)對象的方法執(zhí)行之前簡單的打印一下
?System.out.println("------------------before------------------");
?//?執(zhí)行目標(biāo)對象的方法
?Object?result?=?method.invoke(target,?args);
?//?在目標(biāo)對象的方法執(zhí)行之后簡單的打印一下
?System.out.println("-------------------after------------------");
?return?result;
?}
?/**
?*?獲取目標(biāo)對象的代理對象
?*?@return?代理對象
?*/
?public?Object?getProxy()?{
?return?Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),?
?target.getClass().getInterfaces(),?this);
?}
}
package?dynamic.proxy;
/**
?*?目標(biāo)對象實現(xiàn)的接口,用JDK來生成代理對象一定要實現(xiàn)一個接口
?*?@author?zyb
?*?@since?2012-8-9
?*
?*/
public?interface?UserService?{
?/**
?*?目標(biāo)方法?
?*/
?public?abstract?void?add();
}
package?dynamic.proxy;?
/**
?*?目標(biāo)對象
?*?@author?zyb
?*?@since?2012-8-9
?*
?*/
public?class?UserServiceImpl?implements?UserService?{
?/*?(non-Javadoc)
?*?@see?dynamic.proxy.UserService#add()
?*/
?public?void?add()?{
?System.out.println("--------------------add---------------");
?}
}
package?dynamic.proxy;?
import?org.junit.Test;
/**
?*?動態(tài)代理測試類
?*?@author?zyb
?*?@since?2012-8-9
?*
?*/
public?class?ProxyTest?{
?@Test
?public?void?testProxy()?throws?Throwable?{
?//?實例化目標(biāo)對象
?UserService?userService?=?new?UserServiceImpl();
?//?實例化InvocationHandler
?MyInvocationHandler?invocationHandler?=?new?MyInvocationHandler(userService);
?//?根據(jù)目標(biāo)對象生成代理對象
?UserService?proxy?=?(UserService)?invocationHandler.getProxy();
?//?調(diào)用代理對象的方法
?proxy.add();
?}
}
執(zhí)行結(jié)果如下:
------------------before---------------
--------------------add---------------
-------------------after-----------------
很簡單,核心就是 invocationHandler.getProxy();這個方法調(diào)用的Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),target.getClass().getInterfaces(), this); 怎么生成對象的。
/**
?*?Returns?an?instance?of?a?proxy?class?for?the?specified?interfaces
?*?that?dispatches?method?invocations?to?the?specified?invocation
?*?handler.
?*
?*?
{@code?Proxy.newProxyInstance}?throws
?*?{@code?IllegalArgumentException}?for?the?same?reasons?that
?*?{@code?Proxy.getProxyClass}?does.
?*
?*?@param?loader?the?class?loader?to?define?the?proxy?class
?*?@param?interfaces?the?list?of?interfaces?for?the?proxy?class
?*?to?implement
?*?@param?h?the?invocation?handler?to?dispatch?method?invocations?to
?*?@return?a?proxy?instance?with?the?specified?invocation?handler?of?a
?*?proxy?class?that?is?defined?by?the?specified?class?loader
?*?and?that?implements?the?specified?interfaces
?*?@throws?IllegalArgumentException?if?any?of?the?restrictions?on?the
?*?parameters?that?may?be?passed?to?{@code?getProxyClass}
?*?are?violated
?*?@throws?SecurityException?if?a?security?manager,?s,?is?present
?*?and?any?of?the?following?conditions?is?met:
?*?
?*?
?the?given?{@code?loader}?is?{@code?null}?and
?*?the?caller's?class?loader?is?not?{@code?null}?and?the
?*?invocation?of?{@link?SecurityManager#checkPermission
?*?s.checkPermission}?with
?*?{@code?RuntimePermission("getClassLoader")}?permission
?*?denies?access;
?*?
?for?each?proxy?interface,?{@code?intf},
?*?the?caller's?class?loader?is?not?the?same?as?or?an
?*?ancestor?of?the?class?loader?for?{@code?intf}?and
?*?invocation?of?{@link?SecurityManager#checkPackageAccess
?*?s.checkPackageAccess()}?denies?access?to?{@code?intf};
?*?
?any?of?the?given?proxy?interfaces?is?non-public?and?the
?*?caller?class?is?not?in?the?same?{@linkplain?Package?runtime?package}
?*?as?the?non-public?interface?and?the?invocation?of
?*?{@link?SecurityManager#checkPermission?s.checkPermission}?with
?*?{@code?ReflectPermission("newProxyInPackage.{package?name}")}
?*?permission?denies?access.
?*?
?*?@throws?NullPointerException?if?the?{@code?interfaces}?array
?*?argument?or?any?of?its?elements?are?{@code?null},?or
?*?if?the?invocation?handler,?{@code?h},?is
?*?{@code?null}
?*/
?@CallerSensitive
?public?static?Object?newProxyInstance(ClassLoader?loader,
?Class[]?interfaces,
?InvocationHandler?h)
?throws?IllegalArgumentException
?{
?Objects.requireNonNull(h);
?final?Class[]?intfs?=?interfaces.clone();
?final?SecurityManager?sm?=?System.getSecurityManager();
?if?(sm?!=?null)?{
?checkProxyAccess(Reflection.getCallerClass(),?loader,?intfs);
?}
?/*
?*?Look?up?or?generate?the?designated?proxy?class.
?*/
?Class?cl?=?getProxyClass0(loader,?intfs);
?/*
?*?Invoke?its?constructor?with?the?designated?invocation?handler.
?*/
?try?{
?if?(sm?!=?null)?{
?checkNewProxyPermission(Reflection.getCallerClass(),?cl);
?}
?final?Constructor?cons?=?cl.getConstructor(constructorParams);
?final?InvocationHandler?ih?=?h;
?if?(!Modifier.isPublic(cl.getModifiers()))?{
?AccessController.doPrivileged(new?PrivilegedAction()?{
?public?Void?run()?{
?cons.setAccessible(true);
?return?null;
?}
?});
?}
?return?cons.newInstance(new?Object[]{h});
?}?catch?(IllegalAccessException|InstantiationException?e)?{
?throw?new?InternalError(e.toString(),?e);
?}?catch?(InvocationTargetException?e)?{
?Throwable?t?=?e.getCause();
?if?(t?instanceof?RuntimeException)?{
?throw?(RuntimeException)?t;
?}?else?{
?throw?new?InternalError(t.toString(),?t);
?}
?}?catch?(NoSuchMethodException?e)?{
?throw?new?InternalError(e.toString(),?e);
?}
?}
這個代碼是JDK1.8中的,里面用到了1.8的一些語法,如果不太了解,建議先看看這本書。
代碼看著不少,實際上都在進行一些安全校驗,包裝之類的,真正有用的就兩句:
Class cl = getProxyClass0(loader, intfs);這句話查找或者生成代理類。跟進去:
/**
?*?Generate?a?proxy?class.?Must?call?the?checkProxyAccess?method
?*?to?perform?permission?checks?before?calling?this.
?*/
?private?static?Class?getProxyClass0(ClassLoader?loader,
?Class...?interfaces)?{
?if?(interfaces.length?>?65535)?{
?throw?new?IllegalArgumentException("interface?limit?exceeded");
?}
?//?If?the?proxy?class?defined?by?the?given?loader?implementing
?//?the?given?interfaces?exists,?this?will?simply?return?the?cached?copy;
?//?otherwise,?it?will?create?the?proxy?class?via?the?ProxyClassFactory
?return?proxyClassCache.get(loader,?interfaces);
?}
對,就是從緩存里把接口拿將出來。然后用return cons.newInstance(new Object[]{h}) 這一句將接口用invocationHandler進行包裝。
具體源碼可以跟進去看,不詳述。想必看到這里,JDK動態(tài)代理的原理都已經(jīng)很明白了。
這里要說一點理論性的東西:
AOP解決的問題往往可以用代理模式來解決。Java開發(fā)中常說動態(tài)代理和靜態(tài)代理,而AOP就是動態(tài)代理,因為代理的類是在運行時才生成的。
而一般說的代理模式寫成的代碼是編譯期就已經(jīng)生成的,叫靜態(tài)代理。
想繼續(xù)了解JAVA知識的,記得關(guān)注+關(guān)注+關(guān)注!
