一、问题
1、什么是动态代理模式
2、动态代理模式的使用方法
3、动态代理模式的使用演示
4、动态代理模式的原理分析
二、解决问题
1、动态代理模式的概念:
所谓动态代理类是在运行时生成的class,在生成它时,你必须提供一组interface给它,则动态代理类就宣称它实现了这些interface。当然,动态代理类就充当一个代理,你不要企图它会帮你干实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
2、动态代理的使用方法:
动态代理的使用可分为四部分
我们可以来理一下思路:
invoke
方法。invoke(Object proxy, Method method, Object[] args): 在代理实例上处理方法调用并返回结果。 在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。 |
invoke方法有三个参数:分别说明
Object proxy:
在其上调用方法的代理实例
Method method:
对应于在代理实例上调用的接口方法的 Method
实例
Object[] args:
包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null
3、代码演示
package com.xawl.reflect.proxy;
public interface LagentDynamiqueInterface {
void method1();
}
package com.xawl.reflect.proxy;
public class LagentDynamiqueImp implements LagentDynamiqueInterface {
@Override
public void method1() {
System.out.println("被代理类的实现方法");
}
}
package com.xawl.reflect.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class LagebtClass implements InvocationHandler {
private Object object;
public LagebtClass(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法执行前");
Object result = method.invoke(object, args);
System.out.println("方法执行后");
return result;
}
}
package com.xawl.proxy;
import com.xawl.reflect.proxy.LagebtClass;
import com.xawl.reflect.proxy.LagentDynamiqueImp;
import com.xawl.reflect.proxy.LagentDynamiqueInterface;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class ClientProxy {
public static void main(String[] args) {
//获取实现具体方法的被代理类对象
LagentDynamiqueImp lagentDynamiqueImp = new LagentDynamiqueImp();
//将目标对象交给代理类
InvocationHandler handler = new LagebtClass(lagentDynamiqueImp);
//返回代理对象(要实现方法的接口)
LagentDynamiqueInterface lagentDynamiqueInterface = (LagentDynamiqueInterface)
Proxy.newProxyInstance(handler.getClass().getClassLoader(),
lagentDynamiqueImp.getClass().getInterfaces(),
handler);
lagentDynamiqueInterface.method1();
}
}
4、原理分析:我们在这里是使用jdk提供好的类和接口来实现的代理模式,接下来我们手动来用代码走一下实现原理
分析:在上面我们直接使用了jdk的类和接口,分别是:Proxy,InvocationHandler,ClassLoader
所以我们现在需要来手动写这三个类
先来看一下他们的源码以及在本例中使用的功能,然后再去动手写:
1、InvocationHandler
package java.lang.reflect;
/**
* {@code InvocationHandler} is the interface implemented by
* the invocation handler of a proxy instance.
*
* Each proxy instance has an associated invocation handler.
* When a method is invoked on a proxy instance, the method
* invocation is encoded and dispatched to the {@code invoke}
* method of its invocation handler.
*
* @author Peter Jones
* @see Proxy
* @since 1.3
*/
public interface InvocationHandler {
/**
* Processes a method invocation on a proxy instance and returns
* the result. This method will be invoked on an invocation handler
* when a method is invoked on a proxy instance that it is
* associated with.
*
* @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.
*
* @throws Throwable the exception to throw from the method
* invocation on the proxy instance. The exception's type must be
* assignable either to any of the exception types declared in the
* {@code throws} clause of the interface method or to the
* unchecked exception types {@code java.lang.RuntimeException}
* or {@code java.lang.Error}. If a checked exception is
* thrown by this method that is not assignable to any of the
* exception types declared in the {@code throws} clause of
* the interface method, then an
* {@link UndeclaredThrowableException} containing the
* exception that was thrown by this method will be thrown by the
* method invocation on the proxy instance.
*
* @see UndeclaredThrowableException
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
InvocationHandler是一个接口,里面定义了invoke方法,该方法返回3个参数,proxy,method,args。这三个方法在上面已有说明,这里不再赘述。
2、Proxy:newProxyInstance的方法源码分析
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
//requireNonNull:静态方法,返回h
Objects.requireNonNull(h);
//返回一个和接口具有相同功能的对象,但是改变该对象不会影响到接口
final Class>[] intfs = interfaces.clone();
//返回一个系统的安全接口
final SecurityManager sm = System.getSecurityManager();
//若接口为空,即没有接口,则检查
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
Class> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//获取构造对象
final Constructor> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
Proxy实现了java.io.Serializable接口,这个接口没有定义方法。Proxy类里面有一个很重要的方法,newProxyInstance(ClassLoader loader,Class>[]Interface,InvactaionHandler handler);
3、ClassLoader类:负责加载类的对象
ClassLoader是一个抽象类,里面有一个方法是findClass(String name).该方法的作用是找到
该方法的作用是使用指定的二进制名称查找类
该方法的作用是使用指定的二进制名称查找类