代理模式,顧名思義,就是經過代理去完成某些功能。好比,你須要購買火車票,不想跑那麼遠到火車站售票窗口買,能夠去附近的火車票代售點買,或者到攜程等第三方網站買。這個時候,咱們就把火車站叫作目標對象或者委託對象,也能夠叫被代理對象,而火車票代售點和攜程就叫作代理對象。spring
1、靜態代理編程
靜態代理是最簡單的代理模式。須要定義一個接口,而後委託類和代理類分別實現這個接口ide
//待實現的接口 public interface UserManager { public void getName(String name); public void getId(int id); } //委託類 public class UserManagerImpl implements UserManager { @Override public void getName(String name) { System.out.println("UserManagerImpl.getName:" + name); } @Override public void getId(int id) { System.out.println("UserManagerImpl.getId:" + id); } } //代理類 public class UserManagerProxy implements UserManager { UserManager userManager; public UserManagerProxy(UserManager userManager) { this.userManager = userManager; } @Override public void getName(String name) { System.out.println("before getName"); userManager.getName(name); System.out.println("after getName"); } @Override public void getId(int id) { userManager.getId(id); } public static void main(String[] args) { UserManagerProxy proxy = new UserManagerProxy(new UserManagerImpl()); proxy.getName("zhangsan"); } } //before getName //UserManagerImpl.getName:zhangsan //after getName
能夠看到,在編譯成class以前,就已經肯定了委託類UserManagerImpl和代理類UserManagerProxy。所以,才叫靜態代理。這樣雖然定義比較方便,實現也簡單,可是有一個弊端。當接口再新加一個方法時,委託類和代理類都須要同步地去實現方法,所以維護起來比較麻煩。而動態代理解決了這個問題。函數
2、JDK動態代理網站
動態代理分爲JDK動態代理和cglib動態代理。動態是指,代理類是經過反射等機制動態生成的,委託類和代理類的關係在運行時才肯定。他們的主要區別就是,JDK動態代理須要實現接口,而cglib是經過繼承來實現的,不須要定義接口。this
JDK動態代理,須要定義一個類去實現InvocationHandler接口代理
public class LogHandler implements InvocationHandler { private Object targetObj; public Object newProxyObject(Object targetObj){ this.targetObj = targetObj; return Proxy.newProxyInstance( targetObj.getClass().getClassLoader(), //獲取委託類的類加載器 targetObj.getClass().getInterfaces(), //獲取委託類實現的全部接口 this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object ret; try { System.out.println("before method"); ret = method.invoke(targetObj, args); System.out.println("after method"); } catch (IllegalAccessException e) { e.printStackTrace(); System.out.println("error"); throw e; } return ret; } } public class TestProxy { public static void main(String[] args) { LogHandler logHandler = new LogHandler(); UserManager o = (UserManager)logHandler.newProxyObject(new UserManagerImpl()); o.getName("ls"); o.getId(2); } } /** 運行結果以下: before method UserManagerImpl.getName:ls after method before method UserManagerImpl.getId:2 after method */
JDK動態代理實際上是在運行時動態生成了一個代理類去實現接口,只是隱藏了這個過程,咱們不知道而已。code
class $JDKProxy implements UserManager{}
須要注意的是,實現JDK動態代理的一個前提就是,須要定義一個接口,而後委託類去實現這個接口。那若是我不想定義接口,只定義一個委託類能不能實現呢?這就須要用到cglib代理了。(由於cglib是經過繼承方式)對象
3、cglib動態代理繼承
須要定義一個類實現MethodInterceptor接口(注意,這個類可不是代理類,也不是委託類哦)。
//委託類,不須要實現接口 public class CgTarget { public void getContent(){ System.out.println("cglib被代理類getContent方法"); } } public class CglibProxy implements MethodInterceptor { private Object target; @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("cglib開始"); Object invoke = method.invoke(target, objects); System.out.println("cglib結束"); return invoke; } //代理方法 public Object getCglibProxy(Object target){ this.target = target; Enhancer enhancer = new Enhancer(); //設置加強類的父類,即被代理類 enhancer.setSuperclass(target.getClass()); //設置回調函數 enhancer.setCallback(this); //返回建立的代理類 return enhancer.create(); } } public class TestCglib { public static void main(String[] args) { CglibProxy cglibProxy = new CglibProxy(); CgTarget o = (CgTarget)cglibProxy.getCglibProxy(new CgTarget()); o.getContent(); } } /** 打印結果以下: cglib開始 cglib被代理類getContent方法 cglib結束 */
能夠看到,cglib動態代理是經過Enhancer類的create方法建立了代理類。其實,其內部是經過繼承委託類來動態生成代理類的。它隱藏瞭如下過程
class $cglibProxy extends CgTarget{}
所以,委託類不能定義成final類型的,由於final修飾的類是不能被繼承的。
瞭解spring AOP的同窗應該知道,AOP是面向切面編程,在管理事物的時候會用到。其實,AOP就是經過動態代理來實現的,具體是用的JDK動態代理仍是cglib動態代理,感興趣的小夥伴能夠繼續深刻研究哦。