前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >面试官:说说Java中有哪些代理?

面试官:说说Java中有哪些代理?

作者头像
崩天的勾玉
发布2021-12-20 17:37:19
3390
发布2021-12-20 17:37:19
举报
文章被收录于专栏:崩天的勾玉崩天的勾玉
代理类相当于是原本的类的class对象+自定义操作,理解为一层封装。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。

假如一个班的同学要向老师交班费,但是都是通过班长把自己的钱转交给老师。这里,班长就是代理学生上交班费,班长就是学生的代理。

静态代理

由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。

流程:

  1. 定义一个接口,定义了一个抽象方法。
  2. 被代理类实现了接口,重写了方法。
  3. 代理类也实现接口,然后将被代理类引用,并通过构造方法引入,然后重写方法,此时可以调用被代理类的方法
  4. main方法new了被代理类和代理类两个对象,前者作为参数传给后者,并调用后者的方法。

缺点:每个被代理类都要写一个针对的代理类。

动态代理

代理类在程序运行时创建的代理方式被成为动态代理。动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法

若目标对象实现了接口,spring默认使用「JDK的动态代理」

  • 优点:因为有接口,所以使系统更加松耦合;
  • 缺点:为每一个目标类创建接口;

若目标对象没有实现任何接口,spring使用「CGLib动态代理」

  • 优点:因为代理类与目标类是继承关系,所以不需要有接口的存在。
  • 缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。

「1、jdk动态代理」

newProxyInstance()会返回一个实现了指定接口的代理对象,对该对象的所有方法调用都会转发给InvocationHandler.invoke()方法。理解上述代码需要对Java反射机制有一定了解。动态代理神奇的地方就是:

  1. 代理对象是在程序运行时产生的,而不是编译期;
  2. 对代理对象的所有接口方法调用都会转发到InvocationHandler.invoke()方法,在invoke()方法里我们可以加入任何逻辑,比如修改方法参数,加入日志功能、安全检查功能等;之后我们通过某种方式执行真正的方法体,可以通过反射调用对象的相应方法,还可以通过RPC调用远程方法。

使用方法:代理类实现「InvocationHandler」,然后引用被代理类,并在构造方法里传入。然后重写invoke方法,为具体操作代码。然后通过

代码语言:javascript
复制
Proxy.newProxyInstance(  getClass().getClassLoader(), new Class<?>[] {Hello.class}, // 2. 代理需要实现的接口,可以有多个  
new LogInvocationHandler(new HelloImp()));// 3. 方法调用的实际处理者

Java动态代理是基于接口的,没有实现接口该类无法使用JDK代理,CGLIB登场。

「2、CGLIB动态代理」

CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法去技术拦截所有的父类方法的调用,并顺势织入横切逻辑。

目标对象:

代码语言:javascript
复制
//目标对象RealSubject,cglib不需要定义目标类的统一接口
public class RealSubject {

    public void request() {
        System.out.println("real subject execute request");
    }

    public void hello() {
        System.out.println("hello");
    }
}

代理对象:实现MethodInterceptor,重写intercept方法。

代码语言:javascript
复制
//代理对象
public class DemoMethodInterceptor implements MethodInterceptor{
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("before in cglib");
        Object result = null;
        try{
            result = proxy.invokeSuper(obj, args);
        }catch (Exception e){
            System.out.println("get ex:"+e.getMessage());
            throw e;
        }finally {
            System.out.println("after in cglib");
        }
        return result;
    }
}

客户端调用:

代码语言:javascript
复制
//客户端
public class Client {
    public static void main(String[] args){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RealSubject.class);
        enhancer.setCallback(new DemoMethodInterceptor());
        // 此刻,realSubject不是单纯的目标类,而是增强过的目标类  
        RealSubject realSubject = (RealSubject) enhancer.create();
        realSubject.hello();
        realSubject.request()
    }
}

也可以通过匿名的方式:

代码语言:javascript
复制

 public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(SampleClass.class);
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                System.out.println("before method run...");
                Object result = proxy.invokeSuper(obj, args);
                System.out.println("after method run...");
                return result;
            }
        });
        SampleClass sample = (SampleClass) enhancer.create();
        sample.test();
    }

代理的原理可以参考:https://www.cnblogs.com/gonjan-blog/p/6685611.html

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-11-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 崩天的勾玉 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 静态代理
  • 动态代理
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档