概述
JDK动态代理的两个主要类:
java.lang.reflect.InvocationHandler:执行代理对象的方法时的回调接口。在这个接口中编写与代理业务相关的代码。它在JDK中的定义如下。
public interface InvocationHandler {
/**
* @param proxy JDK生成的代理对象
* @param method 被代理接口的方法对象
* @param args 方法执行的参数
* @return
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
java.lang.reflect.Proxy:调用它的静态方法newProxyInstance创建代理对象。它为代理的接口创建实现类,并为其创建一个以InvocationHandler对象为参数的构造方法,每个代理方法都会执行InvocationHandler对象的invoke方法。
运用
A. 鱼儿开始和停止游泳时告诉大家
通过jdk动态代理,可以在一个行为前后添加性能监控、日志等操作。
下面我们来记录鱼儿开始和停止游泳的日志。
(1)定义一个FishService接口和实现
public interface FishService{
/**
* 游泳
**/
void swimming();
}
实现如下
public class FishServiceImpl implements FishService {
public void swimming() {
System.out.println("游泳中....");
}
}
(2)定义SimpleInvocationHandler 用于获得代理对象和和方法回调。
在这里该类的定义稍微复杂了点,直接看我的注释就是。
public class SimpleInvocationHandler implements InvocationHandler {
private Set<Class> interfaces = new HashSet<>();
// 接口和默认实现
private Map<Class, Object> additionalItf = new HashMap<>();
/**
* 添加被代理接口和其实现
* @param itf 被代理的接口
* @param defaultImpl 接口的默认实现
* @param <T>
*/
public <T> void additionalItf(Class<T> itf, T defaultImpl) {
additionalItf.put(itf, defaultImpl);
interfaces.add(itf);
}
/**
* 获得代理对象
* 通过Proxy的静态方法newProxyInstance创建代理
* @return 返回代理对象
*/
public Object getProxy() {
ClassLoader loader = SimpleInvocationHandler.class.getClassLoader();
Class[] interfaces = this.interfaces.toArray(new Class[0]);
return Proxy.newProxyInstance(loader, interfaces, this);
}
/**
* 实现InvocationHandler接口的invoke方法。
* 该方法在执行代理对象的方法时,会回调执行。
* @return 返回被代理的方法的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
try {
System.out.println(name + "方法执行前");
// 根据方法的声明类对象,获取方法的调用者
Object defaultImpl = additionalItf.get(method.getDeclaringClass());
if (defaultImpl == null) {
System.out.println(name + "方法无默认实现");
return null;
}
return method.invoke(defaultImpl, args);
} finally {
System.out.println(name + "方法执行后");
}
}
}
(3)创建代理,并执行接口方法。
public class MainObject {
public static void main(String[] args) throws Exception {
SimpleInvocationHandler handler = new SimpleInvocationHandler();
// 添加被代理接口和实现类
handler.additionalItf(FishService.class, new FishServiceImpl());
// 获得代理对象
FishService fishService = (FishService) handler.getProxy();
// 通过代理对象执行代理方法
fishService.swimming();
}
}
输入如下。
swimming方法执行前
游泳中....
swimming方法执行后
B. 让鱼儿飞起来
可以通过JDK动态代理多个接口,使对象提供更多的服务。操作如下。
(1)定义一个飞行的接口和一个默认实现。
interface FlyService {
/**
* 飞行
*/
void fly();
}
实现飞行接口,如下。
public class FlyServiceImpl implements FlyService {
@Override
public void fly() {
System.out.println("飞...");
}
}
(2)通过SimpleInvocationHandler 创建一个会飞的鱼,代码如下。
class MainObject {
public static void main(String[] args) throws Exception {
SimpleInvocationHandler handler = new SimpleInvocationHandler();
handler.additionalItf(FishService.class, new FishServiceImpl());
handler.additionalItf(FlyService.class, new FlyServiceImpl());
FishService fishService = (FishService) handler.getProxy();
fishService.swimming();
// 让鱼飞起来
((FlyService)fishService).fly();
}
}
运行结果:
swimming方法执行前
游泳中....
swimming方法执行后
fly方法执行前
飞...
fly方法执行后
总结
JDK动态代理的作用:
(1)通过JDK代理可以为接口创建代理。
(2)通过JDK代理可以为类增加更多的行为。
JDK动态代理的不足:
只能为接口创建代理,而不能为一个class类创建代理。