最近在學習Spring AOP的代碼,AOP的底層是經過代理機制進行實現的,在這裏先學習代理機制;java
jdk動態代理使用接口InvocationHander和Proxy類,其中接口InvocationHander中:ide
該接口中只用一個方法invoke,該方法有三個參數:函數
- proxy 該參數爲代理類的實例
- method 被調用的方法對象
- args 調用method對象的方法參數學習
public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
類Proxy,Proxy(Class)this
Proxy是 Java 動態代理機制的主類,它提供了一組靜態方法來爲一組接口動態地生成代理類及其對象。
Proxy 的靜態方法 static InvocationHandler getInvocationHandler(Object proxy)
該方法用於獲取指定代理對象所關聯的調用處理器 static Class getProxyClass(ClassLoader loader, Class[] interfaces)
該方法用於獲取關聯於指定類裝載器和一組接口的動態代理類的類對象 static boolean isProxyClass(Class cl)
該方法用於判斷指定類對象是不是一個動態代理類 static Object newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler h)
- loader 指定代理類的ClassLoader加載器
- interfaces 指定代理類要實現的接口
- h: 表示的是當我這個動態代理對象在調用方法的時候,會關聯到哪個InvocationHandler對象上。spa
使用Java 動態代理的兩個重要步驟代理
如下以實例對jdk的動態代理進行說明code
(a)、建立一個第三方的接口及類,用於進行動態代理實例說明對象
接口:blog
public interface SubjectService { void say(); }
相應的實現類:
public class SubjectServiceImpl implements SubjectService { public void say(){ System.out.println("開始說話"); } }
(b)、建立一個接口InvocationHandler的實現類
public class jdkProxy implements InvocationHandler { Object target; public jdkProxy(Object target){ this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName() == "say"){ System.out.println("說話以前"); method.invoke(target,args); System.out.println("說話以後"); } return null; } }
(c)、經過Proxy類建立代理對象,進行函數調用
public static void main(String[] args) { SubjectService subject = (SubjectService) Proxy.newProxyInstance(jdkProxy.class.getClassLoader(), SubjectService.class.getInterfaces(),new jdkProxy(new SubjectServiceImpl())); subject.say(); }
其中第二個參數SubjectService.class.getInterfaces(),還可使用new Class[]{SubjectService.class}。
默認狀況下,Spring Aop若是發現目標對象實現了相應的接口,就是使用動態代理的方式爲目標對象生成一個代理對象,可是若是目標對象沒有實現接口,那麼只能使用一個CGLIB的開源動態字節碼生成類庫,爲目標對象生成動態的代理對象實例。
原理:爲目標對象進行擴展,爲其生成相應的子類,而子類能夠經過複寫擴展父類的行爲,只要將橫切邏輯的實現放到子類中,而後讓系統使用擴展後的目標對象的子類,就能夠達到與代理模式相同的效果了。
藉助CGLIB這樣的字節碼生成庫,在系統運行期間能夠動態的爲目標對象生成相應的子類。
該接口繼承了Callback接口,接口中只有一個方法 intercept(),該方法共有四個參數:
1)obj表示加強的對象,即實現這個接口類的一個對象;
2)method表示要被攔截的方法;
3)args表示要被攔截方法的參數;
4)proxy表示要觸發父類的方法對象
public interface MethodInterceptor extends Callback { Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable; }
實例:
(a)、創建一個類
public class SubjectServiceImpl { public void say(){ System.out.println("開始說話"); } }
(b)、實現MethodInteceptor的類及相應的實現函數
public class CGLIB implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("吃飯以前"); methodProxy.invokeSuper(o,objects); System.out.println("吃飯以後"); return null; } public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(SubjectServiceImpl.class); enhancer.setCallback(new CGLIB()); SubjectServiceImpl subjectService = (SubjectServiceImpl) enhancer.create(); subjectService.say(); } }
引伸學習,研究一下CGLIB的源碼:
從enhancer.create()建立實例開始:
(1)、create()
/** * Generate a new class if necessary and uses the specified * callbacks (if any) to create a new object instance. * Uses the no-arg constructor of the superclass. * @return a new instance */ public Object create() { classOnly = false; argumentTypes = null; return createHelper(); }
(2)、createHelper()
private Object createHelper() { preValidate(); Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null, ReflectUtils.getNames(interfaces), filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter), callbackTypes, useFactory, interceptDuringConstruction, serialVersionUID); this.currentKey = key; Object result = super.create(key); return result; }
preValidate()方法校驗callbackTypes、filter是否爲空,以及爲空時的處理。
(3)、create()
protected Object create(Object key) { try { ClassLoader loader = getClassLoader(); Map<ClassLoader, ClassLoaderData> cache = CACHE; ClassLoaderData data = cache.get(loader); if (data == null) { synchronized (AbstractClassGenerator.class) { cache = CACHE; data = cache.get(loader); if (data == null) { Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache); data = new ClassLoaderData(loader); newCache.put(loader, data); CACHE = newCache; } } } this.key = key; Object obj = data.get(this, getUseCache()); if (obj instanceof Class) { return firstInstance((Class) obj); } return nextInstance(obj); } catch (RuntimeException e) { throw e; } catch (Error e) { throw e; } catch (Exception e) { throw new CodeGenerationException(e); } }
(4)、nextInstance()
protected Object nextInstance(Object instance) { EnhancerFactoryData data = (EnhancerFactoryData) instance; if (classOnly) { return data.generatedClass; } Class[] argumentTypes = this.argumentTypes; Object[] arguments = this.arguments; if (argumentTypes == null) { argumentTypes = Constants.EMPTY_CLASS_ARRAY; arguments = null; } return data.newInstance(argumentTypes, arguments, callbacks); }
第一個參數爲代理對象的構成器類型,第二個爲代理對象構造方法參數,第三個爲對應回調對象。
(5)、
看看data.newInstance(argumentTypes, arguments, callbacks)方法,
經過反射生成代理對象,源碼以下:
/** * Creates proxy instance for given argument types, and assigns the callbacks. * Ideally, for each proxy class, just one set of argument types should be used, * otherwise it would have to spend time on constructor lookup. * Technically, it is a re-implementation of {@link Enhancer#createUsingReflection(Class)}, * with "cache {@link #setThreadCallbacks} and {@link #primaryConstructor}" * * @see #createUsingReflection(Class) * @param argumentTypes constructor argument types * @param arguments constructor arguments * @param callbacks callbacks to set for the new instance * @return newly created proxy */ public Object newInstance(Class[] argumentTypes, Object[] arguments, Callback[] callbacks) { setThreadCallbacks(callbacks); try { // Explicit reference equality is added here just in case Arrays.equals does not have one if (primaryConstructorArgTypes == argumentTypes || Arrays.equals(primaryConstructorArgTypes, argumentTypes)) { // If we have relevant Constructor instance at hand, just call it // This skips "get constructors" machinery return ReflectUtils.newInstance(primaryConstructor, arguments); } // Take a slow path if observing unexpected argument types return ReflectUtils.newInstance(generatedClass, argumentTypes, arguments); } finally { // clear thread callbacks to allow them to be gc'd setThreadCallbacks(null); } }
上述方法能夠看出生成代理對象最終使用的是反射的方法進行獲取。
在進行方法調用的時候,代理類中會調用攔截器函數,能夠從字節碼中看到相應代碼。