一、基本介绍
1. 代理模式的基本介绍
- 代理模式:为一个对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
- 被代理的对象可以是远程对象、创建开销大的对象或者需要安全控制的对象
- 代理模式有不同的形式,主要有三种静态代理、动态代理(JDK代理、接口代理)和CGLIB代码(可以在内存动态创建对象,而不需要实现接口,他是属于动态代理的范畴)
二、静态代理
1. 静态代理模式代码的基本介绍
- 静态代理在使用时,需要定义接口,被代理对象(即目标对象)与代理对象一起实现相同接口。
2. 应用实例
现在有一个场景,就是你想买Switch游戏机,但是正版的Switch只在日本生产和销售,所以你想买Switch游戏机,只能在淘宝、京东等这些地方去购买。那么你从淘宝、京东上购买的Switch的价格和直接在日本购买的价格是一样的吗,肯定是淘宝、京东上买的更贵,这就是功能增强,提高Switch的价格。
(1) 定义一个接口:SwitchSell
public interface SwitchSell {
/**
* 根据购买相应switch的数量,返回相应的价格。
* @param buySwitchNum 购买switch的数量
* @return
*/
double sell(long buySwitchNum);
}
(2)目标类对象NintendoSwitchSell实现SwitchSell
public class NintendoSwitchSell implements SwitchSell{
public static final double SWITCH_PRICE = 100.0d;
/**
* 任天堂:一个switch100元,购买100个打9折
* @param buySwitchNum 购买switch的数量
* @return
*/
@Override
public double sell(long buySwitchNum) {
return buySwitchNum < 100 ? buySwitchNum*SWITCH_PRICE : buySwitchNum*SWITCH_PRICE*0.9;
}
}
(3)代理对象TaoBaoSwitchSell实现了SwitchSell
public class TaobaoSwitchSell implements SwitchSell{
public static final double SWITCH_PRICE = 120.0d;
private NintendoSwitchSell nintendoSwitchSell;
public TaobaoSwitchSell(NintendoSwitchSell nintendoSwitchSell) {
this.nintendoSwitchSell = nintendoSwitchSell;
}
/**
* 淘宝:一个Switch游戏机120元一个
* @param buySwitchNum 购买switch的数量
* @return
*/
@Override
public double sell(long buySwitchNum) {
// 可以在这里做一些功能增强,例如,购买会员,满多少送一个优惠券、购买数量满多少打折。
// 这里提高售价就是功能增强的一种体现
double price = nintendoSwitchSell.sell(buySwitchNum);
System.out.println("代理商在任天堂购买"+buySwitchNum+"个Switch,共花了"+price+"元");
price = buySwitchNum * SWITCH_PRICE;
System.out.println("用户在淘宝购买"+buySwitchNum+"个Switch,共花了"+price+"元");
return price;
}
}
(4)调用的时候通过调用代理对象的方法来调用目标对象
public class SwitchTest {
public static void main(String[] args) {
// 创建目标对象
NintendoSwitchSell nintendoSwitchSell = new NintendoSwitchSell();
// 创建代理对象,同时将被代理对象传递给代理对象
TaobaoSwitchSell taobaoSwitchSell = new TaobaoSwitchSell(nintendoSwitchSell);
// 通过代理对象,调用被对象对象的方法
// 执行的是代理对象的方法,代理对象再去调用目标对象的方法
taobaoSwitchSell.sell(100);
}
}
3、静态代理优缺点
- 优点:在不修改目标对象的功能前提下,能通过代理对象对目标功能扩展
- 缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类
- 一旦接口增加方法,目标对象与代理对象都要维护
三、动态代理
1、动态代理模式的基本介绍
- 目标对象要实现接口,否则不能用动态代理
- 代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象
- 动态代理也叫做:JDK代理、接口代理
2、JDK代理生成代理对象的API
- 代理类所在的包:java.lang.reflect.Proxy
- JDK实现代理只需要使用newProxyInstance方法,但是改方法需要接受三个参数,完整的写法是:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
loader:用于定义代理类的类装入器
interfaces:目标类所实现的接口
h:调用处理程序,这是一个接口,只要一个invoke方法。执行代理类的相应方法时,方法内部会调用处理程序的invoke方法,而在invoke方法里面我们自己可以实现,通过反射从而调用目标对象的方法。
3、动态代理实例
(1)创建调用处理程序
/**
* 调用处理器实现类
* 每次生成动态代理类对象时都需要指定一个实现了该接口的调用处理器对象
*/
public class InvocationHandlerImpl implements InvocationHandler {
/**
* 这个就是我们要代理的真实对象
*/
private NintendoSwitchSell nintendoSwitchSell;
/**
* 构造方法,给我们要代理的真实对象赋初值
*
* @param nintendoSwitchSell
*/
public InvocationHandlerImpl(NintendoSwitchSell nintendoSwitchSell) {
this.nintendoSwitchSell = nintendoSwitchSell;
}
/**
* 该方法负责集中处理动态代理类上的所有方法调用。
* 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行
*
* @param proxy 代理类实例
* @param method 被调用的方法对象
* @param args 调用参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
Object price = method.invoke(nintendoSwitchSell, args);
long buySwitchNum = Long.parseLong(args[0].toString());
System.out.println("代理商在任天堂购买"+buySwitchNum+"个Switch,共花了"+price+"元");
price = buySwitchNum * 120.0d;
System.out.println("用户在淘宝购买"+buySwitchNum+"个Switch,共花了"+price+"元");
//在代理真实对象后我们也可以添加一些自己的操作
return price;
}
}
(2)调用代码
public class SwitchTest {
public static void main(String[] args) {
// 创建目标对象
NintendoSwitchSell nintendoSwitchSell = new NintendoSwitchSell();
// 创建代理对象,同时将被代理对象传递给代理对象
TaobaoSwitchSell taobaoSwitchSell = new TaobaoSwitchSell(nintendoSwitchSell);
// 通过代理对象,调用被对象对象的方法
// 执行的是代理对象的方法,代理对象再去调用目标对象的方法
taobaoSwitchSell.sell(100);
// 创建代理对象
SwitchSell proxy = (SwitchSell) Proxy.newProxyInstance(NintendoSwitchSell.class.getClassLoader(), NintendoSwitchSell.class.getInterfaces(), new InvocationHandlerImpl(nintendoSwitchSell));
proxy.sell(100);
}
}
4、动态代理源码解析
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
// 判断有没有创建代理的权限
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
// 这是动态代理中最重要的方法,代理类就是从中得到的
Class<?> cl = getProxyClass0(loader, intfs);
// 判断代理类是否可以访问
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
// 得到代理类的构造方法,代理类只有一个有参的构造方法,参数类型就是InvocationHandler,这个后面我们会说到的
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
// 判断代理类是否是被public修饰的,如果不是,设计代理类是可以通过反射访问到的
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);
}
}
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// 通过缓存得到代理类,如果没有就创建
return proxyClassCache.get(loader, interfaces);
}
我们看一下proxyClassCache是什么类的实例
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
public WeakCache(BiFunction<K, P, ?> subKeyFactory,
BiFunction<K, P, V> valueFactory) {
this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
this.valueFactory = Objects.requireNonNull(valueFactory);
}
KeyFactory实现了函数性接口,其中apply放回了相应接口的虚引用
private static final class KeyFactory
implements BiFunction<ClassLoader, Class<?>[], Object>
{
@Override
public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
switch (interfaces.length) {
// 目标类实现了一个接口,就返回一个接口的虚引用,Key1继承了WeakReference,并重写了equals方法,以保证相同接口名是的对象是同一个
case 1: return new Key1(interfaces[0]);
// 目标类实现了两个接口,就返回两个接口的虚引用,Key2继承了WeakReference,并重写了equals方法,以保证两个相同接口名是的对象是同一个
case 2: return new Key2(interfaces[0], interfaces[1]);
// 如果目标类没有实现接口就返回一个Object对象
case 0: return key0;
// 返回一个虚引用数组,KeyX继承了WeakReference,并重写了equals方法,以保证多个相同接口名是的对象是同一个
default: return new KeyX(interfaces);
}
}
}
ProxyClassFactory也实现了函数性接口,返回代理类的Class对象
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// 代理类类名的前缀
private static final String proxyClassNamePrefix = "$Proxy";
//代理类类名的后缀
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
// 判断相同名字的接口是否是同一个Class对象
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
// 判断相应接口是否是一个真正的接口
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
// 验证接口是否重复
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null;
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
// 如果目标类实现的接口中,有接口不是被public修饰的,那么代理类会动态生成在那个不是被public修饰的接口所在包下,且被final修饰,如果有多个接口不是被public修饰的,而且这些接口不在同一个包下,那么会报错。因为如果不是在同一个包下,可能会出现访问不到的问题
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// 如果目标类所实现的接口都是被public修饰的,那么会动态生成在com.sun.proxy下,而且被public final修饰
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
// 生成代理类的二进制文件
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
// 动态生成代理类,这就是最后一步了,由于是native方法,所以就无法向下追究了
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
}
我们最后再来看一下proxyClassCache.get(loader, interfaces)
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
expungeStaleEntries();
// 同一个类加载器是同一个cacheKey
Object cacheKey = CacheKey.valueOf(key, refQueue);
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// 调用前面我们说到的KeyFactory实例对象的apply方法,返回目标实现接口的虚引用
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
while (true) {
if (supplier != null) {
// 到这一步,其实supplier就是factory对象
V value = supplier.get();
if (value != null) {
return value;
}
}
if (factory == null) {
// Factory实现了Supplier类
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
supplier = factory;
}
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
supplier = factory;
} else {
supplier = valuesMap.get(subKey);
}
}
}
}
我们在看一下factory对象的get()方法
public synchronized V get() {
Supplier<V> supplier = valuesMap.get(subKey);
if (supplier != this) {
V value = null;
try {
// 其实最总还是调用了我上面提到的ProxyClassFactory实例对象的apply()方法,返回代理类的Class对象
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
if (value == null) {
valuesMap.remove(subKey, this);
}
}
assert value != null;
CacheValue<V> cacheValue = new CacheValue<>(value);
reverseMap.put(cacheValue, Boolean.TRUE);
if (!valuesMap.replace(subKey, this, cacheValue)) {
throw new AssertionError("Should not reach here");
}
return value;
}
}
5、代理类的庐山真面目
上面我们已经了解了动态代理的大致原理,我们知道生成Class对象是由defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length)这个方法所生成的,而这个方法要传入一个由byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);这个方法所生成的代理类的二进制文件,我们只要把这个二进制文件输出到一个文件中,这个文件就是代理类的class文件,然后工具反解析就行了。
private static void createProxyClassFile() {
String name = "ProxySwitchSell";
byte[] data = ProxyGenerator.generateProxyClass(
name, NintendoSwitchSell.class.getInterfaces(), Modifier.PUBLIC | Modifier.FINAL);
FileOutputStream out = null;
try {
out = new FileOutputStream(name + ".class");
out.write(data);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != out) try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
代理类的java代码:
public final class ProxySwitchSell extends Proxy implements SwitchSell {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public ProxySwitchSell(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
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 double sell(long var1) throws {
try {
return (Double)super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} 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"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("org.xujin.sui.SwitchSell").getMethod("sell", Long.TYPE);
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
通过代理类的Java代码,正如我上面所说,执行代理类的相应方法时,方法内部会调用处理程序的invoke方法,而在invoke方法里面我们自己可以实现,通过反射从而调用目标对象的方法。