代理模式是应用最广泛的设计模式之一,例如spring中的aop就是代理模式的实践。通常在java中使用比较广泛的是动态代理模式,其中实现方式比较常用的是jdk动态代理和cglib动态代理。
jdk实现动态代理
利用jdk实现动态代理代码比较简单,需要注意的是基于jdk的动态代理是必须基于接口才可以的,代码如下。
定义接口。
public interface Action {
public void move();
}
- 1
- 2
- 3
- 4
定义被代理对象。
public class TargetAction implements Action {
@Override
public void move() {
System.out.println("target doing move");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
实现InvocationHandler定义调用者。
public class InvocationHandlerAction implements InvocationHandler {
private Action target;
public InvocationHandlerAction(Action target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoker doing");
return method.invoke(target, args);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
测试代码。
public class JdkProxyTest {
public static void main(String[] args) throws IOException {
Action targetAction = new TargetAction();
Action proxyAction = (Action) Proxy.newProxyInstance(targetAction.getClass().getClassLoader(), targetAction.getClass().getInterfaces(), new InvocationHandlerAction(targetAction));
proxyAction.move();
//输出动态生成代理类的字节码文件
byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{Action.class});
FileOutputStream outputStream = new FileOutputStream(new File("D://$Proxy0.class"));
outputStream.write(bytes);
outputStream.flush();
outputStream.close();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
根据上面的代码就可以实现一个动态代理逻辑,在InvocationHandler利用反射调用目标对象的方法的前后,可以做出一些逻辑的丰富。
需要注意的上面使用了ProxyGenerator来输出动态生成的字节码文件,内容如下。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import design.mode.proxy.jdk.Action;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements Action {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void move() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("design.mode.proxy.jdk.Action").getMethod("move");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
根据输出的字节码文件,可以知道新生成的代理类,实现了Action接口,也就是我们定义的接口,同时实现了接口方法,查看接口方法,发现方法调用逻辑主要是以下代码,h就是我们实现了InvocationHandler接口的类,通过InvocationHandler的invoke方法,进入代理逻辑,实现动态代理。
public final void move() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
整个动态代理类的生成过程可以归纳为以下一个步骤。
1.根据接口信息,新生成一个代理类的.java文件
2.根据.java,编译生成.class文件
3.classloader读取class文件信息到jvm
4.新建对象,设置InvocationHandler参数。
cglib动态代理实现
定义被代理对象。需要注意,cglib的代理实现不需要基于接口。
public class TargetAction {
private String word = "default";
public TargetAction(){
}
public TargetAction(String word){
this.word = word;
}
public void move(){
System.out.println("target doing move" + word);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
定义一个作用类似于InvocationHandler的类。
public class CglibCallBackInvocationHandler implements MethodInterceptor{
private TargetAction targetAction;
public CglibCallBackInvocationHandler(TargetAction targetAction){
this.targetAction = targetAction;
}
/**
* 类似动态代理的InvocationHandler作用
* @param o
* @param method
* @param objects
* @param methodProxy
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("invoker doinig move");
//return methodProxy.invokeSuper(o, objects);
return method.invoke(targetAction, objects);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
定义代理类创建器
public class CglibProxyCreator {
public static <T> T create(Class<T> clazz, MethodInterceptor callbackinvoker){
Enhancer enhancer = new Enhancer();
//设置代理什么类
enhancer.setSuperclass(clazz);
//设置invoker
enhancer.setCallback(callbackinvoker);
return (T) enhancer.create();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
测试代码。
public class CglibTest {
public static void main(String[] args) {
TargetAction targetAction = new TargetAction("defintioin word");
TargetAction cglibProxy = CglibProxyCreator.create(TargetAction.class, new CglibCallBackInvocationHandler(targetAction));
cglibProxy.move();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
基本的编码方式与jdk实现的动态代理基本一致,以上就是两种动态代理模式的使用。
评论记录:
回复评论: