动态代理
1、使用场景
- 通过代理对目标类方法进行增强;
- 使用RPC框架的时,框架本身并不能提前知道各个业务方要调用哪些接口的哪些方法 。这时,通过动态代理的方式建立一个中间人给客户端使用,方便框架搭建逻辑, 可以使客户端代码和框架解耦;
- Spring的AOP机制采用动态代理的机制来实现切面编程。
2、JDK和CGLIB动态代理的区别
- CGLIB动态代理是JDK动态代理的补充,JDK动态代理只能代理具有接口的实现类,不能代理没有接口的Java类中的方法,CGLIB既可以代理接口,亦可以代理普通JAVA类;
- JDK动态代理实现了InvocationHandler接口,CGLIB动态代理实现了MethodInterceptor方法拦截器
3、JDK动态代理
JDK动态代理接口,通过接口找到对应的实现类,如有以下接口IPrinter:
public interface IPrinter {
void print(String msg);
}
对应的实现类为:
public class PrinterImpl implements IPrinter {
@Override
public void print(String msg) {
System.out.println("XLT,"+msg);
}
}
创建代理工具类JdkProxy实现InvocationHandler接口
public class JdkProxy implements InvocationHandler {
private Object object;
public JdkProxy(Object object) {
this.object=object;
}
public <T> T getProxy(){
return (T)Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK PROXY before invoke method:"+method.getName());
Object result = method.invoke(object, args);
System.out.println("JDK PROXY after invoke method:"+method.getName());
return result;
}
}
测试代理效果:
public class TestProxy {
public static void main(String[] args) {
IPrinter printerImplProxy = new JdkProxy(new PrinterImpl()).getProxy();
printerImplProxy.print("面试通过了吗?");
}
}
运行结果:
4、CGLIB动态代理
与JDK动态代理只能代理具有接口的方法,对于普通的JAVA类的方法不能代理,CGLIB对其进行了补充,它通过字节码的技术,动态生成被代理类的子类,实现对被代理类方法的调用。CGLIB需要引入jar包:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
如, 代理如下的hi方法:
public class SayHello {
public void hi(String name) {
System.out.println("Hi,"+name);
}
}
创建代理工具类,需要实现MethodInterceptor接口
public class CgLibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz) {
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create(); //通过字节码技术创建子类实例
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("Before invoke method:"+method.getName());
Object result = methodProxy.invokeSuper(obj, args);
System.out.println("After invoke method:"+method.getName());
return result;
}
}
测试类:
public class TestProxy {
public static void main(String[] args) {
CgLibProxy cgLibProxy = new CgLibProxy();
SayHello sayHelloProxy = (SayHello)cgLibProxy.getProxy(SayHello.class);
sayHelloProxy.hi("Mark");
}
}
![image-20211112225640291](https://img-blog.csdnimg.cn/29ea3f53a0594a8bac8abf83f0d07530.png)