Java动态代理源码

对于java代理和反射之间的理解
首先需要明白概念:什么为反射,反射为一种机制,我们可以动态的获取类的所有参数
反射可以用来做什么?现在最常用的设计模式之一的代理模式底层就是通过代理来实现的。
代理:用一个类来代替另一个类执行操作。
静态代理和动态代理的区别就是一个是因为有代理类,在编译期就已经确定了这个类为谁的代理类;
动态代理则是可以随着程序员的选择手动选择代理某个类。
首先先讲一下静态代理。为了符合面向接口编程,创建一个接口来抽象规定用户的某个行为

public interface User {
void eat();
}


现在有两个普通的User类实现这个接口。

public class Rose implements User {
@Override
public void eat() {
System.out.println("我是Rose,我在吃早餐");
}
}
public class Tom implements User {
@Override
public void eat() {
System.out.println("我是tom,我在吃苹果");
}
}


如果想执行这两个用户的操作那肯定就是new Tom().eat之类的,如果现在有需求,要在执行eat方法前先洗手,静态代理的做法如下
先创建一个类来代理tom

public class TomProxy implements User {
private Tom tom;

public TomProxy(Tom tom) {
this.tom = tom;
}

@Override
public void eat() {
//执行前置加强
System.out.println("先洗手");
//执行委托类的方法
tom.eat();
//进行后置加强
System.out.println("吃饱了呀");
}
}

创建代理类的时候传入需要代理类的参数,这样需要Tom吃饭的时候直接创建代理类对象来替他执行
new TomProxy(new Tom()).eat;这样会先执行前置加强再执行代理类的方法,最后执行后置加强
因为手动创建了一个类,其实编译期在编译期就已经知道了哪些类是代理类,这就是静态代理。

动态代理:
动态代理也叫jdk代理,我们将User接口不变,Rose和Tom类也不变,新建一个类LoadHandler,对外提供一个构造方法,参数为需要代理的类实例

public class LoadHandler {

public Object newProxyInstance(Object targetObject) {
//代理的是接口,不是实现类
/** @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 Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), new InvocationHandler() {
@Override

/**
* @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}.
*/

 

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("先洗手");
//通过代理,调用动态代理对象要执行的方法
//如果有返回值,这里Object为空
Object o=method.invoke(targetObject, args);
//这里写方法执行之后的操作
System.out.println("吃饱了");
//没有返回值,直接return
return null;
}
});
}
}

这个动态代理的用法我们肯定知道了,创建一个LoadHandler,传入需要代理的类的实例,返回对象直接调用方法就行了
new LoadHandler().newProxyInstance(new TomProxy()).eat();即可
现在我们来分析里面的参数,方法名字可以看出为创建一个代理实例并返回
我们现在分析一下参数
loader :the class loader to define the proxy class
loader参数定义的类的类加载器,可以通过对象.getclass().getClassLoader()来获得

interfaces :the list of interfaces for the proxy class to implement
interfaces参数为代理类要实现的接口列表

h:invocations to the specified invocation handler.
h参数为调用处理程序,将方法调用分派到指定的调用处理程序。
怎么理解?就是使用我们自己写的调用处理程序来代替方法执行,之前的方法会分派到我们写的调用处理程序里
new InvocationHandler(); 这是一个接口,需要重写invoke方法,有三个参数
@param proxy :the proxy instance that the method was invoked on
proxy:调用方法的代理实例 在这里就是targetObject
@param method:the {@code Method} instance corresponding to
the interface method invoked on the proxy instance.
与代理实例上调用的接口方法相对应的实例,在这里就是eat了。

@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}.
一个对象数组,包含代理实例的方法调用中传递的参数值,如果接口方法不接受任何参数,就为null
而且原始类型的参数要包装,比如Integer。什么意思?就是执行eat方法需要调用的参数,没参数就为Null

java.lang.reflect.Method里对这个invoke的解释如下
Invokes the underlying method represented by this {@code Method}
* object, on the specified object with the specified parameters.
* Individual parameters are automatically unwrapped to match
* primitive formal parameters, and both primitive and reference
* parameters are subject to method invocation conversions as
* necessary.
在具有指定参数的指定对象上调用此method对象表示的基础方法,各个参数将自动解包以匹配原始形式参数
这里method其实就等于eat方法,method.invoke(对象,参数)可以理解为eat.invoke(对象,参数),这里为 什么对象执行eat方法,有什么参数。
附上源码解读

public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
//判断h对象是否为空,可以理解为有没有指定的处理程序
Objects.requireNonNull(h);
//重点在这,动态代理是根据反射来创建的接口实例
final Class<?>[] intfs = interfaces.clone();
//获取程序的安全管理器
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
//检查创建代理类所需的权限
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}

//生成指定的代理类,是根据接口来生成的哦,
Class<?> cl = getProxyClass0(loader, intfs);

//使用指定的调用处理程序调用代理类的构造函数
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);
}
}
不和别人一样,不复制只真正理解
原文地址:https://www.cnblogs.com/Vinlen/p/12749867.html