一、代理是什么
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
通俗的讲,在有些情况下,一个客户不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代理对象。例如,购买火车票不一定要去火车站买,可以通过 携程或者淘宝上买。又比如,找保姆、找工作等都可以通过找58或boss等网站中介完成。
二、代理的实现
在java中代理实现的方式有两种,一种是通过继承的方式,另一种是通过组合的方式去实现。
1.继承模式
package com.example.demo.proxy;
public class HouseOwner {
public void rent() {
System.out.println("和房东签署协议,租房完成!");
}
}
package com.example.demo.proxy;
public class Intermediary extends HouseOwner {
public void rent() {
System.out.println("找房....");
super.rent();
System.out.println("收房租....");
}
}
package com.example.demo.proxy;
public class Test {
public static void main(String[] args) {
HouseOwner houseOwner = new Intermediary();
houseOwner.rent();
}
}
2.组合模式
组合模式有三个关键点:
- 代理类和被代理类实现同一接口
- 代理类持有被代理类的接口引用。
- 代理类通过构造函数函数传入被代理类。
package com.example.demo.proxy;
public interface Owner {
void rent();
}
package com.example.demo.proxy;
public class HouseOwner implements Owner {
public void rent() {
System.out.println("和房东签署协议,租房完成!");
}
}
package com.example.demo.proxy;
public class Intermediary implements Owner {
private Owner owner;
public Intermediary(Owner owner) {
this.owner = owner;
}
public void rent() {
System.out.println("找房....");
owner.rent();
System.out.println("收房租....");
}
}
package com.example.demo.proxy;
public class Test {
public static void main(String[] args) {
Owner owner = new Intermediary(new HouseOwner());
owner.rent();
}
}
三、jdk动态代理实现
package com.example.demo.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class Intermediary implements InvocationHandler {
private Owner target;
public Intermediary(Owner target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("找房....");
//通过反射执行目标方法
Object result = method.invoke(target, args);
System.out.println("收房租....");
return result;
}
}
package com.example.demo.proxy;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
HouseOwner houseOwner = new HouseOwner();
Owner owner = (Owner) Proxy.newProxyInstance(houseOwner.getClass()
.getClassLoader(), houseOwner.getClass()
.getInterfaces(), new Intermediary(houseOwner));
owner.rent();
}
}
四、jdk动态代理实现原理
jdk动态代理的实现与上面讲的组合模式实现代理基本一样,只不过不是在编译前手动编写的代理类,而是在运行时通过反射的方式,动态的生成了代理类,所以称为动态代理。
核心实现源码:
package java.lang.reflect;
import java.lang.ref.WeakReference;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiFunction;
import sun.misc.ProxyGenerator;
import sun.misc.VM;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.reflect.misc.ReflectUtil;
import sun.security.util.SecurityConstants;
public class Proxy implements java.io.Serializable {
private static final long serialVersionUID = -2222568056686623797L;
private Proxy() {
}
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
Class<?> cl = getProxyClass0(loader, intfs);
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
}
通过 newProxyInstance方法,jdk在运行时动态生成了代理类$proxy0,并加载到了虚拟机中,这个类实际是不存在的。
$proxy0类的代码如下:
package com.example.demo.proxy;
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 Owner {
private static Method method;
static {
try {
method = Class.forName("com.example.demo.proxy.Owner").getMethod("rent");
} catch (NoSuchMethodException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public $Proxy0(InvocationHandler invocationHandler) {
super(invocationHandler);
}
public final void rent() {
try {
super.h.invoke(this, method, new Object[]{});
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
}