办法的代理能够在调用办法时进行其它的相干操作,并缩小代码的入侵和偶合。很多框架都用到了动静代理,并提供了减化代理操作,如: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
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
办法代理执行接口类办法
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
操作,代理需要变更只需批改代理类,实现理解偶的成果。但不同的接口多个办法就要反复的编写代理类,来实现办法代理操作。
JDK 动静代理
实现接口 InvocationHandler
的invoke
办法,通过 Proxy
的newProxyInstance
办法,构建代理接口实例。相比动态代理更加灵便,动静代理不同的接口和接口中的办法。
改良电脑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
小结
使用反射,动静代理能够代理不同的接口的多个办法,不用批改代码。但只能用于接口办法的代理,无奈实现所有类办法。
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
实现接口 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
操作。
相干文章
-
Java 反射实例操作 2020/08/23
-
Java 中的重写 (Override) 与重载(Overload) 2020/08/20
-
收费申请 JetBrains 开源开发许可证,蕴含 IDEA 2020/08/19
-
Java 开发环境的搭建,开启你的编程之旅 2020/08/15
源文:https://ichochy.com/posts/20200824/