动态代理的作用:在不改变源码的情况下增强方法;
举个例子,在进行简单的jdbc操作的时候,你想做到每执行一次sql语句就打印一句话,作为日志.
说明:本例子是基于接口的动态代理,(当然也有基于子类的动态代理模式了)[点击这里连接到](https://blog.csdn.net/weixin_45127611/article/details/104524537);
首先定义一个接口类,定义一个简单的功能吧:
public interface IProducter {
Float saleProduct(Float money);
}
然后定义一个实现了这个接口的类:
public class ProducterImpl implements Product{
@Override
public Float saleProduct(Float money) {
System.out.println("卖了"+money);
return money;
}
}
好,两个类出来了,现在给你出个问题,你怎么能够在不改变源码的情况下,让每次执行这个方法之前打印一行字,或者是改变money参数的倍数等简单操作??
这些问题其实JDK官方提供的 Proxy 类,就可以解决;基于接口的动态代理是使用JDK官方提供的 Proxy 类,被代理的类至少实现一个接口,创建代理使用的方法;(为什么必须要求被代理的类至少实现一个接口,一会你看一下参数也能够很容易记住和理解了)
接下来是类代码:
public class ProductProxy {
//定义要代理的对象的实现的接口可以用来接收实现类对象(不能用实现类定义)
private IProducter target;
public ProductProxy (IProducter target){
this.target = target;
}
public IProducter getlProxyObject(){
//这里也是必须要用接口类型接收
IProducter proxy = null;
//代理对象由哪一个类加载器负责加载
ClassLoader loader = target.getClass().getClassLoader();
//代理对象的类型,即其中有哪些方法
Class[] interfaces = new Class[]{IProducter .class};
//当调用代理对象其中的方法是,该执行的代码
InvocationHandler h = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("被调用的方法名:"+method.getName());
Float money = (Float) args[0];
money = (float) (0.8*money);
//执行的方法
Object result = method.invoke(target, money);
return result;
}
};
//这个方法是有重载的,在测试类中我会再写一个功能跟这个get方法一样的
proxy = (IProducter ) Proxy.newProxyInstance(loader, interfaces, h);
return proxy;
}
}
测试类用来测试咱们写的东西:
public class Test {
public static void main(String[] args) {
ProductProxy ppy= new ProductProxy(new ProducterImpl());
IProducter get = ppy.getlProxyObject();
System.out.println(get.saleProduct(1000f));
//这样已经完成了基本的使用,也可以用一下的方法来使用基于接口的动态代理。
//必须用接口
/* IProducter pro = (Product) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), //所以说必须要继承至少一个接口
new InvocationHandler() {
//target就是上边的实现类对象,自己定义一个即可;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object returnValue = null;
if("saleProduct".equals(method.getName())) {
Float money = (float) (0.8*(Float)args[0]);
returnValue = method.invoke(target, money);
}
return returnValue;
}
});
pro.saleProduct(1000f);
}
*/
}
两种方法运行的结果都是:
被调用的方法名:saleProduct
卖了800.0
800.0
写到最后:用这种方式的(基于接口的动态代理)中,只有在Proxy.newProxyInstance(target.getClass().getClassLoader(),这个方法的第一个参数才需要用到实现类的类加载器,其余地方如果你写到了实现类那么你的例子一定会失败的;
还有一种基于子类的动态代理:使用cglib实现;
https://blog.csdn.net/weixin_45127611/article/details/104524537