今天學到Spring的動態代理實現AOP,對代理這個概念很模糊,看了一篇文章發現這是一種設計模式,因而學習記錄一下。html
代理模式是一種對象結構型的模式,主要爲其餘對象提供一種代理以控制對這個對象的訪問。簡單點說就是你訪問一個對象並非直接的訪問它,而是經過一個代理簡介訪問,那麼這個代理就能夠在訪問對象以前或以後作一些定製化的操做,好比校驗入參,打印日誌什麼的。Spring AOP就是一個代理模式的典型應用。java
java中的代理分爲三類:靜態代理、動態代理和Cglib代理。下面依次講解着三種代理。編程
靜態代理在使用時,須要定義接口或者父類,被代理的對象和代理對象須要一塊兒實現同一個接口或者繼承同一個父類。設計模式
代碼示例緩存
接口:框架
package com.wangjun.designPattern.proxy; /* * 咱們有一我的類的接口,有不少種職業,好比教師,學生 */ public interface Person { //獲取本職業的職責 public String getDuty(); }
目標對象1:ide
package com.wangjun.designPattern.proxy; public class Student implements Person { @Override public String getDuty() { return "學習知識"; } }
目標對象2:函數
package com.wangjun.designPattern.proxy; public class Teacher implements Person { @Override public String getDuty() { return "教書育人"; } }
代理對象:工具
package com.wangjun.designPattern.proxy; import java.util.HashMap; import java.util.Map; /* * 經過代理,加入緩存功能 */ public class CachedPersonProxy implements Person{ private Person person; private Map<Person,String> map = new HashMap<>();; public CachedPersonProxy(Person person) { this.person = person; } @Override public String getDuty() { String duty = map.get(person); if(null == duty) { duty = person.getDuty(); map.put(person, duty); } return duty; } }
測試類:性能
package com.wangjun.designPattern.proxy; public class Main { public static void main(String[] args) { Teacher teacher = new Teacher(); CachedPersonProxy proxy = new CachedPersonProxy(teacher); System.out.println(proxy.getDuty()); } }
靜態代理總結:
動態代理也叫JDK代理或者接口代理。
動態代理有如下特色:
代理類所在的包是:java.lang.reflect.Proxy
JDK實現動態代理只須要使用newProxyInstance方法,該方法須要傳入三個變量:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
代碼示例
接口類Person.class和實現類Teacher.class、Sutdent.class不變,在這個基礎上,增長一個代理工廠類ProxyFactory.java,而後在測試類(須要使用到代理的代碼)中先創建目標對象和代理對象的聯繫,接着代用代理對象的中同名方法。
代理工廠類:
package com.wangjun.designPattern.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map; public class ProxyFactory { private Person person; private Map<Person, String> map = new HashMap<>(); public ProxyFactory(Person person) { this.person = person; } public Object getProxyInstance() { return Proxy.newProxyInstance( person.getClass().getClassLoader(), person.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String duty = map.get(person); if(null == duty) { //執行對象方法 System.out.println("沒有緩存"); duty = (String) method.invoke(person, args); map.put(person, duty); } return duty; } }); } }
測試類:
package com.wangjun.designPattern.proxy; public class Main { public static void main(String[] args) { Person teacher = new Teacher(); System.out.println(teacher.getClass()); //使用動態代理 ProxyFactory proxyFactory = new ProxyFactory(teacher); Person teacherProxy = (Person) proxyFactory.getProxyInstance(); System.out.println(teacherProxy.getClass()); System.out.println(teacherProxy.getDuty()); System.out.println(teacherProxy.getDuty()); } }
總結
代理對象不須要實現接口,可是目標對象必定要實現接口,不然不能用動態代理。
上面的靜態代理和動態代理模式都是要求目標對象是實現一個接口的目標對象,可是有時候目標對象只是一個單獨的對象,並無實現任何的接口,這個時候就可使用以目標對象子類的方式類實現代理,這種方法就叫作:Cglib代理。
Cglib子類實現代理的方法
代碼示例
目標對象類:
package com.wangjun.designPattern.proxy; /* * 目標對象,沒有實現任何接口 */ public class Doctor { public String getDuty() { return "救死扶傷"; } }
Cglib代理工廠類:
package com.wangjun.designPattern.proxy; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /* * cglib代理工廠 * 對Doctor在內存中動態構建一個子類對象 */ public class CglibProxyFactory implements MethodInterceptor { private Object person; private Map<Object, String> map = new HashMap<>(); public CglibProxyFactory(Object person) { this.person = person; } // 給目標對象建立一個代理對象 public Object getProxyInstance() { // 1.工具類 Enhancer en = new Enhancer(); // 2.設置父類 en.setSuperclass(person.getClass()); // 3.設置回調函數 en.setCallback(this); // 4.建立子類(代理對象) return en.create(); } @Override public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { String duty = map.get(person); if(null == duty) { //執行目標對象的方法 System.out.println("cglib實現,有緩存"); duty = (String) arg1.invoke(person, arg2); map.put(person, duty); } return duty; } }
測試類:
package com.wangjun.designPattern.proxy; public class Main { public static void main(String[] args) { // 使用cglib // 目標對象 Doctor target = new Doctor(); System.out.println(target.getClass()); // 代理對象 Doctor proxyCglib = (Doctor) new CglibProxyFactory(target).getProxyInstance(); // 執行代理對象的方法 System.out.println(proxyCglib.getClass()); System.out.println(proxyCglib.getDuty()); System.out.println(proxyCglib.getDuty()); } }
在Spring的AOP編程中: