方法的代理能夠在調用方法時進行其它的相關操做,並減小代碼的入侵和偶合。不少框架都用到了動態代理,並提供了減化代理操做,如:Spring 的 AOP。java
以電腦爲模型,咱們都知道,電腦是由 CPU、GPU、DISK 多個設備組裝的,它們都是經過接口相鏈接。如今模擬一臺電腦(Computer
)經過接口設備(Device
),代理(Proxy
)組裝不一樣的設備(CPU、GPU
),並運行(run
)。編程
Device
/* * File:Device.java * User:iChochy * URL:https://ichochy.com * Copyright (c) 2020 * Date:2020/08/31 17:49:31 */ package com.ichochy.proxy; public interface Device { public void run(); }
/* * File:CPU.java * User:iChochy * URL:https://ichochy.com * Copyright (c) 2020 * Date:2020/08/31 17:52:31 */ package com.ichochy.proxy; public class CPU implements Device { @Override public void run() { System.out.println("Game"); } }
/* * File:GPU.java * User:iChochy * URL:https://ichochy.com * Copyright (c) 2020 * Date:2020/08/31 17:52:31 */ package com.ichochy.proxy; public class GPU implements Device { @Override public void run() { System.out.println("Display"); } }
Computer
Computer
的start
方法代理執行接口類方法框架
/* * File:SimpleProxy.java * User:iChochy * URL:https://ichochy.com * Copyright (c) 2020 * Date:2020/08/31 17:54:31 */ package com.ichochy.proxy; public class Computer { private Device device; public Device start(){ System.out.println("Start Computer"); device.run(); return device; } public Device getDevice() { return device; } public void setDevice(Device device) { this.device = device; } }
經過類Computer
的start
方法代理執行接口類方法ide
package com.ichochy; import com.ichochy.proxy.CPU; import com.ichochy.proxy.Computer; import com.ichochy.proxy.GPU; public class App { public static void main(String[] args) { Computer proxy = new Computer(); proxy.setDevice(new CPU()); proxy.start(); proxy.setDevice(new GPU()); proxy.start(); } }
Start Computer Game Start Computer Display
靜態代理能夠代理某個方法,實現AOP
操做,代理需求變動只需修改代理類,實現瞭解偶的效果。但不一樣的接口多個方法就要重複的編寫代理類,來實現方法代理操做。post
實現接口InvocationHandler
的invoke
方法,經過Proxy
的newProxyInstance
方法,構建代理接口實例。相比靜態代理更加靈活,動態代理不一樣的接口和接口中的方法。this
Computer
實現接口InvocationHandler
的invoke
方法,運用反射,動態執行代理方法代理
/* * File:SimpleProxy.java * User:iChochy * URL:https://ichochy.com * Copyright (c) 2020 * Date:2020/08/31 17:54:31 */ package com.ichochy.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class Computer implements InvocationHandler { private Device device; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Start..."); //運用反射,動態執行代理方法,並返回方法執行結果 Object result = method.invoke(device, args); System.out.println("End"); return result; } public Device getDevice() { return device; } public void setDevice(Device device) { this.device = device; } }
經過類Proxy
的newProxyInstance
方法構建代理接口類,實現方法的代理執行日誌
/* * File:App.java * User:iChochy * URL:https://ichochy.com * Copyright (c) 2020 * Date:2020/09/01 12:46:01 */ package com.ichochy; import com.ichochy.proxy.CPU; import com.ichochy.proxy.Computer; import com.ichochy.proxy.Device; import java.lang.reflect.Proxy; public class App { public static void main(String[] args) throws Exception { CPU cpu = new CPU(); Computer computer = new Computer(); computer.setDevice(cpu); //獲取代理接口實例 Device device = (Device) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), cpu.getClass().getInterfaces(), computer); device.run(); } }
Start... Game End
運用反射,動態代理能夠代理不一樣的接口的多個方法,沒必要修改代碼。但只能用於接口方法的代理,沒法實現全部類方法。code
CGLIB庫是用於生成和轉換Java字節碼的高級API,它容許運行時對字節碼進行修改和動態生成,經過繼承方式實現動態代理。xml
CGLIB
庫經過Maven
庫管理引入第三方CGLIB
庫
<!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
Computer
實現接口MethodInterceptor
的intercept
方法,運用反射,動態執行代理方法(原父類方法)
/* * File:SimpleProxy.java * User:iChochy * URL:https://ichochy.com * Copyright (c) 2020 * Date:2020/08/31 17:54:31 */ package com.ichochy.proxy; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class Computer implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("Start..."); //運用反射,動態執行代理方法,並返回方法執行結果 Object result = methodProxy.invokeSuper(obj, args); System.out.println("End"); return result; } }
經過類Enhancer
的create
方法構建代理類,實現方法的代理執行
/* * File:App.java * User:iChochy * URL:https://ichochy.com * Copyright (c) 2020 * Date:2020/09/01 12:46:01 */ package com.ichochy; import com.ichochy.proxy.CPU; import com.ichochy.proxy.Computer; import net.sf.cglib.proxy.Enhancer; public class App { public static void main(String[] args) throws Exception { Computer computer = new Computer(); Enhancer enhancer = new Enhancer(); //設置要代理超類 enhancer.setSuperclass(CPU.class); //設置回調處理類 enhancer.setCallback(computer); //構建代理類 CPU cpu = (CPU)enhancer.create(); cpu.run(); } }
Start... Game End
經過CGLIB
庫能夠很方便的實現方法的動態代理,實現AOP
操做。CGLIB
庫構建代理類的子類,並重寫代理父類的方法,經過執行子類方法實現動態代理操做。
當咱們要對一類方法或全部方法進行相同操做時,運用方法代理能夠很好實現咱們的需求,並不用去重寫之前的業務方法,如:事務處理、日誌監控、權限管理、異常捕捉及處理。
總結:方法代理,實現AOP
操做。