提到動態代理,就不得不先提一下代理模式。當咱們不想修改原有對象A的方法A1,但卻想在使用該方法時,增長多一些功能時,就可使用代理模式。ide
代理模式的邏輯很簡單,例如上述的場景,咱們會先建立一個代理對象B,經過B,來間接調用對象A的方法A1,而且在調用方法A1的先後,增長一些代碼邏輯,由此提升擴展性。工具
咱們運行一個應用時,會經歷編譯-運行幾個階段。通常咱們根據代理的建立時期,將代理分紅兩類:靜態代理、動態代理。性能
靜態代理會在編譯期,生成代理類class文件。而動態代理,則是在程序運行時,經過反射機制
,在內存中動態建立出代理類class文件。this
如下演示如何使用靜態代理。代理
public interface UserService { void createUser(String userName);}
2. 建立服務類,實現服務接口。code
public class UserServiceImpl implements UserService { @Override public void createUser(String userName) { System.out.println(userName + " is created"); }}
3. 建立代理類,實現服務接口,而且將原服務類注入到該代理類中。對象
public class UserServiceProxy implements UserService { private UserService userService; //注入原服務類 public UserServiceProxy(UserService userService) { this.userService = userService; } @Override public void createUser(String userName) { //前置加強 System.out.println(userName +" will be created"); // 調用原方法 userService.createUser(userName); //後置加強 System.out.println("finish"); }}
4. 當須要使用方法時,不直接調用服務類對象,而是經過代理類對象。blog
//建立服務類對象UserService userService = new UserServiceImpl();//建立代理類對象UserService userServiceProxy = new UserServiceProxy(userService);//調用代理類對象,間接調用原方法userServiceProxy.createUser("王二");
優勢: 能夠簡單的對目標對象進行功能擴展。繼承
缺點:須要對服務接口都實現一遍,不易管理。一旦接口修改,代理類也須要一併修改。接口
因爲靜態代理的缺點,由此引出動態代理。動態代理的核心就是反射
,經過反射咱們可以直接操做類或者對象,好比獲取某個類的定義,獲取某個類的屬性和方法等。在動態代理中,咱們再也不須要手動建立代理類。而是經過動態代理處理器,在應用運行時,經過反射
生成代理類,最終生成咱們須要用到的代理對象。
目前動態代理技術有不少,經常使用有:JDK動態代理,CGLIB動態代理,Javassist動態代理和ASM動態代理。
JDK動態代理是內置在JDK中的,而不須要引入第三方Jar包。CGLIB和Javassist是高級的字節碼生成工具,聽說是比JDK自帶的動態代理性能更好,功能十分強大。ASM是低級的字節碼生成工具,性能最好,但因爲更底層,對開發水平要求很高。
如下只簡單說明下JDK動態代理和CGLIB動態代理。
JDK動態代理是基於接口的動態代理。代理處理器類須要注入被代理的接口,而且須要繼承InvocationHandler
接口。調用時,使用Proxy
類中的newProxyInstance
方法動態的建立代理類。
代碼實踐以下:
public interface UserService { void createUser(String userName);}
2. 建立服務類,實現服務接口。
public class UserServiceImpl implements UserService { @Override public void createUser(String userName) { System.out.println(userName + " is created"); }}
3. 建立動態代理處理器類,實現InvocationHandler
接口。
public class UserHandler implements InvocationHandler { private UserService userService; public UserHandler(UserService userService) { this.userService = userService; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { start(); //經過反射調用方法,並獲取返回值 Object result = method.invoke(userService, args); end(); return result; } //前置加強 private void start(){ System.out.println("start"); } //後置加強 private void end(){ System.out.println("end"); }}
4. 經過Proxy的newProxyInstance
方法動態生成代理對象。
UserService userService = new UserServiceImpl();UserHandler userHandler = new UserHandler(userService);//獲取被代理類的類加載器和方法列表ClassLoader classLoader = userService.getClass().getClassLoader();Class<?>[] interfaces = userService.getClass().getInterfaces();UserService userServiceProxy = (UserService)Proxy.newProxyInstance(classLoader,interfaces,userHandler);//調用方法userServiceProxy.createUser("王二");
CGLIB動態代理,是針對類來實現代理的。經過對目標類繼承,重寫方法,以此實現動態代理。因而可知,CGLIB能夠代理絕大多數類,而JDK代理只能代理實現了接口的類。
代碼實踐以下:
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.5</version></dependency>
2. 建立服務類。
public class UserServiceImpl { @Override public void createUser(String userName) { System.out.println(userName + " is created"); }}
3. 自定義攔截器,攔截目標類的方法。
public class UserServiceInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { start(); Object result = methodProxy.invokeSuper(o, args); end(); return result; } private void start(){ System.out.println("start"); } private void end(){ System.out.println("end"); }}
在該攔截器中,須要實現intercept
方法,參數含義以下:
4. 使用Enhancer,建立代理對象。Enhancer 是一個很是重要的類,它爲非接口類型建立一個代理,動態地建立給定類的子類。
Enhancer enhancer = new Enhancer();//設置目標類爲動態代理類的父類enhancer.setSuperclass(UserServiceImpl.class);//設置調用時的攔截處理器enhancer.setCallback(new UserServiceInterceptor());//建立代理類對象UserService userService = (UserService)enhancer.create();userService.createUser("王二");
反射機制
動態生成。反射機制
動態調用。