文章目录
- 1、简介
- 2、静态代理
- 3、动态代理
- 3.1 JDK动态代理实现
- 3.2 CGLIB动态代理实现
- 4、动态代理原理
1、简介
代理模式23种Java常用设计模式之一。代理模式的定义:对其他对象提供一种代理以控制对这个对象的访问。
代理模式(Proxy)是通过代理对象访问目标对象,这样可以在目标对象基础上增强额外的功能,如添加权限,访问控制和审计等功能。
2、静态代理
(1)接口类
public interface IUserService {
void add();
}
(2)实现类
public class UserService implements IUserService {
public void add() {
System.out.println("add");
}
}
(3)代理类
public class UserServiceProxy implements IUserService {
private IUserService userService;
public UserServiceProxy(IUserService userService) {
this.userService = userService;
}
@Override
public void add() {
System.out.println("do something before");
this.userService.add();
System.out.println("do something after");
}
}
(4)启动类
public static void main(String[] args) {
IUserService userService = new UserService();
UserServiceProxy proxy = new UserServiceProxy(userService);
proxy.add();
}
3、动态代理
静态代理中一个代理只能代理一种类型,而且是在编译器编译前就已经确定被代理的对象。而动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象。
原理:在运行时期,构建需要被代理类的代理对象,这个代理对象可以针对不同的被代理类组装成不同的内容,因此可以对各种对象进行代理,这种方式是通过Java的反射机制实现的。
实现动态代理的两种方案:
- JDK动态代理:内置在JDK中,不需要引入第三方jar,使用简单,但功能比较弱。
- CGLIB动态代理:使用第三方CGLIB库,总体性能比JDK动态代理好,且功能强大。
3.1 JDK动态代理实现
(1)接口类
public interface IUserService {
void add();
}
(2)实现类
public class UserService implements IUserService {
public void add() {
System.out.println("add");
}
}
(3)代理类
public class SDKDynamicProxy implements InvocationHandler {
private Object object;
public SDKDynamicProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("do something before");
Object invoke = method.invoke(object, args);
System.out.println("do something after");
return invoke;
}
}
(4)启动类
public static <T> T getProxy(Class<T> clazz, T obj) {
SDKDynamicProxy proxy = new SDKDynamicProxy(obj);
return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[]{clazz}, proxy);
}
public static void main(String[] args) {
IUserService userService = getProxy(IUserService.class, new UserService());
userService.add();
}
3.2 CGLIB动态代理实现
(1)添加依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
(2)接口类
public interface IUserService {
void add();
}
(3)实现类
public class UserService implements IUserService {
public void add() {
System.out.println("add");
}
}
(4)代理类
public class CglibDynamicProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("do something before " + method.getName());
Object invoke = methodProxy.invokeSuper(o, objects);
System.out.println("do something after " + method.getName());
return invoke;
}
}
(5)启动类
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new CglibDynamicProxy());
UserService userService = (UserService) enhancer.create();
userService.add();
}
4、动态代理原理
从上面的例子可以看到动态代理对象是在运行过程中创建的:
Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[]{clazz}, proxy);
Proxy.newProxyInstance方法中会先创建代理类:
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
再用反射机制创建代理类的对象:
final Constructor<?> cons = cl.getConstructor(constructorParams); // cl为代理类
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});
我们可以看看代理类具体的实现,先获取代理类的字节码:
private static void generateProxyClass() {
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", UserService.class.getInterfaces());
String path = "/path/to/Proxy.class";
try (FileOutputStream fos = new FileOutputStream(path)) {
fos.write(classFile);
fos.flush();
} catch (Exception e) {
System.out.println("写文件错误");
}
}
得到字节码后反编译出实现代码:
public final class $Proxy0 extends Proxy implements IUserService {
private static Method m1;
private static Method m2;
private static Method m3;
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);
}
}
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 void add() throws {
try {
super.h.invoke(this, m3, (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"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.example.aop.service.IUserService").getMethod("add");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
我们可以看到代理类实现了被代理类的接口,所以外部可以直接将代理类对象转化为接口对象来使用,调用代理对象的方法时,执行的是构造参数InvocationHandler的invoke方法:
public final void add() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
以上是JDK动态代理的实现原理,Cglib动态代理的情况类似。