Proxy与CGLib代理:深入解析与应用
### Proxy与CGLib代理:深入解析与应用
在软件开发中,代理模式是一种常见的设计模式,通过代理对象控制对目标对象的访问,增强目标对象的功能。在Java开发中,Proxy和CGLib是两种常用的代理实现方式,它们在应用场景、实现原理以及性能表现上各有特色。本文将深入解析Proxy和CGLib代理的原理,并通过示例展示它们在实际开发中的应用。
#### Proxy代理
Proxy代理基于Java的反射机制,通过动态生成代理类实现对目标对象的代理。Proxy代理要求目标对象必须实现至少一个接口,代理类将实现与目标对象相同的接口,并在方法调用时通过反射机制调用目标对象的方法。
**实现步骤**:
1. 定义一个接口,并创建目标对象实现该接口。
2. 创建一个实现了`InvocationHandler`接口的代理类,在`invoke`方法中编写代理逻辑。
3. 使用`Proxy.newProxyInstance`方法生成代理对象,并将目标对象和代理类传递给该方法。
**示例**:
```java
public interface IUserDao {
void save();
void delete();
}
public class UserDao implements IUserDao {
public void save() {
System.out.println("====save");
}
public void delete() {
System.out.println("====delete");
}
}
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method " + method.getName() + " invoke");
Object result = method.invoke(target, args);
System.out.println("After method " + method.getName() + " invoke");
return result;
}
}
);
}
}
public class Client {
public static void main(String[] args) {
IUserDao target = new UserDao();
IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
proxy.save();
proxy.delete();
}
}
```
**优点**:
- 代理对象与目标对象实现了相同的接口,易于扩展和维护。
- 可以在不修改目标对象代码的情况下,增加额外的功能。
**缺点**:
- 目标对象必须实现接口,无法代理没有接口的类。
- 反射机制会增加一定的性能开销。
#### CGLib代理
CGLib(Code Generation Library)是一个高性能的代码生成库,可以在运行时生成Java类的字节码。CGLib代理通过生成目标类的子类来实现代理功能,因此不需要目标对象实现接口。
**实现步骤**:
1. 创建一个目标类。
2. 创建一个实现了`MethodInterceptor`接口的代理类,在`intercept`方法中编写代理逻辑。
3. 使用CGLib的`Enhancer`类生成代理对象,并将目标对象和代理类传递给`Enhancer`类。
**示例**:
```java
public class TargetClass {
public void doSomething() {
System.out.println("Doing something...");
}
}
public class MyInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method " + method.getName() + " invoke");
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method " + method.getName() + " invoke");
return result;
}
}
public class CGLibProxy {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(TargetClass.class);
enhancer.setCallback(new MyInterceptor());
TargetClass proxy = (TargetClass) enhancer.create();
proxy.doSomething();
}
}
```
**优点**:
- 可以代理没有接口的类,更加灵活。
- 性能相对较高,因为直接调用子类的方法,减少了反射的开销。
**缺点**:
- 无法代理final类和方法,因为CGLib是通过继承实现代理的。
- 生成的子类字节码较大,可能会影响加载和运行时性能。
#### 应用场景
- **Proxy代理**:适用于目标对象实现了接口的场景,如Spring框架中的AOP(面向切面编程)实现。
- **CGLib代理**:适用于目标对象没有实现接口的场景,如需要对类的方法进行增强或监控。