办法的代理能够在调用办法时进行其它的相干操作,并缩小代码的入侵和偶合。很多框架都用到了动静代理,并提供了减化代理操作,如:Spring 的 AOP。

动态代理

以电脑为模型,咱们都晓得,电脑是由 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();}

设施 CPU

/* * 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");    }}

设施 GPU

/* * 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

Computerstart办法代理执行接口类办法

/* * 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;    }}

运行电脑

通过类Computerstart办法代理执行接口类办法

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 ComputerGameStart ComputerDisplay

小结

动态代理能够代理某个办法,实现AOP操作,代理需要变更只需批改代理类,实现理解偶的成果。但不同的接口多个办法就要反复的编写代理类,来实现办法代理操作。

JDK动静代理

实现接口InvocationHandlerinvoke办法,通过ProxynewProxyInstance办法,构建代理接口实例。相比动态代理更加灵便,动静代理不同的接口和接口中的办法。

改良电脑Computer

实现接口InvocationHandlerinvoke办法,使用反射,动静执行代理办法

/* * 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;    }}

动静运行电脑

通过类ProxynewProxyInstance办法构建代理接口类,实现办法的代理执行

/* * 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... GameEnd

小结

使用反射,动静代理能够代理不同的接口的多个办法,不用批改代码。但只能用于接口办法的代理,无奈实现所有类办法。

CGLIB动静代理

CGLIB库是用于生成和转换Java字节码的高级API,它容许运行时对字节码进行批改和动静生成,通过继承形式实现动静代理。

引入CGLIB

通过Maven库治理引入第三方CGLIB

<!-- https://mvnrepository.com/artifact/cglib/cglib --><dependency>    <groupId>cglib</groupId>    <artifactId>cglib</artifactId>    <version>3.3.0</version></dependency>

改良电脑Computer

实现接口MethodInterceptorintercept办法,使用反射,动静执行代理办法(原父类办法)

/* * 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;    }}

动静运行电脑

通过类Enhancercreate办法构建代理类,实现办法的代理执行

/* * 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... GameEnd

小结

通过CGLIB库能够很不便的实现办法的动静代理,实现AOP操作。CGLIB库构建代理类的子类,并重写代理父类的办法,通过执行子类办法实现动静代理操作。

总结

当咱们要对一类办法或所有办法进行雷同操作时,使用办法代理能够很好实现咱们的需要,并不必去重写以前的业务办法,如:事务处理、日志监控、权限治理、异样捕获及解决。

总结:办法代理,实现AOP操作。

相干文章

  • Java 反射实例操作 2020/08/23

  • Java 中的重写(Override)与重载(Overload) 2020/08/20

  • 收费申请 JetBrains 开源开发许可证,蕴含 IDEA 2020/08/19

  • Java 开发环境的搭建,开启你的编程之旅 2020/08/15

源文:https://ichochy.com/posts/20200824/