java动态代理
动态代理
代理比较好理解,和现实生活中意思一样。就是我要干一件事情,可以通过代理人或代理平台进行完成,不需要直接和服务方接触。
又或者计算机网络上说的代理。为什么叫动态代理?
这里回到java程序上,是因为在运行时可以动态的创建接口的实现,通过java的反射进行实现。依赖三个关键类:Proxy、Method和InvocationHandler.
创建代理实例
使用Proxy类的newProxyInstance方法
/**
loader是类加载器
interfaces 被代理的类,这里只支持接口
InvocationHandler 代理处理handler
*/
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h){}
要创建代理实例,我们就要准备三个参数:第一个类加载器用来动态加载class文件。第二个参数需要动态代理的接口。第三个参数代理处理handler。创建被代理实例
都会调用该handler的invoke方法。
InvocationHandler只有一个接口方法
public interface InvocationHandler{
Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
invoke方法持有三个参数:
proxy代理实例对象,就是newProxyInstance创建的实例,目前没有发现有哪些用处
method被代理方法实例。这里就可以通过反射获取方法定义相关的信息。
args调用方法实例参数。
invoke方法体就是具体我们要对代理方法进行增强的操作逻辑。一般情况下我们在一些操作后还要执行原先method的方法逻辑,当然你也可以完全修改原逻辑。学过反射都知道
通过反射执行method.invoke(target, args)。需要target实例对象,args参数。这里参数已经有了,还差target实例。所以一般在实现InvocationHandler接口的时候
还会把target对象传进来。
完整的一个代理例子:
public class DynamicProxyTest {
static class DyInvokeHandler implements InvocationHandler{
public DyInvokeHandler(Object target){
this.target = target;
}
//被代理实例对象
private Object target;
//这里proxy参数就是外面创建的代理对象proxyMap
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("put".equals(method.getName()))
System.out.println("invoke method:"+method.getName());
return method.invoke(target, args);
}
}
public static void main(String[] args) {
//创建Map接口的代理对象
Map proxyMap = (Map) Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(),
new Class[]{Map.class},new DyInvokeHandler(new HashMap<>()));
proxyMap.put("name","test");
System.out.println(proxyMap.get("name"));
}
}
使用场景
spring中的AOP切面编程还有依赖注入、事务的控制都是用的动态代理。日志记录,mock接口数据,权限控制其实都可以使用。