java jdk中自带的基于接口的动态代理实现方式和cglib基于子类的动态代理举例,使用和记忆

动态代理的作用:在不改变源码的情况下增强方法;
举个例子,在进行简单的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

发布了11 篇原创文章 · 获赞 39 · 访问量 2736

猜你喜欢

转载自blog.csdn.net/weixin_45127611/article/details/104523192