摘要:關(guān)于的這種,我感覺(jué)應(yīng)該是屬于編譯器織入,因?yàn)槭峭ㄟ^(guò)子類生成字節(jié)碼然后進(jìn)行調(diào)用。
關(guān)于的Aop:
用處:可以用在連接數(shù)據(jù)庫(kù)的方面,比如每一次在連接數(shù)據(jù)庫(kù)的時(shí)候都需要手動(dòng)新建一個(gè)連接,然后執(zhí)行數(shù)據(jù)庫(kù)操作,最后再來(lái)關(guān)閉數(shù)據(jù)庫(kù)的連接來(lái)避免資源的消耗。這時(shí)候有人就在想那么可不可以讓系統(tǒng)在我們每一次執(zhí)行數(shù)據(jù)庫(kù)操作的時(shí)候都自動(dòng)的新建一個(gè)連接然后當(dāng)我們執(zhí)行完數(shù)據(jù)庫(kù)的連接之后再自動(dòng)的關(guān)閉連接呢。
這里就需要一個(gè)數(shù)據(jù)庫(kù)
Aop的原理例子(會(huì)使用到cglib動(dòng)態(tài)代理):
例子:
首先新建三個(gè)注解
//定義在類上面標(biāo)明該類是一個(gè)切點(diǎn) @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface MyAspect { } // 前置通知注解 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Before { String value(); } //后置通知注解 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface After { String value(); }
新建一個(gè)歌曲類
public class Music { public void sing(String str){ System.out.println(str+"唱歌"); } }
當(dāng)然,有人唱個(gè)歌就得有人做開(kāi)始前的準(zhǔn)備,例如唱歌前的準(zhǔn)備,于是新建一個(gè)類表示唱歌前的準(zhǔn)備:
@MyAspect // 表明這是一個(gè)切點(diǎn)類 public class Player { @Before("reflec.aop.cglibtest.Music.sing()") // 前置通知,當(dāng)調(diào)用sing方法被調(diào)用的時(shí)候該方法會(huì)被在它之前調(diào)用 public void beforeSing() { System.out.println("開(kāi)始唱歌前的準(zhǔn)備"); } @After("reflec.aop.cglibtest.Music.sing()") // 同理,在調(diào)用sing方法之后再來(lái)調(diào)用該方法 public void afterSing() { System.out.println("唱完之后開(kāi)始評(píng)分"); } }
那么當(dāng)調(diào)用sing方法的時(shí)候我們?cè)鯓诱{(diào)用這兩個(gè)方法呢,即怎樣織入這兩個(gè)方法
這里就得考慮Cglib動(dòng)態(tài)代理了,cglib依賴asm包,在目標(biāo)類的基礎(chǔ)上生成一個(gè)子類,然后通過(guò)子類來(lái)實(shí)現(xiàn)在目標(biāo)方法調(diào)用的時(shí)候?qū)崿F(xiàn)前置或者后置通知。。關(guān)于Cglib的這種,我感覺(jué)應(yīng)該是屬于編譯器織入,因?yàn)槭峭ㄟ^(guò)子類生成字節(jié)碼然后進(jìn)行調(diào)用。
建立代理類:
這個(gè)類的作用只要是通過(guò)動(dòng)態(tài)代理來(lái)實(shí)現(xiàn)那兩個(gè)方法的執(zhí)行
public class CGLIBProxy implements MethodInterceptor { private Object target; private ProxyUtil proxyUtil ; public CGLIBProxy(Object target) throws ClassNotFoundException { this.target = target; proxyUtil =new ProxyUtil(); } publicT getProxy(){ return (T) new Enhancer().create(this.target.getClass(),this); } public T getProxy(Class> clazz){ return (T) new Enhancer().create(this.target.getClass(),this); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { ProxyEntity proxyEntity =new ProxyEntity(proxy,this.target.getClass(),obj,method,args); return proxyUtil.generateEntity(proxyEntity); }
建立反射類:(即主要是通)
public class Reflect { Mapmap ; //存入的是方法名以及其注解 Map clazzMap; public Reflect() throws ClassNotFoundException { map=new HashMap<>(); clazzMap =new HashMap<>(); getAnnotationClass(); } public Map getMap() { // 這里返回的是已經(jīng)全部存好的map方面ProxyUtil使用 return map; } @Test public void getAnnotationClass() throws ClassNotFoundException { String clazzName="reflec.aop.cglibtest.Player"; Class> clazz =Class.forName(clazzName,false,Thread.currentThread().getContextClassLoader()); // 這里為了省事直接動(dòng)態(tài)加載了該類 if (clazz.isAnnotationPresent(MyAspect.class)) { //假設(shè)是注解類 Method[] methods =clazz.getDeclaredMethods(); //遍歷方法 for (Method method :methods) { if (method.isAnnotationPresent(Before.class)) { // 獲取注解 Before before =method.getAnnotation(Before.class); String beforeValue=before.value(); // 獲取注解的值以及當(dāng)前類的名字方面調(diào)用方法 map.put(method.getName()+ "-"+clazzName+"-"+"before",beforeValue.substring(0,beforeValue.length()-2)); // 存入的是方法名和注解名以及執(zhí)行的順序,這里為了省事直接就在后面寫了 if (method.isAnnotationPresent(After.class)) { After after =method.getAnnotation(After.class); / String afterValue=after.value(); map.put(method.getName()+ "-"+clazzName+"-"+"after",afterValue.substring(0,afterValue.length()-2)); } } } }
建立處理這個(gè)Cglib里面的MethodInterceptor接口中的intercept方法的具體類
public class ProxyUtil { Reflect reflect; public ProxyUtil() throws ClassNotFoundException { reflect = new Reflect(); } public void getMethod(String name) { Mapmap = new HashMap<>(); } //該方法負(fù)責(zé)代理 public Object generateEntity(ProxyEntity proxyEntity) throws Throwable { String proxyMethodValue = proxyEntity.getMethod().toString().substring(proxyEntity.getMethod().toString().lastIndexOf(" ") + 1, proxyEntity.getMethod().toString().indexOf("(")); Map methodMap = reflect.getMap(); for (Map.Entry map : methodMap.entrySet()) { if (map.getValue().equals(proxyMethodValue)) { String[] str = mapKeyDivision(map.getKey()); if (str[2].equals("before")) { Class> clazz = Class.forName(str[1], false, Thread.currentThread().getContextClassLoader()); // 加載該類 Method method = clazz.getDeclaredMethod(str[0]); method.invoke(clazz.newInstance(), null); // 反射調(diào)用方法 } } } return doAfter(proxyEntity,methodMap); // 處理后置通知 } private Object doAfter(ProxyEntity proxyEntity,Map map) throws Throwable { Object object = proxyEntity.getMethodProxy().invokeSuper(proxyEntity.getObject(), proxyEntity.getArgs()); // 調(diào)用方法 String proxyMethodValue = proxyEntity.getMethod().toString().substring(proxyEntity.getMethod().toString().lastIndexOf(" ") + 1, proxyEntity.getMethod().toString().indexOf("(")); for(Map.Entry aMap:map.entrySet()){ if (aMap.getValue().equals(proxyMethodValue)){ String[] str =mapKeyDivision(aMap.getKey()); if(str[2].equals("after")){ Class> clazz = Class.forName(str[1], false, Thread.currentThread().getContextClassLoader()); // 加載該類 Method method = clazz.getDeclaredMethod(str[0]); method.invoke(clazz.newInstance(), null); // 這一步需要原始的類 } } } return object; } //分解map里面的鍵,因?yàn)槔锩娲嫒肓朔椒ê皖惷约皥?zhí)行順序 private String[] mapKeyDivision(String value) { String[] str = new String[10]; str[0] = value.substring(0, value.indexOf("-")); //注解下面的方法 str[1] = value.substring(value.indexOf("-") + 1, value.lastIndexOf("-")); //注解所在的類 str[2]=value.substring(value.lastIndexOf("-")+1,value.length()); //是before還是after return str; }
最后是一個(gè)bean
public class ProxyEntity { private final MethodProxy methodProxy; private final Class> clazz; private final Object object; private final Method method; private final Object[] args; public Object getObject() { return object; } public Object[] getArgs() { return args; } public Class> getClazz() { return clazz; } public Method getMethod() { return method; } public ProxyEntity(MethodProxy methodProxy, Class> clazz, Object object, Method method, Object[] args) { this.methodProxy = methodProxy; this.clazz = clazz; this.object = object; this.method = method; this.args = args; } public MethodProxy getMethodProxy() { return methodProxy; } }
最后進(jìn)行測(cè)試:
public class CglibTest { public static void main(String args[]) throws ClassNotFoundException { Music music = new Music(); CGLIBProxy cglibProxy = new CGLIBProxy(music); ((Music)cglibProxy.getProxy()).sing("測(cè)試的人 "); } } 測(cè)試結(jié)果: 開(kāi)始唱歌前的準(zhǔn)備 唱歌測(cè)試的人 唱完之后開(kāi)始評(píng)分
在這個(gè)測(cè)試中并沒(méi)有調(diào)用Player類里面的方法卻在運(yùn)行的時(shí)候自動(dòng)的運(yùn)行了,這個(gè)例子執(zhí)行簡(jiǎn)單的模仿了下Spring的AOP,其實(shí)還有好多地方都沒(méi)有顧及到
這個(gè)類的思路就是先通過(guò)反射獲取到切點(diǎn)類,然后將用注解標(biāo)注的方法名以及注解里面的值存入一個(gè)map,最后在建立一個(gè)類用來(lái)處理map
Github地址:https://github.com/Somersames...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/69896.html
摘要:使用與的靜態(tài)代理不同,使用的動(dòng)態(tài)代理,所謂的動(dòng)態(tài)代理就是說(shuō)框架不會(huì)去修改字節(jié)碼,而是在內(nèi)存中臨時(shí)為方法生成一個(gè)對(duì)象,這個(gè)對(duì)象包含了目標(biāo)對(duì)象的全部方法,并且在特定的切點(diǎn)做了增強(qiáng)處理,并回調(diào)原對(duì)象的方法。 AOP(Aspect Orient Programming),我們一般稱為面向方面(切面)編程,作為面向?qū)ο蟮囊环N補(bǔ)充,用于處理系統(tǒng)中分布于各個(gè)模塊的橫切關(guān)注點(diǎn),比如事務(wù)管理、日志、緩存...
摘要:,,面向切面編程。,切點(diǎn),切面匹配連接點(diǎn)的點(diǎn),一般與切點(diǎn)表達(dá)式相關(guān),就是切面如何切點(diǎn)。例子中,注解就是切點(diǎn)表達(dá)式,匹配對(duì)應(yīng)的連接點(diǎn),通知,指在切面的某個(gè)特定的連接點(diǎn)上執(zhí)行的動(dòng)作。,織入,將作用在的過(guò)程。因?yàn)樵创a都是英文寫的。 之前《零基礎(chǔ)帶你看Spring源碼——IOC控制反轉(zhuǎn)》詳細(xì)講了Spring容器的初始化和加載的原理,后面《你真的完全了解Java動(dòng)態(tài)代理嗎?看這篇就夠了》介紹了下...
摘要:在上文中,我實(shí)現(xiàn)了一個(gè)很簡(jiǎn)單的和容器。比如,我們所熟悉的就是在這里將切面邏輯織入相關(guān)中的。初始化的工作算是結(jié)束了,此時(shí)處于就緒狀態(tài),等待外部程序的調(diào)用。其中動(dòng)態(tài)代理只能代理實(shí)現(xiàn)了接口的對(duì)象,而動(dòng)態(tài)代理則無(wú)此限制。 1. 背景 本文承接上文,來(lái)繼續(xù)說(shuō)說(shuō) IOC 和 AOP 的仿寫。在上文中,我實(shí)現(xiàn)了一個(gè)很簡(jiǎn)單的 IOC 和 AOP 容器。上文實(shí)現(xiàn)的 IOC 和 AOP 功能很單一,且 I...
摘要:又是什么其實(shí)就是一種實(shí)現(xiàn)動(dòng)態(tài)代理的技術(shù),利用了開(kāi)源包,先將代理對(duì)象類的文件加載進(jìn)來(lái),之后通過(guò)修改其字節(jié)碼并且生成子類。 在實(shí)際研發(fā)中,Spring是我們經(jīng)常會(huì)使用的框架,畢竟它們太火了,也因此Spring相關(guān)的知識(shí)點(diǎn)也是面試必問(wèn)點(diǎn),今天我們就大話Aop。特地在周末推文,因?yàn)樵撈恼麻喿x起來(lái)還是比較輕松詼諧的,當(dāng)然了,更主要的是周末的我也在充電學(xué)習(xí),希望有追求的朋友們也盡量不要放過(guò)周末時(shí)...
摘要:我自己總結(jié)的學(xué)習(xí)的系統(tǒng)知識(shí)點(diǎn)以及面試問(wèn)題,已經(jīng)開(kāi)源,目前已經(jīng)。目前最新的版本中模塊的組件已經(jīng)被廢棄掉,同時(shí)增加了用于異步響應(yīng)式處理的組件。每一次請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的,該僅在當(dāng)前內(nèi)有效。顯而易見(jiàn),這種模式存在很多問(wèn)題。 我自己總結(jié)的Java學(xué)習(xí)的系統(tǒng)知識(shí)點(diǎn)以及面試問(wèn)題,已經(jīng)開(kāi)源,目前已經(jīng) 41k+ Star。會(huì)一直完善下去,歡迎建議和指導(dǎo),同時(shí)也歡迎Star: https://githu...
閱讀 2784·2021-09-01 10:30
閱讀 1680·2019-08-30 15:52
閱讀 965·2019-08-29 18:40
閱讀 1116·2019-08-28 18:30
閱讀 2391·2019-08-23 17:19
閱讀 1321·2019-08-23 16:25
閱讀 2700·2019-08-23 16:18
閱讀 2977·2019-08-23 13:53