动态代理
动态代理:(转)java动态代理实现与原理详细分析
特点: 字节码随用随创建, 随用随修改
作用: 不修改源码的基础上对方法增强
分类:
基于接口的动态代理
基于子类的动态代理
基于接口的动态代理:
涉及的类:Proxy
提供者:JDK官方
如何创建代理对象:
使用Proxy类的newProxyInstance方法
创建代理对象的要求:
被代理类最少实现一个接口, 如果没有则不能使用
newProxyInstance方法的参数:(查看源码)
/** @param loader the class loader to define the proxy class * @param interfaces the list of interfaces for the proxy class * to implement * @param h the invocation handler to dispatch method * invocations to * @return a proxy instance with the specified invocation handler * of a * proxy class that is defined by the specified class loader * and that implements the specified interfaces */ public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); }
ClassLoader :用于定义代理类的类加载器
是用于加载代理对象字节码的, 和被代理对象使用相同的类加载器。
Class[] : 代理类的接口列表 字节码数组
它是用于让代理对象和被代理对象有相同方法
InvocationHandler : 用于提供增强的代码
它是让我们写如何代理, 写一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的
此接口的实现类都是谁用谁写
使用匿名内部类实现InvocationHandler接口
1 IProducer iProducer=(IProducer)Proxy.newProxyInstance (producer.getClass ().getClassLoader (), producer.getClass ().getInterfaces (), new InvocationHandler () {
2 public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
3 return null;
4 }
5 });
不使用匿名内部类实现InvocationHandler接口
public class MyInvocationHandler<T> implements InvocationHandler { private Object target=null; public MyInvocationHandler (Object target) { this.target= target; } public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { proxy=this.target; //提供增强的代码 /* */ //获取方法执行的参数-----args[0] Object returnValue = method.invoke(proxy,args); return returnValue; } }
InvocationHandler producerInvocationHandler= new MyInvocationHandler<IProducer> (producer); IProducer producerProxy = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(), producer.getClass().getInterfaces(),producerInvocationHandler); producerProxy.saleProduct(10000f);
InvocationHandler中的invoke方法:
* @param proxy the proxy instance that the method was invoked on 代理调用该方法的代理实例 * * @param method the {@code Method} instance corresponding to * the interface method invoked on the proxy instance. The declaring * class of the {@code Method} object will be the interface that * the method was declared in, which may be a superinterface of the * proxy interface that the proxy class inherits the method through. * * @param args an array of objects containing the values of the * arguments passed in the method invocation on the proxy instance, * or {@code null} if interface method takes no arguments. * Arguments of primitive types are wrapped in instances of the * appropriate primitive wrapper class, such as * {@code java.lang.Integer} or {@code java.lang.Boolean}. * * @return the value to return from the method invocation on the * proxy instance. If the declared return type of the interface * method is a primitive type, then the value returned by * this method must be an instance of the corresponding primitive * wrapper class; otherwise, it must be a type assignable to the * declared return type. If the value returned by this method is * {@code null} and the interface method's return type is * primitive, then a {@code NullPointerException} will be * thrown by the method invocation on the proxy instance. If the * value returned by this method is otherwise not compatible with * the interface method's declared return type as described above, * a {@code ClassCastException} will be thrown by the method * invocation on the proxy instance. *
/** * 作用:执行被代理对象的任何接口方法都会经过该方法 * 方法参数的含义 * @param proxy 代理对象的引用 * @param method 当前执行的方法 * @param args 当前执行方法所需的参数 * @return 和被代理对象方法有相同的返回值 * @throws Throwable */ public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { proxy=this.proxy; //提供增强的代码 //获取方法执行的参数-----args[0] Object returnValue =method.invoke(proxy, args); return returnValue; }