深入理解Java动态代理
引言
设计模式-代理模式
- Subject 抽象主题角色:可以是抽象类,也可以是接口。抽象主题是一个普通的业务类型,无特殊要求。
- RealSubject 具体主题角色:也叫做被委托角色或被代理角色,是业务逻辑的具体执行者。
- Proxy 代理主题角色:也叫做委托类或代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在具体主题角色处理完毕前后做预处理和善后处理工作。
优点:
- 职责清晰(业务类只实现自己具体的业务逻辑,而不用关心其他业务功能,由上层代理类进行完成)
- 高扩展性(在不改变原有类的基础上,通过代理类增加额外的功能)
使用场景:
- 日志打印
- 事务处理
- 数据的过滤,预处理,后处理等
代码示例:
# 业务接口定义
public interface IPeople {
void eat();
}
# 业务实现类
public class WangPeople implements IPeople {
@Override
public void eat() {
System.out.println("吃个苹果");
}
}
# 代理类
public class PeopleProxy implements IPeople {
private IPeople peopleManager;
public PeopleProxy(IPeople peopleManager) {
this.peopleManager = peopleManager;
}
@Override
public void eat() {
peopleManager.eat();
System.out.println("加个鸡腿");
}
}
## 测试
public class MainTest {
public static void main(String[] args) {
IPeople people = new WangPeople();
PeopleProxy proxy = new PeopleProxy(people);
proxy.eat();
}
}
1、JDK动态代理
在代码中不编写具体接口的代理类,在运行期间通过反射实现代理功能
java.lang.reflect.InvocationHandler
java.lang.reflect.Proxy
1.1、代码示例
public class PeopleProxyHandler implements InvocationHandler {
private IPeople target;
private PeopleProxyHandler() {
}
public static IPeople newProxyInstance(IPeople target) {
PeopleProxyHandler proxy = new PeopleProxyHandler();
proxy.target = target;
return (IPeople) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), proxy);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object ret = null;
try {
ret = method.invoke(target, args);
System.out.println("加个鸡腿");
} catch (Exception e) {
System.err.println("PeopleDynamicProxy 执行业务方法异常");
}
return ret;
}
}
public class MainTest2 {
public static void main(String[] args) {
IPeople people = new WangPeople();
IPeople wangPeople = PeopleProxyHandler.newProxyInstance(people);
wangPeople.eat();
}
}
运行效果:
1.2、动态生成代理类
public final class $Proxy0 extends Proxy implements IPeople {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
// 重写所有被代理类方法,并声明为final
// 传入代理类,执行方法,和参数
public final void eat() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.docker.test.dockertest.proxy.jdk.IPeople").getMethod("eat");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
调用的时序图
1.3、源码分析
public interface InvocationHandler {
/**
* proxy – 调用该方法的代理实例(被代理的对象)
* method – 与在代理实例上调用的接口方法对应的Method实例(要调用的方法)
* args – 包含在代理实例的方法调用中传递的参数值的对象数组
* return 从代理实例上的方法调用返回的值
**/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
public class Proxy implements java.io.Serializable {
/**
*
* loader 定义代理类的类加载器
* interfaces 代理类要实现的接口列表
* h 将方法调用分派到的调用处理程序
* return 具有代理类的指定调用处理程序的代理实例
**/
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);
}
/*
* 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);
}
}
}
1.4、优缺点
- 优点:当需要对业务类中的每个方法加统一逻辑时,不需要对每个方法都实现一个代理方法,而是使用invoke进行统一处理
- 缺点:它必须依赖于interface 来实现动态代理,否则将不能使用
2、Cglib
cglib 是一个强大、高性能和高质量的代码生成库。它用于扩展 JAVA 类并在运行时实现接口,为JDK的动态代理提供了很好的补充。开源免费
https://github.com/cglib/cglib
- CGLIB代理主要通过对字节码的操作,为对象引入间接级别,以控制对象的访问
- CGLIB主要依赖于ASM包实现对字节码的操作
- Java 字节码是Java代码编译之后的一种低级语言表示,Java虚拟机执行的就是字节码文件,以.class为扩展名的文件
2.1、代码示列:
# 拦截方法,实现附加功能
public class PeopleMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object object = methodProxy.invokeSuper(o, args);
System.out.println("加个鸡腿");
return object;
}
}
# 通过CGLIB增强类创建实例,执行业务方法
public class CglibMainTest {
public static void main(String[] args) {
// 生产CGLIB动态代理类到指定的目录中
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/haoyin/work/personal/docker-test/code");
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(WangPeople.class);
enhancer.setCallback(new PeopleMethodInterceptor());
WangPeople people = (WangPeople) enhancer.create();
people.eat();
}
}
运行效果:
2.2 、动态生成的代理类
一共动态生产了三个类:
- classNameEnhancerByCGLIBxxxxxx 代理类
- classNameEnhancerByCGLIBxxxxxFastClassByCGLIBxxxxxx FastClass f2 代理类的增强类
- classNameFastClassByCGLIBxxxxxx FastClass f1 原始类的增加类
WangPeopleEnhancerByCGLIBb9fd69a8.class(删除了一些无关代码)
public class WangPeople$$EnhancerByCGLIB$$b9fd69a8 extends WangPeople implements Factory {
private boolean CGLIB$BOUND;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private static final Method CGLIB$eat$0$Method;
private static final MethodProxy CGLIB$eat$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("com.docker.test.dockertest.proxy.jdk.WangPeople$$EnhancerByCGLIB$$b9fd69a8");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$eat$0$Method = ReflectUtils.findMethods(new String[]{"eat", "()V"}, (var1 = Class.forName("com.docker.test.dockertest.proxy.jdk.WangPeople")).getDeclaredMethods())[0];
CGLIB$eat$0$Proxy = MethodProxy.create(var1, var0, "()V", "eat", "CGLIB$eat$0");
}
// 调用被代理类原始方法
// methodProxy.invokeSuper调用此方法
final void CGLIB$eat$0() {
super.eat();
}
// 判断是否是有拦截器配置,如果有就执行拦截器方法,否则执行被代理类原始方法
// methodProxy.invoke 会调用此方法,如果在拦截方法中调用methodProxy.invoke会出现死循环
public final void eat() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$eat$0$Method, CGLIB$emptyArgs, CGLIB$eat$0$Proxy);
} else {
super.eat();
}
}
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -1310345955:
if (var10000.equals("eat()V")) {
return CGLIB$eat$0$Proxy;
}
break;
return null;
}
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
WangPeople$$EnhancerByCGLIB$$b9fd69a8 var1 = (WangPeople$$EnhancerByCGLIB$$b9fd69a8)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (var10000 == null) {
return;
}
}
var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
}
}
public Object newInstance(Callback[] var1) {
CGLIB$SET_THREAD_CALLBACKS(var1);
WangPeople$$EnhancerByCGLIB$$b9fd69a8 var10000 = new WangPeople$$EnhancerByCGLIB$$b9fd69a8();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Callback var1) {
CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
WangPeople$$EnhancerByCGLIB$$b9fd69a8 var10000 = new WangPeople$$EnhancerByCGLIB$$b9fd69a8();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
WangPeople$$EnhancerByCGLIB$$b9fd69a8 var10000 = new WangPeople$$EnhancerByCGLIB$$b9fd69a8;
switch(var1.length) {
case 0:
var10000.<init>();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
default:
throw new IllegalArgumentException("Constructor not found");
}
}
static {
CGLIB$STATICHOOK1();
}
}
WangPeopleEnhancerByCGLIBb9fd69a8FastClassByCGLIBa91fce25(删除了一些无关代码)
public class WangPeople$$EnhancerByCGLIB$$b9fd69a8$$FastClassByCGLIB$$a91fce25 extends FastClass {
public WangPeople$$EnhancerByCGLIB$$b9fd69a8$$FastClassByCGLIB$$a91fce25(Class var1) {
super(var1);
}
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case -1526958892:
if (var10000.equals("CGLIB$eat$0()V")) {
return 2;
}
break;
case -1310345955:
if (var10000.equals("eat()V")) {
return 13;
}
break;
}
return -1;
}
public int getIndex(String var1, Class[] var2) {
switch(var1.hashCode()) {
case 100184:
if (var1.equals("eat")) {
switch(var2.length) {
case 0:
return 13;
}
}
break;
}
case 1111931649:
if (var1.equals("CGLIB$eat$0")) {
switch(var2.length) {
case 0:
return 2;
}
}
break;
return -1;
}
public int getIndex(Class[] var1) {
switch(var1.length) {
case 0:
return 0;
default:
return -1;
}
}
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
b9fd69a8 var10000 = (b9fd69a8)var2;
int var10001 = var1;
try {
switch(var10001) {
case 2:
var10000.CGLIB$eat$0();
return null;
case 13:
var10000.eat();
return null;
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
// 这里new出来的是代理类实例
b9fd69a8 var10000 = new b9fd69a8;
b9fd69a8 var10001 = var10000;
int var10002 = var1;
try {
switch(var10002) {
case 0:
var10001.<init>();
return var10000;
}
} catch (Throwable var3) {
throw new InvocationTargetException(var3);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
public int getMaxIndex() {
return 26;
}
}
WangPeopleFastClassByCGLIB1a9bb430
public class WangPeople$$FastClassByCGLIB$$1a9bb430 extends FastClass {
public WangPeople$$FastClassByCGLIB$$1a9bb430(Class var1) {
super(var1);
}
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case -1310345955:
if (var10000.equals("eat()V")) {
return 0;
}
break;
}
return -1;
}
public int getIndex(String var1, Class[] var2) {
switch(var1.hashCode()) {
case 100184:
if (var1.equals("eat")) {
switch(var2.length) {
case 0:
return 0;
}
}
break;
return -1;
}
public int getIndex(Class[] var1) {
switch(var1.length) {
case 0:
return 0;
default:
return -1;
}
}
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
WangPeople var10000 = (WangPeople)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
var10000.eat();
return null;
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
// 这里new出来的是被代理类实例
WangPeople var10000 = new WangPeople;
WangPeople var10001 = var10000;
int var10002 = var1;
try {
switch(var10002) {
case 0:
var10001.<init>();
return var10000;
}
} catch (Throwable var3) {
throw new InvocationTargetException(var3);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
public int getMaxIndex() {
return 9;
}
}
2.3、源码分析:
2.3.1、代理类的创建过程
enhancer.create();
2.3.2、FastClass怎么来的?
通过MethodProxy进行创建,在调用invoke方法的时候进行懒加载
public class MethodProxy {
// 保存原方法的签名
private Signature sig1;
// CGLIB生成的代理方法签名
private Signature sig2;
// 保存创建代理时的类信息(原类、代理类)
// 为了懒加载的时候创建FastClassInfo
private CreateInfo createInfo;
private final Object initLock = new Object();
private volatile FastClassInfo fastClassInfo;
/**
* For internal use by {@link Enhancer} only; see the {@link net.sf.cglib.reflect.FastMethod} class
* for similar functionality.
*/
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
MethodProxy proxy = new MethodProxy();
proxy.sig1 = new Signature(name1, desc);
proxy.sig2 = new Signature(name2, desc);
proxy.createInfo = new CreateInfo(c1, c2);
return proxy;
}
private void init()
{
/*
* Using a volatile invariant allows us to initialize the FastClass and
* method index pairs atomically.
*
* Double-checked locking is safe with volatile in Java 5. Before 1.5 this
* code could allow fastClassInfo to be instantiated more than once, which
* appears to be benign.
*/
if (fastClassInfo == null)
{
synchronized (initLock)
{
if (fastClassInfo == null)
{
CreateInfo ci = createInfo;
FastClassInfo fci = new FastClassInfo();
fci.f1 = helper(ci, ci.c1);
fci.f2 = helper(ci, ci.c2);
fci.i1 = fci.f1.getIndex(sig1);
fci.i2 = fci.f2.getIndex(sig2);
fastClassInfo = fci;
createInfo = null;
}
}
}
}
private static class FastClassInfo
{
FastClass f1;
FastClass f2;
int i1;
int i2;
}
// 生成代理类或者被代理类的 fastClass
private static FastClass helper(CreateInfo ci, Class type) {
FastClass.Generator g = new FastClass.Generator();
g.setType(type);
g.setClassLoader(ci.c2.getClassLoader());
g.setNamingPolicy(ci.namingPolicy);
g.setStrategy(ci.strategy);
g.setAttemptLoad(ci.attemptLoad);
return g.create();
}
/**
* 调用原始方法
* Invoke the original method, on a different object of the same type.
* @param obj the compatible object; recursion will result if you use the object passed as the first
* argument to the MethodInterceptor (usually not what you want)
* @param args the arguments passed to the intercepted method; you may substitute a different
* argument array as long as the types are compatible
* @see MethodInterceptor#intercept
* @throws Throwable the bare exceptions thrown by the called method are passed through
* without wrapping in an <code>InvocationTargetException</code>
*/
public Object invoke(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f1.invoke(fci.i1, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (IllegalArgumentException e) {
if (fastClassInfo.i1 < 0)
throw new IllegalArgumentException("Protected method: " + sig1);
throw e;
}
}
/**
* 调用代理类的方法
* Invoke the original (super) method on the specified object.
* @param obj the enhanced object, must be the object passed as the first
* argument to the MethodInterceptor
* @param args the arguments passed to the intercepted method; you may substitute a different
* argument array as long as the types are compatible
* @see MethodInterceptor#intercept
* @throws Throwable the bare exceptions thrown by the called method are passed through
* without wrapping in an <code>InvocationTargetException</code>
*/
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
}
时序图:
优点:
- 不使用反射方式调用方法,而通过生成FastClass进行缓存,进行直接调用
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 蛮王的记事本
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果
Steam卡片