一、概述
1、代理模式是常用的java設計模式,生成一個代理對象,來代替真正的對象,從而控制真實對象的訪問。
客戶(調用者)----------商務(代理對象)-----------軟件工程師(真正對象)
2、我們需要在調用者調用對象之前就生成一個代理對象,而這個代理對象需要和真正對象建立代理關系
-----代理對象和真正對象建立關系
-----實現代理對象的代理邏輯方法
3、常用的代理對象方法:JDK動態代理,CGLIB
二、JDK動態代理
JDK動態代理所用到的代理類在程序調用到代理類對象時才由JVM真正創建,JVM根據傳進來的 業務實現類對象以及方法名 ,動態地創建了一個代理類的class文件並被字節碼引擎執行,然后通過該代理類對象進行方法調用。
1、需要借助接口生成代理對象
public interface HelloWorld { public void sayHelloWorld(); }
public class HelloWorldImp implements HelloWorld{ @Override public void sayHelloWorld() { System.out.println("你好"); } }
2、實現代理邏輯類:需要實現java.lang,reflect.InvocationHandler接口,重寫invoke方法
package reflect; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import org.junit.Test; public class JdkProxyExample implements InvocationHandler{ //真實對象 private Object target = null; //建立關系,返回代理對象 public Object bind(Object target) { this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this); } @Override //處理代理實例上的方法調用並返回結果。當在與其關聯的代理實例上調用方法時,將在調用處理程序上調用此方法。 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("調用真實對象服務之前的服務"); Object obj = method.invoke(target, args);//相當於調用sayHelloWorld() System.out.println("調用真實對象服務之后的服務"); return obj; } @Test public void testJdkProxyExample() { JdkProxyExample jdkProxyExample = new JdkProxyExample(); HelloWorld proxy = (HelloWorld) jdkProxyExample.bind(new HelloWorldImp()); proxy.sayHelloWorld(); } }
1、該方法返回指定接口的代理類的實例,該接口將方法調用分派給指定的invocationhandler代理 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException
參數:InvocationHandler是由代理實例的調用處理程序實現的接口。每個代理實例都有一個關聯的調用處理程序。當在代理實例上調用方法時,
方法調用被編碼並發送到其調用處理程序的invokemethod。
2、Object invoke(Object proxy, Method method,Object[] args) throws Throwable{}
處理代理實例上的方法調用並返回結果。當在與其關聯的代理實例上調用方法時,將在調用處理程序上調用此方法。
參數:Object proxy :就是newProxyInstance返回的代理對象
Method method : 當前調度的接口中的方法
Object[] args : 調度方法中的參數
通俗點說就是實現java.lang,reflect.InvocationHandler接口,重寫invoke方法,但是重寫invoke()需要給它三個參數
參數一:Object proxy :需要通過newProxyInstance返回的獲取參數proxy
三、CGLIB動態代理
1、cglib是針對類來實現代理的,原理是對指定的業務類生成一個子類,並覆蓋其中業務方法實現代理。因為采用的是繼承,所以不能對final修飾的類進行代理。
(1)首先定義一個y業務類Hello
public class Hello { public void sayHello() { System.out.println("hello..."); } }
(2)對指定的業務類生成一個子類,並覆蓋其中業務方法實現代理。
package reflect; import java.lang.reflect.Method; import org.junit.Test; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CGLIBProxyExample implements MethodInterceptor{ //生成代理對象 public Object getProxy(Class cls) { //增強類 Enhancer enhance = new Enhancer(); //設置增強的父類,即業務類 enhance.setSuperclass(cls); /*setCallback()設置哪個類是它的代理類,參數是this為當前對象, * 要求當前對象實現MethodInterceptor接口並實現方法intercept*/ enhance.setCallback(this); return enhance.create(); } @Override public Object intercept(Object proxy,Method method,Object[]args, MethodProxy methodProxy) throws Throwable { System.out.println("前"); Object result = methodProxy.invokeSuper(proxy, args); System.out.println("后"); return result; } @Test public void testCGLIBProxyExample() { CGLIBProxyExample cglibProxyExample = new CGLIBProxyExample(); Hello proxy = (Hello) cglibProxyExample.getProxy(Hello.class); proxy.sayHello(); } }
MethodInterceptor、 Enhancer在cglib-nodep-3.2.10.jar下
四、攔截器
1、因為攔截器可以進一步簡化動態代理的使用方法,是程序變得更簡單。
2、實現步驟:(1)定義一個攔截器接口
(2)定義攔截器的實現類
(3)實現攔截器的邏輯
public interface Interceptor { public boolean before(Object proxy,Object target,Method method,Object[] args); public void around(Object proxy,Object target,Method method,Object[] args); public void after(Object proxy,Object target,Method method,Object[] args); }
package interceptor; import java.lang.reflect.Method; public class InterceptorImp implements Interceptor{ @Override /*當返回值為true時,反射真實對象原來的方法 * 當返回值為false時,則調用around方法 */ public boolean before(Object proxy, Object target, Method method, Object[] args) { System.out.println("反射方法前邏輯"); return false; } @Override
//對原來的方法不滿意,進行調整 public void around(Object proxy, Object target, Method method, Object[] args) { System.out.println("取代原方法的邏輯"); } @Override public void after(Object proxy, Object target, Method method, Object[] args) { System.out.println("調用原方法或around后還要執行的邏輯"); } }
package interceptor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;public class InterceptorJdkProxy implements InvocationHandler{ private Object target; private String interceptorClass = null;//定義攔截器類路徑 public InterceptorJdkProxy(Object target,String interceptorClass) { this.target = target; this.interceptorClass = interceptorClass; } public static Object bind(Object target,String interceptorClass) { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InterceptorJdkProxy(target,interceptorClass)); } @Override //第一個參數proxy的獲取通過Proxy.newProxyInstance()獲取 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(interceptorClass==null) { //沒有攔截器就直接反射原來方法 return method.invoke(target, args); } //否則,通過反射生成攔截器 Object result = null; Interceptor interceptor = (Interceptor) Class.forName(interceptorClass).newInstance(); //判斷before方法 if(interceptor.before(proxy, target, method, args)) { result = method.invoke(target, args); }else { interceptor.around(proxy, target, method, args); } interceptor.after(proxy, target, method, args); return result; } public static void main(String[] args) { //沒有使用代理 HelloWorld helloWorld = new HelloWorldImp(); helloWorld.sayHelloWorld(); //使用了代理 HelloWorld proxy = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImp(), "interceptor.InterceptorImp"); proxy.sayHelloWorld(); } }