目录
1 动态代理和静态代理
1.1 代理模式
代理模式是面向对象编程中比较常见的设计模式,uml图如下:
需要注意的有下面几点:
- 用户只关心接口功能,而不在乎谁提供了功能。上图中接口是 Subject。
- 接口真正实现者是上图的 RealSubject,但是它不与用户直接接触,而是通过代理。
- 代理就是上图中的 Proxy,由于它实现了 Subject 接口,所以它能够直接与用户接触。
- 用户调用 Proxy 的时候,Proxy 内部调用了 RealSubject。所以,Proxy 是中介者,它可以增强 RealSubject 操作。
值得注意的是,代理可以分为静态代理和动态代理两种。先从静态代理讲起。
1.2 静态代理
静态代理的代理类时静态生成的,在编译前已经有了确定的目标对象
1.3 动态代理
动态代理的代理类实在程序运行过程中动态生成的。
2 JDK动态代理
2.1 demo
- 需要代理的两个接口类
StudentService
,TeacherService
public interface StudentService {
void study(String course);
}
public interface TeacherService {
void teach(String course);
}
- 代理的目标对象类
PersonServiceImpl
public class PersonServiceImpl implements StudentService,TeacherService {
@Override
public void study(String course){
System.out.println("学习:"+course);
}
@Override
public void teach(String course) {
System.out.println("授课:"+course);
}
}
- 代理类
JDKDynamicProxy
public class JDKDynamicProxy implements InvocationHandler {
/**
* 代理的目标类
*/
private Object target;
/**
* 构造方法注入目标类
*/
public JDKDynamicProxy(Object target) {
this.target = target;
}
/**
* 获取代理对象:这里面会进行一系列的操作,生产目标对象的代理对象。
*/
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
/**
* 最终通过代理对象执行方法,都会反射执行这个方法。
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
Object result = null;
try {
System.out.println(method.getName() + ":执行前");
result = method.invoke(target, args);
System.out.println(method.getName() + ":执行后");
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return result;
}
}
- 启动测试类
public class ProxyTest {
public static void main(String[] args) throws Exception {
JDKDynamicProxy jdkDynamicProxy = new JDKDynamicProxy(new PersonServiceImpl());
StudentService studentService = jdkDynamicProxy.getProxy();
TeacherService teacherService = jdkDynamicProxy.getProxy();
studentService.study("语文");
studentService.toString();
teacherService.teach("数学");
//以下代码可将动态生成的类文件存储到本地
byte[] bts = ProxyGenerator.generateProxyClass("PersonServiceImpl", UserServiceImpl.class.getInterfaces());
FileOutputStream fos = new FileOutputStream(new File("D:/PersonServiceImpl.class"));
fos.write(bts);
fos.flush();
fos.close();
}
}
- 生成的代理类
public final class PersonServiceImpl extends Proxy implements UserService {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public PersonServiceImpl(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);
}
}
public final void addUser(String var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
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("org.example.springstudy.service.UserService").getMethod("addUser", Class.forName("java.lang.String"));
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());
}
}
}
2.2 jdk动态代理实现技术及源码
从上一节的demo中,我们可以看到,jdk实现动态代理的技术如下:
- 代理接口
- 目标对象
JDKDynamicProxy
类,实现InvocationHandler
接口,持有代理对象Proxy.newProxyInstance()
会在内存中动态生成一个代理类的class文件,这个类继承了Proxy接口,实现了代理对象接口。- 代理类中的方法,都是通过
JDKDynamicProxy
的invoke
方法进行调用的(所以JDKDynamicProxy
需要实现InvocationHandler
接口)。 - 以上最关键的过程动态的生产代理类class文件及相应的代理对象,这是通过
Proxy.newProxyInstance()
方法实现的,具体如下。
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文件就比较复杂了,在此不进行详述)
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);
}
}
3.CGLIB动态代理
上面的jdk动态代理只能针对接口进行代理,那么如果接口没有实现任何接口,就不能用jdk自带的代理。这时候需要使用cglib代理。
3.1 demo
- 代理的目标类
Person1ServiceImpl
public class Person1ServiceImpl{
public void study(String course){
System.out.println("学习:"+course);
}
//注意:这里特意声明为final方法
public final void teach(String course) {
System.out.println("授课:"+course);
}
}
- 创建代理的类
CglibDynamicProxy
public class CglibDynamicProxy implements MethodInterceptor {
public <T> T getProxyInstance(Class c){
//输出class文件
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
//新建一个cglib的增强类
Enhancer enhancer = new Enhancer();
//设置父类,也就是被代理的类
enhancer.setSuperclass(c);
//设置回调,主要是最后是执行MethodInterceptor接口的intercept方法
enhancer.setCallback(this);
//在内存中创建代理类的Class文件,并通过反射创建代理对象
return (T) enhancer.create();
}
@Override
public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("方法执行前");
Object invoke = methodProxy.invokeSuper(sub, objects);
System.out.println("方法执行后");
return invoke;
}
}
- 启动类
public class ProxyTest {
public static void main(String[] args){
CglibDynamicProxy cglibDynamicProxy = new CglibDynamicProxy();
Person1ServiceImpl proxyInstance = cglibDynamicProxy.getProxyInstance(Person1ServiceImpl.class);
proxyInstance.study("111");
proxyInstance.teach("222");
}
}
- 执行结果
方法执行前
学习:111
方法执行后
授课:222
- 动态生产的代理类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.lihui.study.proxy;
import java.lang.reflect.Method;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.cglib.core.Signature;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class Person1ServiceImpl$$EnhancerByCGLIB$$64a03981 extends Person1ServiceImpl implements Factory {
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
//设置的回调接口
private MethodInterceptor CGLIB$CALLBACK_0;
//设置的过滤器
private static Object CGLIB$CALLBACK_FILTER;
//被代理的方法
private static final Method CGLIB$study$0$Method;
//代理方法
private static final MethodProxy CGLIB$study$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$equals$1$Method;
private static final MethodProxy CGLIB$equals$1$Proxy;
private static final Method CGLIB$toString$2$Method;
private static final MethodProxy CGLIB$toString$2$Proxy;
private static final Method CGLIB$hashCode$3$Method;
private static final MethodProxy CGLIB$hashCode$3$Proxy;
private static final Method CGLIB$clone$4$Method;
private static final MethodProxy CGLIB$clone$4$Proxy;
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("com.lihui.study.proxy.Person1ServiceImpl$$EnhancerByCGLIB$$64a03981");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$equals$1$Method = var10000[0];
CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
CGLIB$toString$2$Method = var10000[1];
CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
CGLIB$hashCode$3$Method = var10000[2];
CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
CGLIB$clone$4$Method = var10000[3];
CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
CGLIB$study$0$Method = ReflectUtils.findMethods(new String[]{"study", "(Ljava/lang/String;)V"}, (var1 = Class.forName("com.lihui.study.proxy.Person1ServiceImpl")).getDeclaredMethods())[0];
CGLIB$study$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)V", "study", "CGLIB$study$0");
}
final void CGLIB$study$0(String var1) {
super.study(var1);
}
public final void study(String var1) {
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$study$0$Method, new Object[]{var1}, CGLIB$study$0$Proxy);
} else {
super.study(var1);
}
}
final boolean CGLIB$equals$1(Object var1) {
return super.equals(var1);
}
public final boolean equals(Object var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
return var2 == null ? false : (Boolean)var2;
} else {
return super.equals(var1);
}
}
final String CGLIB$toString$2() {
return super.toString();
}
public final String toString() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
}
final int CGLIB$hashCode$3() {
return super.hashCode();
}
public final int hashCode() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
return var1 == null ? 0 : ((Number)var1).intValue();
} else {
return super.hashCode();
}
}
final Object CGLIB$clone$4() throws CloneNotSupportedException {
return super.clone();
}
protected final Object clone() throws CloneNotSupportedException {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
}
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$4$Proxy;
}
break;
case 581061590:
if (var10000.equals("study(Ljava/lang/String;)V")) {
return CGLIB$study$0$Proxy;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return CGLIB$equals$1$Proxy;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return CGLIB$toString$2$Proxy;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return CGLIB$hashCode$3$Proxy;
}
}
return null;
}
public Person1ServiceImpl$$EnhancerByCGLIB$$64a03981() {
CGLIB$BIND_CALLBACKS(this);
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
CGLIB$THREAD_CALLBACKS.set(var0);
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
CGLIB$STATIC_CALLBACKS = var0;
}
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
Person1ServiceImpl$$EnhancerByCGLIB$$64a03981 var1 = (Person1ServiceImpl$$EnhancerByCGLIB$$64a03981)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);
Person1ServiceImpl$$EnhancerByCGLIB$$64a03981 var10000 = new Person1ServiceImpl$$EnhancerByCGLIB$$64a03981();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Callback var1) {
CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
Person1ServiceImpl$$EnhancerByCGLIB$$64a03981 var10000 = new Person1ServiceImpl$$EnhancerByCGLIB$$64a03981();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
Person1ServiceImpl$$EnhancerByCGLIB$$64a03981 var10000 = new Person1ServiceImpl$$EnhancerByCGLIB$$64a03981;
switch(var1.length) {
case 0:
var10000.<init>();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
default:
throw new IllegalArgumentException("Constructor not found");
}
}
public Callback getCallback(int var1) {
CGLIB$BIND_CALLBACKS(this);
MethodInterceptor var10000;
switch(var1) {
case 0:
var10000 = this.CGLIB$CALLBACK_0;
break;
default:
var10000 = null;
}
return var10000;
}
public void setCallback(int var1, Callback var2) {
switch(var1) {
case 0:
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
default:
}
}
public Callback[] getCallbacks() {
CGLIB$BIND_CALLBACKS(this);
return new Callback[]{this.CGLIB$CALLBACK_0};
}
public void setCallbacks(Callback[] var1) {
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
}
static {
CGLIB$STATICHOOK1();
}
}
3.2 技术讲解
从上面的demo可以看到,生成的代理类没有对final修复的teach方法进行代理,因为生成的代理类Person1ServiceImpl$$EnhancerByCGLIB$$64a03981
继承了需要代理的类Person1ServiceImpl
(final方法是不能被继承的),实现了Factory
接口。
整个流程如下:
- 新建一个cglib的增强类:
Enhancer enhancer = new Enhancer()
- 设置代理类和回调:
enhancer.setSuperclass(c);enhancer.setCallback(this);
- 动态生成代理类的class文件及相应的代理对象:
enhancer.create()
- 通过代理类调用相应方法,比如调用
study()
方法;
public final void study(String var1) {
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$study$0$Method, new Object[]{var1}, CGLIB$study$0$Proxy);
} else {
super.study(var1);
}
}
- 如上,实际会调用之前设置的回调对象的回调方法,参数解释如下:
/**
* sub : 传入的子类对象,也就是被代理的对象
* method :被代理的方法
* objects:方法入参
* methodProxy:代理对象的代理方法
**/
public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("方法执行前");
Object invoke = methodProxy.invokeSuper(sub, objects);
System.out.println("方法执行后");
return invoke;
}
- 执行代理对象的方法:
methodProxy.invokeSuper(sub, objects)