静态代理
先看一个例子,有个汽车记录功能,我们既要记录行驶的时间,又要记录其它日志,如果这些事全部交给Car这个对象来做,那么它要处理的事情就太多了,既要跑还有写,所以为了给Car减轻负担,代理类就诞生了,代码如下:
//接口类
public interface MoveAble {
void move();
}
//Car类
public class Car implements MoveAble {
@Override
public void move() {
System.out.println("car move中");
}
}
//记录时间代理类
public class TimeProxy implements MoveAble{
private MoveAble m;
public TimeProxy(MoveAble m){
this.m = m;
}
@Override
public void move() {
System.out.println("time开始");
m.move();
System.out.println("time结束");
}
}
//记录日志代理类
public class LogProxy implements MoveAble {
private MoveAble m;
public LogProxy(MoveAble m) {
this.m = m;
}
@Override
public void move() {
System.out.println("log开始");
m.move();
System.out.println("log结束");
}
}
从以上的代码中可以看出我们创造了两个新的类去继承和Car一样的接口,这样做本质上来说它们三个就都有跑的方法了。那么我们可以像下面的代码那样调用它们:
public static void main(String[] args) {
Car car = new Car();
LogProxy logProxy = new LogProxy(car);
TimeProxy timeProxy = new TimeProxy(logProxy);
timeProxy.move();
}
上面这段代码中把Car先放进了LogProxy里,又把LogProxy放进了TimeProxy里,接着调用了TimeProxy对象的move方法,这时候会一层一层的调用move方法,从TimeProxy到LogProxy再到Car,这样子就把记录时间和日志的功能给完成了。
那么这种代理模式有什么好处呢,可以让不同的功能做不同的事,也就是单一职责,拆分了代码逻辑,使逻辑更加的清晰了。
但是这种静态的代理有个问题,就是我们需要自己去写代理类,如果功能少还好说,要是功能多的话就会很麻烦,所以,动态代理就开始登场了。
动态代理
jdk中为我们提供了创建动态代理对象的方式,即Proxy类。
Proxy类位于java.lang.reflect包中,包含有一个静态的创建方法newProxyInstance,代码如下:
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException{
......//暂时可以忽略的逻辑
}
在上面的创建Proxy类代码中需要接口三个参数:
- ClassLoader loader
类加载器 - Class>[] interfaces
类实现的接口 - InvocationHandler h 处理器
我们重点看一下第三个参数InvocationHandler,这个类是个接口,里面只有一个invoke方法,我们所要做的处理逻辑都会在这个方法里执行。代码如下:
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
invoke方法里也有三个参数:
- Object proxy 调用invoke方法的对象实例
- Method method 对象的方法
- Object[] args 参数
那么我们应该怎么使用动态代理创建我们的代理类呢,基于上面Car记录时间和日志的例子,我们可以这样写:
public static void main(String[] args) {
Car car = new Car();
MoveAble m = (MoveAble) Proxy.newProxyInstance(car.getClass().getClassLoader(), car.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("log开始");
System.out.println("time开始");
method.invoke(car);
System.out.println("time结束");
System.out.println("log结束");
return null;
}
});
m.move();
}
是不是很简单,有个动态代理,我们就不用自己去创建LogProxy,TimeProxy等等代理类了。
动态代理原理
知道了通过动态代理的方式可以帮我们自动的生成一些代理类,那么Proxy究竟是怎么办到的呢,下面就开始分析一下Proxy的内部原理。首先,看一下newProxyInstance这个静态方法,代码如下:
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); //1
try {
final Constructor> cons = cl.getConstructor(constructorParams);//2
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
cons.setAccessible(true);
AccessController.doPrivileged call.
}
return cons.newInstance(new Object[]{h});//3
} 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);
}
}
为了逻辑清晰我删除了注释,这段代码的主要逻辑就是在1,2,3处,这三步分别是:
- 1.得到Proxy的Class对象
- 2.通过Class对象得到Constructor对象
- 3.通过Constructor对象的newInstance方法获得实例对象
下面我们主要分析Class> cl = getProxyClass0(loader, intfs); //1
这行代码,来看看这个方法是怎么生成的Class类对象的。
这个方法的代码很简单:
private static Class> getProxyClass0(ClassLoader loader,
Class>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}
主要就是看最后一行代码,返回的就是Class对象
public V get(K key, P parameter) {
......
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier supplier = valuesMap.get(subKey);
Factory factory = null;
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue instance
V value = supplier.get();
if (value != null) {
return value;//1
}
}
// lazily construct a Factory
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
这段代码我删除了一些注释和与主要逻辑关系不大的代码。
首先来看几个比较的对象:
- Supplier
supplier - Factory factory
先看最后返回的value是通过supplier.get()的,也就是代码中1处的逻辑,那么这个supplier是什么呢,它是个接口,下面的factory是它的实现类,下面的while循环中就是给supplier赋值的过程。也就是说value的最终获取是通过factory里的get方法取得,那么我们再看一下这个get方法逻辑:
public synchronized V get() { // serialize access
......
// create new value
V value = null;
try {
value = Objects.requireNonNull(valueFactory.apply(key, parameter));//1
} finally {
if (value == null) { // remove us on failure
valuesMap.remove(subKey, this);
}
}
return value;
}
这里最重要的逻辑是代码1处,从valueFactory的apply里得到了value,也就是我们最终要得到的Class对象。那么我们再来看看这个valueFactory是什么。
public WeakCache(BiFunction subKeyFactory,
BiFunction valueFactory) {
this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
this.valueFactory = Objects.requireNonNull(valueFactory);
}
valueFactory是BiFunction接口的实现类对象,WeakCache初始化的时候被传进来
public class Proxy implements java.io.Serializable {
private static final long serialVersionUID = -2222568056686623797L;
/** parameter types of a proxy class constructor */
private static final Class>[] constructorParams =
{ InvocationHandler.class };
/**
* a cache of proxy classes
*/
private static final WeakCache[], Class>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
......
}
可以看出来是在Proxy类中被初始化的,也就是ProxyClassFactory类对象。这个ProxyClassFactory也实现了BiFunction,那么上面的apply方法最终的实现逻辑就是在这个类中:
public Class> apply(ClassLoader loader, Class>[] interfaces) {
......
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
return generateProxy(proxyName, interfaces, loader, methodsArray,
exceptionsArray);
}
}
这个方法代码很长,我们只需要关注这几行就行了,可以看出,这个方法设定了一个规则,生成一个字符串proxyName也就是我们的代理类的类名,最后的generateProxy方法实际上是调用了本地的一个方法,就是生成Class对象的方法:
@FastNative
private static native Class> generateProxy(String name, Class>[] interfaces,
ClassLoader loader, Method[] methods,
Class>[][] exceptions);
那么到现在为止就把动态代理怎么生成代理对象的机制分析完了。