一、问题
1、什么是动态代理模式
2、动态代理模式的使用方法
3、动态代理模式的使用演示
4、动态代理模式的原理分析
二、解决问题
1、动态代理模式的概念:
所谓动态代理类是在运行时生成的class,在生成它时,你必须提供一组interface给它,则动态代理类就宣称它实现了这些interface。当然,动态代理类就充当一个代理,你不要企图它会帮你干实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
2、动态代理的使用方法:
动态代理的使用可分为四部分
- 接口,定义方法,要被执行的方法
- 被代理类,实现接口,执行接口的方法
- 代理类,实现InvocationHandler,帮助被代理类实现方法
- 客户端(在这里使用测试类)
我们可以来理一下思路:
- 首先我们的目的是实现接口中的方法
- 方法是使用被代理类,即实现该接口的具体类,但是呢,这个具体实现类只负责代理,而不负责实现,所以就需要一个代理类
- 代理类是实现具体的方法实现的,实现了一个InvocationHandler接口。
- 现在的重点就在于InvocationHandler是个什么东西,首先明确InvocationHandler的作用就是获得一个handler。
- handler的中文翻译是信息处理机,根据字面意思也就是说用力处理信息的机器。
- InvocationHandler的含义是代理实例的调用程序处理 实现的接口。每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的
invoke
方法。 - 我的理解是代理模式的作用在于拦截对真实对象的访问,代理对象和真实对象(目标对象)具有相同的方法,但是对代理对象的修改不会影响到真实对象,即在代理对象被修改时,真实对象不会被修改。
- InvocationHandler提供了一个方法(来源于jdk API 1.6.0)
invoke(Object proxy, Method method, Object[] args):
在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
invoke方法有三个参数:分别说明
Object proxy:
在其上调用方法的代理实例
Method method:
对应于在代理实例上调用的接口方法的 Method
实例
Object[] args:
包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null
3、代码演示
- 运行环境:windows下的idea
- 依赖jar包:java.lang (一般无需在pom.xml中手动配置依赖)
- 项目类型:maven项目
- 1、创建一个接口,里面包含若干个方法
package com.xawl.reflect.proxy;
public interface LagentDynamiqueInterface {
void method1();
}
- 2、创建具体实现类,即被代理类
package com.xawl.reflect.proxy;
public class LagentDynamiqueImp implements LagentDynamiqueInterface {
@Override
public void method1() {
System.out.println("被代理类的实现方法");
}
}
- 3、创建代理类
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;
}
}
- 4、创建测试类(客户端)
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 <i>invocation handler</i> of a proxy instance.
*
* <p>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<Void>() {
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).该方法的作用是找到
该方法的作用是使用指定的二进制名称查找类
该方法的作用是使用指定的二进制名称查找类