国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

使用Java動態代理技術實現AOP

2019-11-06 07:07:29
字體:
來源:轉載
供稿:網友

實現動態代理

根據網絡上很多資料,實現一個業務接口的動態代理只需要三步: - 定義業務接口 - 定義實現業務接口的業務類 - 根據PRoxy類創建任何接口的代理類

第一:定義業務接口

AnimalInterface.java

package proxy.imp;/** * 動態代理的業務接口定義 * * @ClassName: AnimalInterface * @Description: TODO(這里用一句話描述這個類的作用) * @author PengRong * @date 2017年3月5日 下午3:52:15 * */public interface AnimalInterface { // 設置名字 void setName(String name); // 獲取名字 String getName(); // 叫聲 void say(); // 獲取棲性 void getProperty(); // 設置棲性 void setProperty(String Property);}

第二:定義一個實現業務接口的具體類,也叫委托類,等下被代理的類

DogImp.java

package proxy;import proxy.annon.Seven;import proxy.imp.AnimalInterface;/** * 實現接口的具體業務類 * * @ClassName: DogImp * @Description: TODO(這里用一句話描述這個類的作用) * @author PengRong * @date 2017年3月5日 下午3:53:12 * */public class DogImp implements AnimalInterface { @Seven(value = "Lumia") private String name; private String Property; public DogImp() { } @Override public void setName(String name) { this.name = name; } @Override public String getName() { return this.name; } @Override public void say() { System.out.println("小狗:汪汪汪汪....."); } @Override @Seven(Property = "水陸兩棲戰士") public void setProperty(String Property) { this.Property = Property; } @Override public void getProperty() { System.out.println(this.name + "= " + this.Property); }}

可以看到我這里使用了注解給具體業務類屬性賦值的技術,所以就引入了注解的定義和解析;詳情可看下面

第三步:先要實現一個調用處理器,然后Proxy類動態生成代理類。

實現調用處理器

AOPHandle.java

package proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import proxy.imp.AOPMethod;/* * 調用處理器,每一個代理類都必須有一個關聯的調用處理器,當代理類上的一個方法被調用都會被分發到這個調用處理器上 * 的invoke方法上面; InvocationHandler接口被實現可以作為代理類的調用處理器功能 * @ClassName: AOPHandle * @Description: TODO(這里用一句話描述這個類的作用) * @author PengRong * @date 2017年3月5日 下午3:55:29 * */public class AOPHandle implements InvocationHandler { // 保存AOP切入的接口引用 private AOPMethod method; /** * 被代理的對象 */ private Object o; /** * * 創建一個新的實例 AOPHandle. * * @param o * 委托類實例引用 * @param method */ public AOPHandle(Object o, AOPMethod method) { this.o = o; this.method = method; } /** * 這個方法會自動調用,Java動態代理機制 會傳入下面是個參數 * * @param Object * proxy 代理對象的接口,不同于對象 * @param Method * method 被調用方法業務接口 * @param Object[] * args 方法參數 不能使用invoke時使用proxy作為反射參數時,因為代理對象的接口,不同于對象 * 這種代理機制是面向接口,而不是面向類的 **/ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object ret = null; if (this.method != null) { // 修改的地方在這里哦 this.method.before(proxy, method, args); // 反射調用方法 ret = method.invoke(o, args); // 修改的地方在這里哦 this.method.after(proxy, method, args); } else {//無AOP的路徑 System.out.println("invocation handler before"); ret = method.invoke(o, args); System.out.println("invocation hander after"); } return ret; }}

代理類動態生成:這個是生成動態代理類的核心

AnimalFactory.java

package proxy;import java.lang.reflect.Proxy;import proxy.annon.AnnoInjection;import proxy.imp.AOPMethod;/** * 根據 傳進來的委托實例引用創建并返回代理類引用 * * @ClassName: AnimalFactory * @Description: TODO(這里用一句話描述這個類的作用) * @author PengRong * @date 2017年3月5日 下午4:13:37 * */public class AnimalFactory { /*** * 獲取對象方法 * * @param obj * @return */ private static Object getAnimalBase(Object obj, AOPMethod method) { // 獲取代理對象 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new AOPHandle(AnnoInjection.getBean(obj), method)); } /*** * 獲取對象方法 * * @param obj * @return */ @SuppressWarnings("unchecked") public static <T> T getAnimal(Object obj, AOPMethod aopMethod) { return (T) getAnimalBase(obj, aopMethod); } /*** * 獲取對象方法 * * @param className * @return */ @SuppressWarnings("unchecked") public static <T> T getAnimal(String className, AOPMethod method) { Object obj = null; try { obj = getAnimalBase(Class.forName(className).newInstance(), method); } catch (Exception e) { e.printStackTrace(); } return (T) obj; } /*** * 獲取對象方法 * * @param clz * @return */ @SuppressWarnings("unchecked") public static <T> T getAnimal(Class<?> clz, AOPMethod method) { Object obj = null; try { obj = getAnimalBase(clz.newInstance(), method); } catch (Exception e) { e.printStackTrace(); } return (T) obj; }}

然后就可以進行測試了 先進行注解的測試,看我在代碼中注解的值到底有沒有賦值到類實例中;

注解測試

package proxy;import proxy.annon.AnnoInjection;public class TestInjection { /*** * 創建一個實例然后,通過注入邏輯自動將注解的內容賦值給實例屬性 */ public static void main(String[] args) throws InterruptedException { DogImp dogImp = (DogImp) AnnoInjection.getBean(new DogImp());//等下還會介紹其中的處理邏輯 Thread.sleep(100); System.out.println(dogImp.getName()); dogImp.getProperty(); }}

輸出結果:可以看到輸出結果我沒有對實例屬性進行任何的賦值操作,但是最后兩句輸出已經可以看出屬性已經有值了。前兩句是注入邏輯中輸出的log,可以看到進行了一次屬性注入,一次方法注入。

注入 name 屬性 Lumia注入 setProperty 方法注解 水陸兩棲戰士LumiaLumia= 水陸兩棲戰士

代理類測試

上面我們是建立了一個簡單的基于接口的動態代理技術框架,動態代理技術主要有委托接口,以及委托類,調用處理器,代理類動態生成這些技術組成;下面給出代理類的測試案例。

package proxy;import java.lang.reflect.Method;import proxy.imp.AOPMethod;import proxy.imp.AnimalInterface;public class AOPTest { public static void main(String[] args) { /** * 返回的dog為代理實例 */ AnimalInterface dog = AnimalFactory.getAnimal(DogImp.class, null);//通過這個函數調用返回DogImp類的代理類; //注意下這里為什么第二個參數為null,這個就是AOP切入的位置 dog.say();// 實體的一個行為 String name1 = "我的名字是= " + dog.getName();// 通過這個可以看到可以將注解注入到屬性中 System.out.println(name1); dog.setName("二狗子"); String name2 = "我的名字是" + dog.getName(); System.out.println(name2); dog.getProperty(); }}

輸出結果:看到注解注入成功,然后在注解處理器中走得是無AOP的路徑。

注入 name 屬性 Lumia注入 setProperty 方法注解 水陸兩棲戰士invocation handler before小狗:汪汪汪汪.....invocation hander afterinvocation handler beforeinvocation hander after我的名字是= Lumiainvocation handler beforeinvocation hander afterinvocation handler beforeinvocation hander after我的名字是二狗子invocation handler before二狗子= 水陸兩棲戰士invocation hander after

自定義注解并用于給屬性賦值

定義注解

Seven.java文件

package proxy.annon;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * 自定義的注解 * * @ClassName: Seven * @Description: TODO(這里用一句話描述這個類的作用) * @author PengRong * @date 2017年3月5日 下午4:20:44 * */@Retention(RetentionPolicy.RUNTIME) // 表示這個注解可以生存到運行期@Target({ ElementType.FIELD, ElementType.METHOD }) // 指定注解的使用范圍public @interface Seven { // 設定注解的方法,注解方法沒有方法體,可以設置默認值 public String value() default "小黑"; public String Property() default "無屬性";}

注解注入

注解自動注入是在程序定義一個空實例后,根據注解進行自動注入。根據剛才自定義的注解可以這個注解只能用于字段,函數中,所有自動注入邏輯主要是遍歷一個變量的所有字段和函數,然后查看是否具有指定的Seven注解,然后讀取我們在源碼中設置的值并通過反射機制屬性對應的setXXX方法完成初始化。

package proxy.annon;import java.lang.reflect.Field;import java.lang.reflect.Method;/* * 注解注入,將一個業務類實例的注解自動賦值給類屬性 * @ClassName: AnnoInjection * @Description: TODO(這里用一句話描述這個類的作用) * @author PengRong * @date 2017年3月5日 下午4:22:52 * */public class AnnoInjection { public static Object getBean(Object obj) { try { // 獲得類屬性 Field f[] = obj.getClass().getDeclaredFields(); // 遍歷屬性,查找所有的屬性注解 for (Field ff : f) { // 獲得屬性上的注解 Seven s = ff.getAnnotation(Seven.class);// 返回ff屬性的Seven類型的注解 if (s != null) { System.err.println("注入 " + ff.getName() + " 屬性" + "/t/t" + s.value()); // 反射調用public set方法,如果訪問級別為private,那么可以直接使用屬性的set(obj, // value); obj.getClass() .getMethod("set" + ff.getName().substring(0, 1).toUpperCase() + ff.getName().substring(1), // 組配函數名稱出來 new Class<?>[] { String.class }) .invoke(obj, s.value());// 通過反射調用屬性對應的setXXX函數將注解的值賦值給類屬性 } } // 獲得所有方法,查找方法注解 Method m[] = obj.getClass().getDeclaredMethods(); for (Method mm : m) { // 獲得方法注解 Seven s = mm.getAnnotation(Seven.class); if (s != null) { System.err.println("注入 " + mm.getName() + " 方法注解" + "/t" + s.Property()); mm.invoke(obj, s.Property());// 通過方法注入注解的值 } } } catch (Exception e) { e.printStackTrace(); } return obj; }}

定義一個AOP接口用于AOP切面編程

上面只是使用了動態代理技術和注解技術,下面通過定義一個AOP接口,將AOP接口的能力添加到代理類中

AOP接口

package proxy.imp;import java.lang.reflect.Method;/** * 這是一個AOP的一個切面;在每個接口方法中可以做一些類似于日志處理的功能 * * @ClassName: AOPMethod * @Description: TODO(這里用一句話描述這個類的作用) * @author PengRong * @date 2017年3月5日 下午4:18:20 * */public interface AOPMethod { // 實例方法執行前執行的方法,比如執行方法前,記錄類狀態,寫入log.監控xx變量,,, void after(Object proxy, Method method, Object[] args); // 實例方法執行后執行的方法 void before(Object proxy, Method method, Object[] args);}

通過在生產代理類的代碼中將實現AOP接口的實例傳遞進去。

package proxy;import java.lang.reflect.Method;import proxy.imp.AOPMethod;import proxy.imp.AnimalInterface;public class AOPTest { public static void main(String[] args) { /** * new AOPMethod() { // 這里寫方法執行前的AOP切入方法 * * @Override public void before(Object proxy, Method method, Object[] * args) { if (method.getName().equals("getProperty")) { * System.err.println("成功攔截" + method.getName() + "方法,啟動"); } * } * * // 這里系方法執行后的AOP切入方法 * @Override public void after(Object proxy, Method method, Object[] * args) { if (method.getName().equals("getProperty")) * System.err.println("成功攔截" + method.getName() + "方法,結束"); * * } } */ /** * 返回的dog為代理實例 */ AnimalInterface dog = AnimalFactory.getAnimal(DogImp.class, new AOPMethod() { // 這里寫方法執行前的AOP切入方法 @Override public void before(Object proxy, Method method, Object[] args) { if (method.getName().equals("getProperty")) { System.err.println("成功攔截" + method.getName() + "方法,啟動"); } } // 這里系方法執行后的AOP切入方法 @Override public void after(Object proxy, Method method, Object[] args) { if (method.getName().equals("getProperty")) System.err.println("成功攔截" + method.getName() + "方法,結束"); } });// 返回一個代理類 dog.say();// 實體的一個行為 String name1 = "我的名字是= " + dog.getName();// 通過這個可以看到可以將注解注入到屬性中 System.out.println(name1); dog.setName("二狗子"); String name2 = "我的名字是" + dog.getName(); System.out.println(name2); dog.getProperty(); }}

執行結果:通過實現AOP接口實例傳遞進去,那么將可以在實際業務方法執行前進行很多其他操作,比如統計,監控,日志功能。

注入 name 屬性 Lumia注入 setProperty 方法注解 水陸兩棲戰士成功攔截getProperty方法,啟動成功攔截getProperty方法,結束小狗:汪汪汪汪.....我的名字是= Lumia我的名字是二狗子二狗子= 水陸兩棲戰士

綜上:動態代理類技術是實現AOP的技術基礎。 源代碼 使用Java原生代理并實現注解自動注入

使用Java原生代理實現AOP


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 兴化市| 长宁区| 澳门| 赤水市| 洪湖市| 五大连池市| 定边县| 达尔| 朝阳市| 眉山市| 勐海县| 延长县| 陆良县| 桓台县| 孟津县| 开平市| 凌源市| 布拖县| 鹰潭市| 庆阳市| 修水县| 泸西县| 天津市| 泾阳县| 赣榆县| 大田县| 安溪县| 龙门县| 思南县| 舒城县| 宁国市| 承德市| 佛教| 六枝特区| 应城市| 芮城县| 三穗县| 西充县| 剑阁县| 盐源县| 连云港市|