Java动态代理
一、动态代理
Java动态代理是指在运行时动态创建一个代理对象,这个代理对象可以实现一个或多个接口,并将方法调用分派给一个或多个委托对象来处理。使用这种机制可以在不修改源码的情况下对现有的类或接口进行功能扩展或增强。它可以用于实现各种功能,如远程调用、事务管理、性能监控等。
在Java中,动态代理通常使用java.lang.reflect包中的Proxy类和InvocationHandler接口来实现。InvocationHandler是一个接口,它定义了代理对象需要实现的方法,用于在代理对象上调用方法时执行额外的逻辑。Proxy类提供了一个静态方法newProxyInstance()来生成代理对象;这个代理对象实现了我们需要代理的接口并将所有方法调用都委托给了InvocationHandler实现类中的invoke()方法。
Java动态代理主要有两种类型:JDK动态代理和CGLIB动态代理。JDK的动态代理只能用于目标对象的类实现了某个接口的情况;而CGLIB动态代理既可以为实现了接口的类做代理,也可以为没有实现接口的类做代理。
二、JDK动态代理
1、简介
动态代理允许某个具有一个方法的类为具有任意数量方法的任意类的多个方法调用提供服务。动态代理可以被认为是一种Facade,但它可以伪装成任何接口的实现。
2、样例一
代理Map:
- InvocationHandler实现类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicInvocationHandler implements InvocationHandler{
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Invoked method: " + method.getName());
System.out.print("parameter: " );
for(Object arg : args){
System.out.print(arg + " ");
}
System.out.println();
return "ok";
}
}
- 测试类
import java.lang.reflect.Proxy;
import java.util.Map;
public class DynamicProxyTest {
public static void main(String[] args) {
Class<?>[] interfaces = new Class[]{Map.class};
DynamicInvocationHandler handler = new DynamicInvocationHandler();
Map<String, String> mapProxy = (Map<String, String>) Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(), interfaces, handler);
String ret = mapProxy.put("hello", "world");
System.out.println(ret);
}
}
输出:
Invoked method: put
parameter: hello world
ok
3、样例二
实现在任意接口列表的对象上调用方法之前和之后打印日志:
- InvocationHandler实现类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DebugHandler implements InvocationHandler{
private Object originalObj;
private DebugHandler(Object originalObj) {
this.originalObj = originalObj;
}
public static Object newProxyInstance(Object obj){
DebugHandler handler = new DebugHandler(obj);
Class<?>[] interfaces = obj.getClass().getInterfaces();
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), interfaces, handler);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try{
System.out.println("before method: " + method.getName());
result = method.invoke(originalObj, args);
}catch(Exception e){
System.out.println("invocation exception: " + e.getMessage());
throw e;
}finally{
System.out.println("after method: " + method.getName());
}
return result;
}
}
- 接口(测试)
public interface Foo {
Object bar(String name);
}
- 实现类(测试)
public class FooImpl implements Foo{
@Override
public Object bar(String name) {
return "hello world, hi " + name;
}
}
- 测试类
Foo proxy = (Foo) DebugHandler.newProxyInstance(new FooImpl());
Object ret = proxy.bar("albert");
System.out.println(ret);
输出:
before method: bar
after method: bar
hello world, hi albert
三、Cglib动态代理
1、简介
cglib(Code Generation Library)是一个强大的、高性能、高质量的代码生成类库。它封装了ASM(字节码操控框架),可以在运行期动态生成新的class来扩展类或实现接口。与proxy必须基于接口不同,它可以为没有实现接口的类创建代理。
cglib被许多AOP框架使用(例如Spring AOP和dynaop)来提供方法的拦截。它广泛应用于需要动态生成代理对象的场景,例如在测试过程中,通过生成代理对象来模拟对象的行为,从而实现对代码的单元测试。
2、安装
添加Maven依赖:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.4</version>
</dependency>
3、样例
使用cglib实现代理;要代理的MyService类如下:
public class MyService {
public String getGreetings(String name){
return "Hello " + name;
}
public int getNameLength(String name){
return name.length();
}
}
- FixedValue
使用FixedValue返回代理方法的固定值:
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyService.class);
enhancer.setCallback(new FixedValue() {
@Override
public Object loadObject() throws Exception {
return "Hello albert!";
}
});
MyService proxy = (MyService) enhancer.create();
String ret = proxy.getGreetings(null);
System.out.println(ret);
输出:
Hello albert!
- MethodInterceptor
可以使用MethodInterceptor接口来拦截对代理的所有调用,并决定是要特殊处理还是执行父类方法:
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyService.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if (method.getDeclaringClass() != Object.class && method.getReturnType() == String.class) {
//类中自定义的返回String类型的方法
return "Hello albert!";
} else {
//其他方法
return proxy.invokeSuper(obj, args);
}
}
});
MyService proxy = (MyService) enhancer.create();
String ret = proxy.getGreetings(null);
System.out.println(ret);
int len = proxy.getNameLength("tom");
System.out.println(len);
输出:
Hello albert!
3
- BeanGenerator
BeanGenerator可以动态地创建Bean并使用setter和getter方法添加字段。代码生成工具可以使用它来生成简单的POJO对象。
BeanGenerator generator = new BeanGenerator();
generator.addProperty("name", String.class);
generator.addProperty("age", int.class);
//动态生成对象
Object myBean = generator.create();
try {
Class<?> beanClass = myBean.getClass();
//设置属性值
Method nameSetter = beanClass.getMethod("setName", String.class);
nameSetter.invoke(myBean, "Scott");
Method ageSetter = beanClass.getMethod("setAge", int.class);
ageSetter.invoke(myBean, 30);
//获取属性值
Method nameGetter = beanClass.getMethod("getName");
System.out.println(nameGetter.invoke(myBean));
Method ageGetter = beanClass.getMethod("getAge");
System.out.println(ageGetter.invoke(myBean));
} catch (Exception e) {
e.printStackTrace();
}
输出:
Scott
30
- Mixin
使用Mixin可以将多个对象组合为一个,需要注意的是mixin中包含的所有对象都必须由接口支持。
IFlying接口:
public interface IFlying {
void fly();
}
ISwimmable接口:
public interface ISwimmable {
void swim();
}
Bird类:
public class Bird implements IFlying{
@Override
public void fly() {
System.out.println("I can fly.");
}
}
Fish类:
public class Fish implements ISwimmable{
@Override
public void swim() {
System.out.println("I can swim.");
}
}
MixinInterface接口:
public interface MixinInterface extends IFlying, ISwimmable{
}
测试类:
Bird bird = new Bird();
Fish fish = new Fish();
MixinInterface mixin = (MixinInterface) Mixin.create(
new Class[]{IFlying.class, ISwimmable.class, MixinInterface.class},
new Object[]{bird, fish}
);
//在 mixin上调用方法将调用bird和fish的实现
mixin.fly();
mixin.swim();
输出:
I can fly.
I can swim.