电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術(shù)文章
文章詳情頁

詳解Java中的反射機(jī)制和動態(tài)代理

瀏覽:82日期:2022-08-10 18:41:11
目錄一、反射概述二、反射之Class類2.1、初識Class類2.2、Class有下面的幾個特點2.3、獲取Class類實例2.4、關(guān)于包裝類的靜態(tài)屬性2.5、通過Class類的其他方法獲取三、Class類的API3.1、創(chuàng)建實例對象3.2、獲取構(gòu)造器3.3、獲取成員變量并使用Field對象的方法3.4、獲取方法并使用method3.5、獲得該類的所有接口3.6、獲取指定資源的輸入流四、反射的應(yīng)用之動態(tài)代理4.1、靜態(tài)代理4.2、JDK中的動態(tài)代理五、動態(tài)代理與AOP簡單實現(xiàn)5.1、AOP是什么5.2、模擬實現(xiàn)AOP一、反射概述

反射機(jī)制指的是Java在運(yùn)行時候有一種自觀的能力,能夠了解自身的情況為下一步做準(zhǔn)備,其想表達(dá)的意思就是:在運(yùn)行狀態(tài)中,對于任意一個類,都能夠獲取到這個類的所有屬性和方法;對于任意一個對象,都能夠調(diào)用它的任意一個方法和屬性(包括私有的方法和屬性),這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能就稱為java語言的反射機(jī)制。通俗點講,通過反射,該類對我們來說是完全透明的,想要獲取任何東西都可以,這是一種動態(tài)獲取類的信息以及動態(tài)調(diào)用對象方法的能力。

想要使用反射機(jī)制,就必須要先獲取到該類的字節(jié)碼文件對象(.class),通過該類的字節(jié)碼對象,就能夠通過該類中的方法獲取到我們想要的所有信息(方法,屬性,類名,父類名,實現(xiàn)的所有接口等等),每一個類對應(yīng)著一個字節(jié)碼文件也就對應(yīng)著一個Class類型的對象,也就是字節(jié)碼文件對象。

Java提供的反射機(jī)制,依賴于我們下面要講到的Class類和java.lang.reflect類庫。我們下面要學(xué)習(xí)使用的主要類有:①Class表示類或者接口;②java.lang.reflect.Field表示類中的成員變量;③java.lang.reflect.Method表示類中的方法;④java.lang.reflect.Constructor表示類的構(gòu)造方法;⑤Array提供動態(tài)數(shù)組的創(chuàng)建和訪問數(shù)組的靜態(tài)方法。

二、反射之Class類2.1、初識Class類

在類Object下面提供了一個方法:

public final native Class<?> getClass()

此方法將會被所有的子類繼承,該方法的返回值為一個Class,這個Class類就是反射的源頭。那么Class類是什么呢?Class類是Java中用來表達(dá)運(yùn)行時類型信息的對應(yīng)類,我們剛剛也說過所有類都會繼承Object類的getClass()方法,那么也體現(xiàn)了著Java中的每個類都有一個Class對象,當(dāng)我們編寫并編譯一個創(chuàng)建的類就會產(chǎn)生對應(yīng)的class文件并將類的信息寫到該class文件中,當(dāng)我們使用正常方式new一個對象或者使用類的靜態(tài)字段時候,JVM的累加器子系統(tǒng)就會將對應(yīng)的Class對象加載到JVM中,然后JVM根據(jù)這個類型信息相關(guān)的Class對象創(chuàng)建我們需要的實例對象或者根據(jù)提供靜態(tài)變量的引用值。將Class類稱為類的類型,一個Class對象稱為類的類型對象。

2.2、Class有下面的幾個特點

①Class也是類的一種(不同于class,class是一個關(guān)鍵字);

②Class類只有一個私有的構(gòu)造函數(shù)

private Class(ClassLoader loader)

只有JVM能夠創(chuàng)建Class類的實例;

③對于同一類的對象,在JVM中只存在唯一一個對應(yīng)的Class類實例來描述其信息;

④每個類的實例都會記得自己是由哪個Class實例所生成;

⑤通過Class可以完整的得到一個類中的完整結(jié)構(gòu);

2.3、獲取Class類實例

剛剛說到過Class只有一個私有的構(gòu)造函數(shù),所以我們不能通過new創(chuàng)建Class實例,有下面這幾種獲取Class實例的方法:

①Class.forName('類的全限定名'),該方法只能獲取引用類型的類類型對象。該方法會拋出異常(a.l類加載器在類路徑中沒有找到該類 b.該類被某個類加載器加載到JVM內(nèi)存中,另外一個類加載器有嘗試從同一個包中加載)

//Class<T> clazz = Class.forName('類的全限定名');這是通過Class類中的靜態(tài)方法forName直接獲取一個Class的對象Class<?> clazz1 = null;try { clazz1 = Class.forName('reflect.Person');} catch (ClassNotFoundException e) { e.printStackTrace();}System.out.println(clazz1); //class reflect.Person

②如果我們有一個類的對象實例,那么通過這個對象的getClass()方法可以獲得他的Class對象,如下所示

//Class<T> clazz = xxx.getClass(); //通過類的實例獲取類的Class對象Class<?> clazz3 = new Person().getClass();System.out.println(clazz3); //class reflect.PersonClass<?> stringClass = 'string'.getClass();System.out.println(stringClass); //class java.lang.String/** * [代表數(shù)組, * B代表byte; * I代表int; * Z代表boolean; * L代表引用類型 * 組合起來就是指定類型的一維數(shù)組,如果是[[就是二維數(shù)組 */Class<?> arrClass = new byte[20].getClass();System.out.println(arrClass); //class [BClass<?> arrClass1 = new int[20].getClass();System.out.println(arrClass1); //class [IClass<?> arrClass2 = new boolean[20].getClass();System.out.println(arrClass2); //class [ZClass<?> arrClass3 = new Person[20].getClass();System.out.println(arrClass3); //class [Lreflect.Person;Class<?> arrClass4 = new String[20].getClass();System.out.println(arrClass4); //class [Ljava.lang.String;

③通過類的class字節(jié)碼文件獲取,通過類名.class獲取該類的Class對象

//Class<T> clazz = XXXClass.class; 當(dāng)類已經(jīng)被加載為.class文件時候,Class<Person> clazz2 = Person.class;System.out.println(clazz2);System.out.println(int [][].class);//class [[ISystem.out.println(Integer.class);//class java.lang.Integer2.4、關(guān)于包裝類的靜態(tài)屬性

我們知道,在Java中對于基本類型和void都有對應(yīng)的包裝類。在包裝類中有一個靜態(tài)屬性TYPE保存了該類的類類型。如下所示

/** * The {@code Class} instance representing the primitive type * {@code int}. * * @since JDK1.1 */ @SuppressWarnings('unchecked') public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass('int');

我們使用這個靜態(tài)屬性來獲得Class實例,如下所示

Class c0 = Byte.TYPE; //byteClass c1 = Integer.TYPE; //intClass c2 = Character.TYPE; //charClass c3 = Boolean.TYPE; //booleanClass c4 = Short.TYPE; //shortClass c5 = Long.TYPE; //longClass c6 = Float.TYPE; //floatClass c7 = Double.TYPE; //doubleClass c8 = Void.TYPE; //void2.5、通過Class類的其他方法獲取

①public native Class<? super T> getSuperclass():獲取該類的父類

Class c1 = Integer.class;Class par = c1.getSuperclass();System.out.println(par); //class java.lang.Number

②public Class<?>[] getClasses():獲取該類的所有公共類、接口、枚舉組成的Class數(shù)組,包括繼承的;

③public Class<?>[] getDeclaredClasses():獲取該類的顯式聲明的所有類、接口、枚舉組成的Class數(shù)組;

④(Class/Field/Method/Constructor).getDeclaringClass():獲取該類/屬性/方法/構(gòu)造器所在的類

三、Class類的API

這是下面測試用例中使用的Person類和實現(xiàn)的接口

package reflect;interface Test { String test = 'interface';}public class Person implements Test{ private String id; private String name; public void sing(String name) {System.out.println(getName() + '會唱' + name +'歌'); } private void dance(String name) {System.out.println(getName() + '會跳' + name + '舞'); } public void playBalls() {System.out.println(getName() + '會打籃球'); } public String getId() {return id; } public void setId(String id) {this.id = id; } public String getName() {return name; } public void setName(String name) {this.name = name; } public Person() { } public Person(String id, String name) {this.id = id;this.name = name; } public Person(String id) {this.id = id; } @Override public String toString() {return 'Person{' +'id=’' + id + ’’’ +', name=’' + name + ’’’ +’}’; }}//Person3.1、創(chuàng)建實例對象

public void test4() throws Exception{ Class clazz =Class.forName('reflect.Person'); Person person = (Person)clazz.newInstance(); System.out.println(person);}

創(chuàng)建運(yùn)行時類的對象,使用newInstance(),實際上就是調(diào)用運(yùn)行時指定類的無參構(gòu)造方法。這里也說明要想創(chuàng)建成功,需要對應(yīng)的類有無參構(gòu)造器,并且構(gòu)造器的權(quán)限要足夠,否則會拋出下面的異常。

①我們顯示聲明Person類一個帶參構(gòu)造,并沒有無參構(gòu)造,這種情況會拋出InstantiationException

詳解Java中的反射機(jī)制和動態(tài)代理

②更改無參構(gòu)造器訪問權(quán)限為private

詳解Java中的反射機(jī)制和動態(tài)代理

3.2、獲取構(gòu)造器

(1)獲取指定可訪問的構(gòu)造器創(chuàng)建對象實例

上面我們所說的使用newInstance方法創(chuàng)建對象,如果不指定任何參數(shù)的話默認(rèn)是調(diào)用指定類的無參構(gòu)造器的。那么如果沒有無參構(gòu)造器,又想創(chuàng)建對象實例怎么辦呢,就使用Class類提供的獲取構(gòu)造器的方法,顯示指定我們需要調(diào)用哪一個無參構(gòu)造器。

@Testpublic void test5() throws Exception { Class clazz = Class.forName('reflect.Person'); //獲取帶參構(gòu)造器 Constructor constructor = clazz.getConstructor(String.class, String .class); //通過構(gòu)造器來實例化對象 Person person = (Person) constructor.newInstance('p1', 'person'); System.out.println(person);}

當(dāng)我們指定的構(gòu)造器全部不夠(比如設(shè)置為private),我們在調(diào)用的時候就會拋出下面的異常

詳解Java中的反射機(jī)制和動態(tài)代理

(2)獲得全部構(gòu)造器

@Testpublic void test6() throws Exception { Class clazz1 = Class.forName('reflect.Person'); Constructor[] constructors = clazz1.getConstructors(); for (Constructor constructor : constructors) {Class[] parameters = constructor.getParameterTypes();System.out.println('構(gòu)造函數(shù)名:' + constructor + 'n' + '參數(shù)');for (Class c: parameters) { System.out.print(c.getName() + ' ');}System.out.println(); }}

運(yùn)行結(jié)果如下

詳解Java中的反射機(jī)制和動態(tài)代理

3.3、獲取成員變量并使用Field對象的方法

(1)Class.getField(String)方法可以獲取類中的指定字段(可見的), 如果是私有的可以用getDeclaedField('name')方法獲取,通過set(對象引用,屬性值)方法可以設(shè)置指定對象上該字段的值, 如果是私有的需要先調(diào)用setAccessible(true)設(shè)置訪問權(quán)限,用獲取的指定的字段調(diào)用get(對象引用)可以獲取指定對象中該字段的值。

@Testpublic void test7() throws Exception { Class clazz1 = Class.forName('reflect.Person'); //獲得實例對象 Person person = (Person) clazz1.newInstance(); /** * 獲得類的屬性信息 * 使用getField(name),通過指定的屬性name獲得 * 如果屬性不是public的,使用getDeclaredField(name)獲得 */ Field field = clazz1.getDeclaredField('id'); //如果是private的,需要設(shè)置權(quán)限為可訪問 field.setAccessible(true); //設(shè)置成員變量的屬性值 field.set(person, 'person1'); //獲取成員變量的屬性值,使用get方法,其中第一個參數(shù)表示獲得字段的所屬對象,第二個參數(shù)表示設(shè)置的值 System.out.println(field.get(person)); //這里的field就是id屬性,打印person對象的id屬性的值}

(2)獲得全部成員變量

@Testpublic void test8() throws Exception{ Class clazz1 = Class.forName('reflect.Person'); //獲得實例對象 Person person = (Person) clazz1.newInstance(); person.setId('person1'); person.setName('person1_name'); Field[] fields = clazz1.getDeclaredFields(); for (Field f : fields) {//打開private成員變量的可訪問權(quán)限f.setAccessible(true);System.out.println(f+ ':' + f.get(person)); }}

詳解Java中的反射機(jī)制和動態(tài)代理

3.4、獲取方法并使用method

(1)使用Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...)方法可以獲取類中的指定方法,如果為私有方法,則需要打開一個權(quán)限。setAccessible(true);用invoke(Object, Object...)可以調(diào)用該方法。如果是私有方法而使用的是getMethod方法來獲得會拋出NoSuchMethodException

@Testpublic void test9() throws Exception{ Class clazz1 = Class.forName('reflect.Person'); //獲得實例對象 Person person = (Person) clazz1.newInstance(); person.setName('Person'); //①不帶參數(shù)的public方法 Method playBalls = clazz1.getMethod('playBalls'); //調(diào)用獲得的方法,需要指定是哪一個對象的 playBalls.invoke(person); //②帶參的public方法:第一個參數(shù)是方法名,后面的可變參數(shù)列表是參數(shù)類型的Class類型 Method sing = clazz1.getMethod('sing',String.class); //調(diào)用獲得的方法,調(diào)用時候傳遞參數(shù) sing.invoke(person,'HaHaHa...'); //③帶參的private方法:使用getDeclaredMethod方法 Method dance = clazz1.getDeclaredMethod('dance', String.class); //調(diào)用獲得的方法,需要先設(shè)置權(quán)限為可訪問 dance.setAccessible(true); dance.invoke(person,'HaHaHa...');}

(2)獲得所有方法(不包括構(gòu)造方法)

@Testpublic void test10() throws Exception{ Class clazz1 = Class.forName('reflect.Person'); //獲得實例對象 Person person = (Person) clazz1.newInstance(); person.setName('Person'); Method[] methods = clazz1.getDeclaredMethods(); for (Method method: methods) {System.out.print('方法名' + method.getName() + '的參數(shù)是:');//獲得方法參數(shù)Class[] params = method.getParameterTypes();for (Class c : params) { System.out.print(c.getName() + ' ');}System.out.println(); }}3.5、獲得該類的所有接口

Class[] getInterfaces():確定此對象所表示的類或接口實現(xiàn)的接口,返回值:接口的字節(jié)碼文件對象的數(shù)組

@Testpublic void test11() throws Exception{ Class clazz1 = Class.forName('reflect.Person'); Class[] interfaces = clazz1.getInterfaces(); for (Class inter : interfaces) {System.out.println(inter); }}3.6、獲取指定資源的輸入流

InputStreamgetResourceAsStream(String name),返回值:一個 InputStream 對象;如果找不到帶有該名稱的資源,則返回null;參數(shù):所需資源的名稱,如果以'/'開始,則絕對資源名為'/'后面的一部分。

@Testpublic void test12() throws Exception { ClassLoader loader = this.getClass().getClassLoader(); System.out.println(loader);//sun.misc.Launcher$AppClassLoader@18b4aac2 ,應(yīng)用程序類加載器 System.out.println(loader.getParent());//sun.misc.Launcher$ExtClassLoader@31befd9f ,擴(kuò)展類加載器 System.out.println(loader.getParent().getParent());//null ,不能獲得啟動類加載器 Class clazz = Person.class;//自定義的類 ClassLoader loader2 = clazz.getClassLoader(); System.out.println(loader2);//sun.misc.Launcher$AppClassLoader@18b4aac2 //下面是獲得InputStream的例子 ClassLoader inputStreamLoader = this.getClass().getClassLoader(); InputStream inputStream = inputStreamLoader.getResourceAsStream('person.properties'); Properties properties = new Properties(); properties.load(inputStream); System.out.println('id:' + properties.get('id')); System.out.println('name:' + properties.get('name'));}

其中properties文件內(nèi)容

id = person001

name = person-name1

四、反射的應(yīng)用之動態(tài)代理

代理模式在Java中應(yīng)用十分廣泛,它說的是使用一個代理將對象包裝起來然后用該代理對象取代原始對象,任何原始對象的調(diào)用都需要通過代理對象,代理對象決定是否以及何時將方法調(diào)用轉(zhuǎn)到原始對象上。這種模式可以這樣簡單理解:你自己想要做某件事情(被代理類),但是覺得自己做非常麻煩或者不方便,所以就叫一個另一個人(代理類)來幫你做這個事情,而你自己只需要告訴要做啥事就好了。上面我們講到了反射,在下面我們會說一說java中的代理

4.1、靜態(tài)代理

靜態(tài)代理其實就是程序運(yùn)行之前,提前寫好被代理類的代理類,編譯之后直接運(yùn)行即可起到代理的效果,下面會用簡單的例子來說明。在例子中,首先我們有一個頂級接口(ProductFactory),這個接口需要代理類(ProxyTeaProduct)和被代理類(TeaProduct)都去實現(xiàn)它,在被代理類中我們重寫需要實現(xiàn)的方法(action),該方法會交由代理類去選擇是否執(zhí)行和在何處執(zhí)行;被代理類中主要是提供頂級接口的的一個引用但是引用實際指向的對象則是實現(xiàn)了該接口的代理類(使用多態(tài)的特點,在代理類中提供構(gòu)造器傳遞實際的對象引用)。分析之后,我們通過下面這個圖理解一下這個過程。

詳解Java中的反射機(jī)制和動態(tài)代理

package proxy;/** * 靜態(tài)代理 *///產(chǎn)品接口interface ProductFactory { void action();}//一個具體產(chǎn)品的實現(xiàn)類,作為一個被代理類class TeaProduct implements ProductFactory{ @Override public void action() {System.out.println('我是生產(chǎn)茶葉的......'); }}//TeaProduct的代理類class ProxyTeaProduct implements ProductFactory { //我們需要ProductFactory的一個實現(xiàn)類,去代理這個實現(xiàn)類中的方法(多態(tài)) ProductFactory productFactory; //通過構(gòu)造器傳入實際被代理類的對象,這時候代理類調(diào)用action的時候就可以在其中執(zhí)行被代理代理類的方法了 public ProxyTeaProduct(ProductFactory productFactory) {this.productFactory = productFactory; } @Override public void action() {System.out.println('我是代理類,我開始代理執(zhí)行方法了......');productFactory.action(); }}public class TestProduct { public static void main(String[] args) {//創(chuàng)建代理類的對象ProxyTeaProduct proxyTeaProduct = new ProxyTeaProduct(new TeaProduct());//執(zhí)行代理類代理的方法proxyTeaProduct.action(); }}

那么程序測試的輸出結(jié)果也很顯然了,代理類執(zhí)行自己實現(xiàn)的方法,而在其中有調(diào)用了被代理類的方法

詳解Java中的反射機(jī)制和動態(tài)代理

那么我們想一下,上面這種稱為靜態(tài)代理的方式有什么缺點呢?因為每一個代理類只能為一個借口服務(wù)(因為這個代理類需要實現(xiàn)這個接口,然后去代理接口實現(xiàn)類的方法),這樣一來程序中就會產(chǎn)生過多的代理類。比如說我們現(xiàn)在又來一個接口,那么是不是也需要提供去被代理類去實現(xiàn)它然后交給代理類去代理執(zhí)行呢,那這樣程序就不靈活了。那么如果有一種方式,就可以處理新添加接口的以及實現(xiàn)那不就更加靈活了嗎,在java中反射機(jī)制的存在為動態(tài)代理創(chuàng)造了機(jī)會

4.2、JDK中的動態(tài)代理

動態(tài)代理是指通過代理類來調(diào)用它對象的方法,并且是在程序運(yùn)行使其根據(jù)需要創(chuàng)建目標(biāo)類型的代理對象。它只提供一個代理類,我們只需要在運(yùn)行時候動態(tài)傳遞給需要他代理的對象就可以完成對不同接口的服務(wù)了。看下面的例子。(JDK提供的代理正能針對接口做代理,也就是下面的newProxyInstance返回的必須要是一個接口)

package proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * JDK中的動態(tài)代理 *///第一個接口interface TargetOne { void action();}//第一個接口的被代理類class TargetOneImpl implements TargetOne{ @Override public void action() {System.out.println('我會實現(xiàn)父接口的方法...action'); }}//動態(tài)代理類class DynamicProxyHandler implements InvocationHandler { //接口的一個引用,多態(tài)的特性會使得在程序運(yùn)行的時候,它實際指向的是實現(xiàn)它的子類對象 private TargetOne targetOne; //我們使用Proxy類的靜態(tài)方法newProxyInstance方法,將代理對象偽裝成那個被代理的對象 /** * ①這個方法會將targetOne指向?qū)嶋H實現(xiàn)接口的子類對象 * ②根據(jù)被代理類的信息返回一個代理類對象 */ public Object setObj(TargetOne targetOne) {this.targetOne = targetOne;// public static Object newProxyInstance(ClassLoader loader, //被代理類的類加載器// Class<?>[] interfaces, //被代理類實現(xiàn)的接口// InvocationHandler h) //實現(xiàn)InvocationHandler的代理類對象return Proxy.newProxyInstance(targetOne.getClass().getClassLoader(),targetOne.getClass().getInterfaces(),this); } //當(dāng)通過代理類的對象發(fā)起對接口被重寫的方法的調(diào)用的時候,都會轉(zhuǎn)換為對invoke方法的調(diào)用 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println('這是我代理之前要準(zhǔn)備的事情......');/** * 這里回想一下在靜態(tài)代理的時候,我們顯示指定代理類需要執(zhí)行的是被代理類的哪些方法; * 而在這里的動態(tài)代理實現(xiàn)中,我們并不知道代理類會實現(xiàn)什么方法,他是根據(jù)運(yùn)行時通過反射來 * 知道自己要去指定被代理類的什么方法的 */Object returnVal = method.invoke(this.targetOne,args);//這里的返回值,就相當(dāng)于真正調(diào)用的被代理類方法的返回值System.out.println('這是我代理之后要處理的事情......');return returnVal; }}public class TestProxy { public static void main(String[] args) {//創(chuàng)建被代理類的對象TargetOneImpl targetOneImpl = new TargetOneImpl();//創(chuàng)建實現(xiàn)了InvocationHandler的代理類對象,然后調(diào)用其中的setObj方法完成兩項操作//①將被代理類對象傳入,運(yùn)行時候調(diào)用的是被代理類重寫的方法//②返回一個類對象,通過代理類對象執(zhí)行接口中的方法DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler();TargetOne targetOne = (TargetOne) dynamicProxyHandler.setObj(targetOneImpl);targetOne.action(); //調(diào)用該方法運(yùn)行時都會轉(zhuǎn)為對DynamicProxyHandler中的invoke方法的調(diào)用 }}

運(yùn)行結(jié)果如下。現(xiàn)在我們對比jdk提供的動態(tài)代理和我們剛剛實現(xiàn)的靜態(tài)代理,剛剛說到靜態(tài)代理對于新添加的接口需要定義對應(yīng)的代理類去代理接口的實現(xiàn)類。而上面的測試程序所使用的動態(tài)代理規(guī)避了這個問題,即我們不需要顯示的指定每個接口對應(yīng)的代理類,有新的接口添加沒有關(guān)系,只需要在使用的時候傳入接口對應(yīng)的實現(xiàn)類然后返回代理類對象(接口實現(xiàn)類型),然后調(diào)用被代理類的方法即可。

詳解Java中的反射機(jī)制和動態(tài)代理

五、動態(tài)代理與AOP簡單實現(xiàn)5.1、AOP是什么

AOP(Aspect Orient Programming)我們一般稱之為面向切面編程,作為一種面向?qū)ο蟮难a(bǔ)充,用于處理系統(tǒng)中分布于各個模塊的橫切關(guān)注點,比如事務(wù)管理、日志記錄等。AOP實現(xiàn)的關(guān)鍵在于AOP的代理(實際實現(xiàn)上有靜態(tài)代理和動態(tài)代理),我們下面使用JDK的動態(tài)代理的方式模擬實現(xiàn)下面的場景。

5.2、模擬實現(xiàn)AOP

我們先考慮下面圖中的情況和說明。然后我們使用動態(tài)代理的思想模擬簡單實現(xiàn)一下這個場景

詳解Java中的反射機(jī)制和動態(tài)代理

package aop;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;//基于jdk的針對接口實現(xiàn)動態(tài)代理,要求的接口interface Target { void login(); void logout();}//被代理類class TargetImpl implements Target { @Override public void login() {System.out.println('log......'); } @Override public void logout() {System.out.println('logout......'); }}class Util { public void printLog() {System.out.println('我是記錄打印日志功能的方法......'); } public void getProperties() {System.out.println('我是獲取配置文件信息功能的方法......'); }}//實現(xiàn)了InvocationHandler的統(tǒng)一代理類class DynamicProxyHandler implements InvocationHandler { private Object object; /** * 參數(shù)為obj,是應(yīng)對對不同的被代理類,都能綁定與該代理類的代理關(guān)系 * 這個方法會將targetOne指向?qū)嶋H實現(xiàn)接口的子類對象,即當(dāng)前代理類實際要去代理的那個類 */ public void setObj(Object obj) {this.object = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Util util = new Util();util.getProperties();Object object = method.invoke(this.object, args); //這個方法是個動態(tài)的方法,可以是login,可以是logout,具體在測試調(diào)用中調(diào)用不同方法util.printLog();return object; }}//該類的主要作用就是動態(tài)的創(chuàng)建一個代理類的對象,同時需要執(zhí)行被代理類class MyDynamicProxyUtil { //參數(shù)obj表示動態(tài)的傳遞進(jìn)來被代理類的對象 public static Object getProxyInstance(Object object) {//獲取代理類對象DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler();dynamicProxyHandler.setObj(object);//設(shè)置好代理類與被代理類之間的關(guān)系后,返回一個代理類的對象return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), dynamicProxyHandler); }}public class TestAop { public static void main(String[] args) {//獲得被代理類Target target = new TargetImpl();//通過代理類工具類,設(shè)置實際與代理類綁定的被代理類,并返回一個代理類對象執(zhí)行實際的方法Target execute = (Target) MyDynamicProxyUtil.getProxyInstance(target);execute.login();execute.logout(); }}

詳解Java中的反射機(jī)制和動態(tài)代理

現(xiàn)在來分析一下上面的代碼,首先我們看一下下面的這個圖。在圖中動態(tài)代理增加的通用日志方法、配置文件方法就是增加的方法,他在執(zhí)行用戶實際自己開發(fā)的方法之前、之后調(diào)用。對應(yīng)于上面的程序就是Target接口的實現(xiàn)類實現(xiàn)的login、logout方法被代理類動態(tài)的調(diào)用,在他們執(zhí)行之前會調(diào)用日志模塊和配置文件模塊的功能。

詳解Java中的反射機(jī)制和動態(tài)代理

以上就是詳解Java中的反射機(jī)制和動態(tài)代理的詳細(xì)內(nèi)容,更多關(guān)于Java 反射機(jī)制 動態(tài)代理的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 服务器之家 - 专注于服务器技术及软件下载分享 | 导电银胶_LED封装导电银胶_半导体封装导电胶厂家-上海腾烁 | 云南外加剂,云南速凝剂,云南外加剂代加工-普洱澜湄新材料科技有限公司 | 宿舍管理系统_智慧园区系统_房屋/房产管理系统_公寓管理系统 | 大巴租车平台承接包车,通勤班车,巴士租赁业务 - 鸿鸣巴士 | 量子管通环-自清洗过滤器-全自动反冲洗过滤器-沼河浸过滤器 | 特材真空腔体_哈氏合金/镍基合金/纯镍腔体-无锡国德机械制造有限公司 | 回转支承-转盘轴承-回转驱动生产厂家-洛阳隆达轴承有限公司 | 天津货架厂_穿梭车货架_重型仓储货架_阁楼货架定制-天津钢力仓储货架生产厂家_天津钢力智能仓储装备 | 深圳装修_店面装修设计_餐厅设计_装修全包价格-尚泰装饰设计 | 行吊_电动单梁起重机_双梁起重机_合肥起重机_厂家_合肥市神雕起重机械有限公司 | 碳纤维复合材料制品生产定制工厂订制厂家-凯夫拉凯芙拉碳纤维手机壳套-碳纤维雪茄盒外壳套-深圳市润大世纪新材料科技有限公司 | 交流伺服电机|直流伺服|伺服驱动器|伺服电机-深圳市华科星电气有限公司 | SRRC认证_电磁兼容_EMC测试整改_FCC认证_SDOC认证-深圳市环测威检测技术有限公司 | 上海橡胶接头_弹簧减震器_金属软接头厂家-上海淞江集团 | LED灯杆屏_LED广告机_户外LED广告机_智慧灯杆_智慧路灯-太龙智显科技(深圳)有限公司 | 济南玻璃安装_济南玻璃门_济南感应门_济南玻璃隔断_济南玻璃门维修_济南镜片安装_济南肯德基门_济南高隔间-济南凯轩鹏宇玻璃有限公司 | 针焰试验仪,灼热丝试验仪,漏电起痕试验仪,水平垂直燃烧试验仪 - 苏州亚诺天下仪器有限公司 | 成都APP开发-成都App定制-成都app开发公司-【未来久】 | 【中联邦】增稠剂_增稠粉_水性增稠剂_涂料增稠剂_工业增稠剂生产厂家 | 压片机_高速_单冲_双层_花篮式_多功能旋转压片机-上海天九压片机厂家 | 真空搅拌机-行星搅拌机-双行星动力混合机-广州市番禺区源创化工设备厂 | 北京模型公司-军事模型-工业模型制作-北京百艺模型沙盘公司 | 碳纤维复合材料制品生产定制工厂订制厂家-凯夫拉凯芙拉碳纤维手机壳套-碳纤维雪茄盒外壳套-深圳市润大世纪新材料科技有限公司 | 欧美日韩国产一区二区三区不_久久久久国产精品无码不卡_亚洲欧洲美洲无码精品AV_精品一区美女视频_日韩黄色性爱一级视频_日本五十路人妻斩_国产99视频免费精品是看4_亚洲中文字幕无码一二三四区_国产小萍萍挤奶喷奶水_亚洲另类精品无码在线一区 | 液氨泵,液化气泵-淄博「亚泰」燃气设备制造有限公司 | 楼梯定制_楼梯设计施工厂家_楼梯扶手安装制作-北京凌步楼梯 | 锡膏喷印机-全自动涂覆机厂家-全自动点胶机-视觉点胶机-深圳市博明智控科技有限公司 | 鼓风干燥箱_真空烘箱_高温干燥箱_恒温培养箱-上海笃特科学仪器 | 聚丙烯酰胺PAM-聚合氯化铝PAC-絮凝剂-河南博旭环保科技有限公司 巨野电机维修-水泵维修-巨野县飞宇机电维修有限公司 | 999范文网_优质范文下载写作帮手 | 专业生产动态配料系统_饲料配料系统_化肥配料系统等配料系统-郑州鑫晟重工机械有限公司 | arch电源_SINPRO_开关电源_模块电源_医疗电源-东佑源 | 专注提供国外机电设备及配件-工业控制领域一站式服务商-深圳市华联欧国际贸易有限公司 | TwistDx恒温扩增-RAA等温-Jackson抗体-默瑞(上海)生物科技有限公司 | VOC检测仪-甲醛检测仪-气体报警器-气体检测仪厂家-深恒安科技有限公司 | 众能联合-提供高空车_升降机_吊车_挖机等一站工程设备租赁 | 电磁流量计厂家_涡街流量计厂家_热式气体流量计-青天伟业仪器仪表有限公司 | 家用净水器代理批发加盟_净水机招商代理_全屋净水器定制品牌_【劳伦斯官网】 | 飞扬动力官网-广告公司管理软件,广告公司管理系统,喷绘写真条幅制作管理软件,广告公司ERP系统 | 拉力测试机|材料拉伸试验机|电子拉力机价格|万能试验机厂家|苏州皖仪实验仪器有限公司 |