静态代理就是B类中用A类去真正地做。
正式点说就是,手动创建代理类,实现与目标对象相同的接口,并在代理类中调用目标对象的方法,同时可以在调用前后添加额外的逻辑。
这里主要介绍动态代理,有两种常见的动态代理方式。
Spring的AOP中,如果目标对象实现了接口,则用JDK动态代理,否则采用CGLIB动态代理。
1. JDK接口动态代理
基于java.lang.reflect.Proxy类的JDK动态代理。
1.1. 做法
- 被代理的对象必须实现接口。
- 实现InvocationHandler接口来定义代理的逻辑。
1.2. 示例
//略去import
interface MyInterface {
void myMethod();
}
// 被代理的类
class MyClass implements MyInterface {
@Override
public void myMethod() {
System.out.println("called");
}
}
// 切进去
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
Object result = method.invoke(target, args);
System.out.println("after");
return result;
}
}
// 使用方法
public class JDKDynamicProxyExample {
public static void main(String[] args) {
MyClass myClass = new MyClass();
InvocationHandler handler = new MyInvocationHandler(myClass);
MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
MyInterface.class.getClassLoader(),
new Class[]{MyInterface.class},
handler);
proxy.myMethod();
}
}
2. CGLIB字节码子类动态代理
基于字节码增强技术的CGLIB动态代理。
2.1. 做法
- 可以代理没有实现接口的类。
- 通过生成被代理类的子类来实现代理。
2.2 示例
使用CGLIB动态代理通常需要引入相关的依赖,如cglib库
//略去import
class TargetClass {
public void targetMethod() {
System.out.println("called");
}
}
class CglibProxyInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before");
Object result = proxy.invokeSuper(obj, args);
System.out.println("after");
return result;
}
}
public class CglibDynamicProxyExample {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(TargetClass.class);
enhancer.setCallback(new CglibProxyInterceptor());
TargetClass proxy = (TargetClass) enhancer.create();
proxy.targetMethod();
}
}
3. 两种代理方式的区别
- JDK动态代理要求实现接口,基于反射机制,生成代理对象会快一些。
- CGLIB动态代理不需要实现接口,基于字节码生成子类,调用代理方法的性能好一些。