芙蓉生在秋江上,不向东风怨未开
上一篇写了Java的静态代理的使用方法,动态代理要比静态代理稍微复杂一点。
首先定义一个接口:
/**
* @author aRunner
* @date 2020/5/11
*/
public interface Person {
/**
*@author aRunner
*@date 2020/5/11
*@description 睡觉方法
*/
public void sleep(String time) ;
/**
*@author aRunner
*@date 2020/5/11
*@description 吃饭方法
*/
public void eat(String something) ;
}
定义被代理的类:
/**
* @author aRunner
* @date 2020/5/11
*/
public class Student implements Person {
@Override
public void sleep(String time) {
System.out.println("Student 正在睡" + time);
}
@Override
public void eat(String something) {
System.out.println("Student 正在吃" + something);
}
}
现在编写动态代理的类:
import java.lang.reflect.Proxy;
/**
* 动态代理,动态代理类不要显示的实现被代理类所实现的接口
* @author aRunner
*
*/
public class MyInvocationHandler {
public static void main(String [] args){
//创建需要被代理的类
Student s = new Student();
Person person = (Person) Proxy.newProxyInstance(s.getClass().getClassLoader(), s.getClass().getInterfaces(), (proxy, method, params) -> {
if (method.getName().equals("sleep")) {
System.out.println("Student 准备睡觉");
return method.invoke(s, params);
} else if (method.getName().equals("eat")) {
System.out.println("Student 准备吃饭");
return method.invoke(s, params);
}
return null;
});
person.sleep("午觉");
person.eat("午饭");
}
}
newProxyInstance(ClassLoader loader, Class>[] interfaces,InvocationHandler h)方法
该方法的参数解释:
loder和interfaces基本就是决定了这个类到底是个怎么样的类。而h是InvocationHandler,决定了这个代理类到底是多了什么功能。所以动态代理的内容重点就是这个InvocationHandler。
InvocationHandler
先来看看该接口的注释:
* Processes a method invocation on a proxy instance and returns
* the result. This method will be invoked on an invocation handler
* when a method is invoked on a proxy instance that it is
* associated with.
*
* @param proxy the proxy instance that the method was invoked on
*
* @param method the {@code Method} instance corresponding to
* the interface method invoked on the proxy instance. The declaring
* class of the {@code Method} object will be the interface that
* the method was declared in, which may be a superinterface of the
* proxy interface that the proxy class inherits the method through.
*
* @param args an array of objects containing the values of the
* arguments passed in the method invocation on the proxy instance,
* or {@code null} if interface method takes no arguments.
* Arguments of primitive types are wrapped in instances of the
* appropriate primitive wrapper class, such as
* {@code java.lang.Integer} or {@code java.lang.Boolean}.
*
* @return the value to return from the method invocation on the
* proxy instance. If the declared return type of the interface
* method is a primitive type, then the value returned by
* this method must be an instance of the corresponding primitive
* wrapper class; otherwise, it must be a type assignable to the
* declared return type. If the value returned by this method is
* {@code null} and the interface method's return type is
* primitive, then a {@code NullPointerException} will be
* thrown by the method invocation on the proxy instance. If the
* value returned by this method is otherwise not compatible with
* the interface method's declared return type as described above,
* a {@code ClassCastException} will be thrown by the method
* invocation on the proxy instance.
根据注解描述可知,InvocationHandler作用就是,当代理对象的原本方法被调用的时候,会绑定执行一个方法,这个方法就是InvocationHandler里面定义的内容,同时会替代原本方法的结果返回。
来看看newProxyInstance()方法的源码:
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);
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
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);
}
}
首先是克隆一个接口:final Class>[] intfs = interfaces.clone();
,然后通过参数中的类加载器和克隆出来的接口,拿到代理类:Class> cl = getProxyClass0(loader, intfs);
,再通过反射技术,利用代理类获取代理类的构造函数:final Constructor> cons = cl.getConstructor(constructorParams);
,最后通过构造函数new一个对象出来:return cons.newInstance(new Object[]{h});
,同时用InvocationHandler绑定这个对象。
本文参考至:你真的完全了解Java动态代理吗?看这篇就够了