动态代理原理和实例

动态代理

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值