Proxy.newProxyInstance是实现java对象的动态代理的方法,他的三个参数loader、 interfaces、h分别代表是需求代理的接口的加载器、 代理接口列表、this。注意,只能代理接口,不能代理类或者抽象类。
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
1、第一次测试我尝试着动态代理能不能实现类似after,before的功能,用来记录支付的次数或者其他功能。
根据上图我建立一个测试接口:Pay
public interface Pay {
boolean pay();
}
再新建一个Person类,实现Pay接口:
public class Person implements Pay {
@Override
public boolean pay() {
System.out.println("支付中。。。");
return true;
}
}
再新建一个代理类:
public class PayProxy<T> {
public PayProxy() {
}
private static int count = 0;
public void before(){
count++;
System.out.println("快要支付了");
}
public void after(){
System.out.println("支付完成, 已完成" + count + "次");
}
/**
* @Description <p> 动态代理,通过接口获取实现接口的对象的实例</p>
* @FunName <p></p>
* @Param {serviceInterface : 需要代理的接口class}
* @Param {u : 实现serviceInterface接口的类,也就是这次我门要来计算次数}
*/
public T getRemoteProxyObj(final Class<T> serviceInterface, Class<? extends T> u) {
return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class[]{serviceInterface},
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object obj = method.invoke(u.getConstructor().newInstance(), args);
after();
return obj;
}
});
}
}
编写测试主类
public class PayTest {
public static void main(String[] args) throws IOException {
PayProxy<Pay> payProxy = new PayProxy<Pay>();
Pay pay = payProxy.getRemoteProxyObj(Pay.class, Person.class);
pay.pay();
}
}
测试结果:
快要支付了
支付中。。。
支付完成, 已完成1次
分析:
关键代码
before();
Object obj = method.invoke(u.getConstructor().newInstance(), args); //这儿调用的是Person的pay方法,该代理类是类似监听器,监听所有实现serviceInterface接口的类调用该接口里面的方法(pay方法)。但是这儿有个不完美的地方,熟悉的人可能发现,我这儿是在调用pay方法之后才让Pay接口的实现类Person实例化,有人可能会说,为什么不通过参数传递呢,下面我就来第二个。
after();
2、同样的实现那个功能,但是我们修改代理类如下:
public class PayProxy<T> {
public PayProxy() {
}
private static int count = 0;
public void before(){
count++;
System.out.println("快要支付了");
}
public void after(){
System.out.println("支付完成, 已完成" + count + "次");
}
/**
* @Description <p> 动态代理,通过接口获取实现接口的对象的实例</p>
* @FunName <p></p>
* @Param {serviceInterface : 需要代理的接口class}
* @Param {u : 实现serviceInterface接口的类,也就是这次我门要来计算次数}
*/
public T getRemoteProxyObj(final Class<T> serviceInterface,@NotNull T u) {
return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class[]{serviceInterface},
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object obj = method.invoke(u, args);
after();
return obj;
}
});
}
}
同样修改测试类:
public class PayTest {
public static void main(String[] args) throws IOException {
PayProxy<Pay> payProxy = new PayProxy<Pay>();
Person person = new Person();
Pay pay = payProxy.getRemoteProxyObj(Pay.class, person);
pay.pay();
}
}
经多测试一样的能结果。
3、我想通过它实现一个匿名类:
这次我们不需要Person类了。只需要修改代理类
public class PayProxy<T> {
public Object doSome(){
System.out.println("这儿需要作的处理");
return false;
}
/**
* @Description <p> 动态代理,通过接口获取实现接口的对象的实例</p>
* @FunName <p></p>
* @Param {serviceInterface : 需要代理的接口class}
* @Param {u : 实现serviceInterface接口的类,也就是这次我门要来计算次数}
*/
public T getRemoteProxyObj(final Class<T> serviceInterface) {
return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class[]{serviceInterface},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object object = doSome(); // 这里面可以传递参数给doSome,方法里面的参数值是args。比如doSome(args)
return object;
}
});
}
}
测试类修改:
public class PayTest {
public static void main(String[] args) throws IOException {
PayProxy<Pay> payProxy = new PayProxy<Pay>();
Pay pay = payProxy.getRemoteProxyObj(Pay.class);
pay.pay();
}
}
测试结果:
这儿需要作的处理
代理使用心得:
Proxy.newProxyInstance(代理对象类加载器,生成类需要实现的接口s,InvocationHandler是的实现(统一的给需要实现的接口统一的编写实现方式,Method和arg[]两个参数判断是那个方法) )。在Proxy.newProxyInstance中还可以在method.invoke执行前后做些准备工作,类似拦截器,监听器,junit过程。
另外,能够使用Proxy.newProxyInstance的都能使用CGLib来实现,CGLib生成代码更加彻底。它一个强大的、高性能的代码生成库,这儿就不详细赘述。