Jdk 动态代理
Jdk动态代理,利用反射,实现 InvocationHandler 接口。Jdk 动态代理需要实现类通过接口定义业务方法,也就是说,委托类必须实现一个定义了业务方法的接口,在接口里约定需要代理的方法,并且只能对接口里约定的方法实现代理。由于需要委托类实现一个接口,这是一个局限性。
- Subject 类
public interface Subject {
void doSomething();
}
- RealSubject 类
public class RealSubject implements Subject {
@Override
public void doSomething() {
System.out.println("do something");
}
}
- Jdk 代理
public class JdkProxy implements InvocationHandler {
private Object target;
public JdkProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
System.out.println("jdk proxy before");
result = method.invoke(target, args);
System.out.println("jdk proxy after");
return result;
}
}
- Jdk 代理测试
public class JdkProxyTest {
@Test
public void testJdkProxy() {
RealSubject realSubject = new RealSubject();
Subject subject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), new JdkProxy(realSubject));
subject.doSomething();
}
}
运行结果:
jdk proxy before
do something
jdk proxy after
Cglib 动态代理
Cglib 代理是针对类来实现代理的,并不要求委托类必须实现接口,它的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,采用的是继承的方式。由于是采用继承的方式,所以用 Cglib 实现的代理类是不能处理被final关键字修饰的方法的。
- Cglib 代理
public class CglibProxy implements MethodInterceptor {
public Object getInstance(Class clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object result;
System.out.println("cglib proxy before");
result = methodProxy.invokeSuper(o, objects);
System.out.println("cglib proxy after");
return result;
}
}
在上文中可以看到,代理对象的生成过程是由 Enhancer 类来实现的,大概步骤是:
- 生成代理类 Class 的二进制字节码;
- 通过 Class.forName 加载二进制字节码,生成Class对象;
- 通过反射机制获取实例构造,并初始化代理类对象。
intercept() 方法拦截目标类方法的调用,o 表示目标类的实例,method 为目标类方法的反射对象,objects 为方法的动态入参,methodProxy 为代理类实例。
- Cglib 代理测试
public class CglibProxyTest {
@Test
public void testCglibProxy() {
RealSubject realSubject = (RealSubject) new CglibProxy().getInstance(RealSubject.class);
realSubject.doSomething();
}
}
运行结果:
cglib proxy before
do something
cglib proxy after