代理模式是一種設計模式,提供了對目標對象額外的訪問方式,即經過代理對象訪問目標對象,這樣能夠在不修改原目標對象的前提下,提供額外的功能操做,擴展目標對象的功能。html
簡言之,代理模式就是設置一箇中間代理來控制訪問原目標對象,以達到加強原對象的功能和簡化訪問方式。java
代理模式UML類圖git
舉個例子,咱們生活中常常到火車站去買車票,可是人一多的話,就會很是擁擠,因而就有了代售點,咱們能從代售點買車票了。這其中就是代理模式的體現,代售點代理了火車站對象,提供購買車票的方法。github
這種代理方式須要代理對象和目標對象實現同樣的接口。spring
優勢:能夠在不修改目標對象的前提下擴展目標對象的功能。設計模式
缺點:api
舉例:保存用戶功能的靜態代理實現bash
package com.proxy; public interface IUserDao { public void save(); }
package com.proxy; public class UserDao implements IUserDao{ @Override public void save() { System.out.println("保存數據"); } }
package com.proxy; public class UserDaoProxy implements IUserDao{ private IUserDao target; public UserDaoProxy(IUserDao target) { this.target = target; } @Override public void save() { System.out.println("開啓事務");//擴展了額外功能 target.save(); System.out.println("提交事務"); } }
package com.proxy; import org.junit.Test; public class StaticUserProxy { @Test public void testStaticProxy(){ //目標對象 IUserDao target = new UserDao(); //代理對象 UserDaoProxy proxy = new UserDaoProxy(target); proxy.save(); } }
開啓事務 保存數據 提交事務
動態代理利用了JDK API,動態地在內存中構建代理對象,從而實現對目標對象的代理功能。動態代理又被稱爲JDK代理或接口代理。框架
靜態代理與動態代理的區別主要在:maven
特色:
動態代理對象不須要實現接口,可是要求目標對象必須實現接口,不然不能使用動態代理。
JDK中生成代理對象主要涉及的類有
static Object newProxyInstance(ClassLoader loader, //指定當前目標對象使用類加載器 Class<?>[] interfaces, //目標對象實現的接口的類型 InvocationHandler h //事件處理器 ) //返回一個指定接口的代理類實例,該接口能夠將方法調用指派到指定的調用處理程序。
Object invoke(Object proxy, Method method, Object[] args) // 在代理實例上處理方法調用並返回結果。
舉例:保存用戶功能的動態代理實現
package com.proxy; public interface IUserDao { public void save(); }
package com.proxy; public class UserDao implements IUserDao{ @Override public void save() { System.out.println("保存數據"); } }
package com.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyFactory { private Object target;// 維護一個目標對象 public ProxyFactory(Object target) { this.target = target; } // 爲目標對象生成代理對象 public Object getProxyInstance() { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("開啓事務"); // 執行目標對象方法 Object returnValue = method.invoke(target, args); System.out.println("提交事務"); return null; } }); } }
package com.proxy; import org.junit.Test; public class TestProxy { @Test public void testDynamicProxy (){ IUserDao target = new UserDao(); System.out.println(target.getClass()); //輸出目標對象信息 IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance(); System.out.println(proxy.getClass()); //輸出代理對象信息 proxy.save(); //執行代理方法 } }
class com.proxy.UserDao class com.sun.proxy.$Proxy4 開啓事務 保存數據 提交事務
cglib is a powerful, high performance and quality Code Generation Library. It can extend JAVA classes and implement interfaces at runtime.
cglib (Code Generation Library )是一個第三方代碼生成類庫,運行時在內存中動態生成一個子類對象從而實現對目標對象功能的擴展。
cglib特色
cglib與動態代理最大的區別就是
使用cglib須要引入cglib的jar包,若是你已經有spring-core的jar包,則無需引入,由於spring中包含了cglib。
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.5</version> </dependency>
舉例:保存用戶功能的動態代理實現
package com.cglib; public class UserDao{ public void save() { System.out.println("保存數據"); } }
package com.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class ProxyFactory implements MethodInterceptor{ private Object target;//維護一個目標對象 public ProxyFactory(Object target) { this.target = target; } //爲目標對象生成代理對象 public Object getProxyInstance() { //工具類 Enhancer en = new Enhancer(); //設置父類 en.setSuperclass(target.getClass()); //設置回調函數 en.setCallback(this); //建立子類對象代理 return en.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("開啓事務"); // 執行目標對象的方法 Object returnValue = method.invoke(target, args); System.out.println("關閉事務"); return null; } }
package com.cglib; import org.junit.Test; public class TestProxy { @Test public void testCglibProxy(){ //目標對象 UserDao target = new UserDao(); System.out.println(target.getClass()); //代理對象 UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance(); System.out.println(proxy.getClass()); //執行代理對象方法 proxy.save(); } }
class com.cglib.UserDao class com.cglib.UserDao$$EnhancerByCGLIB$$552188b6 開啓事務 保存數據 關閉事務
代理模式相關知識
UML相關知識