前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java中代理模式的一点理解

Java中代理模式的一点理解

作者头像
猫老师的叶同学
发布2023-03-01 13:53:12
2840
发布2023-03-01 13:53:12
举报
文章被收录于专栏:中间件的探究中间件的探究

Java中代理模式的一点理解

1、什么是代理模式?

代理模式中可主要分为客户端、代理类、目标类这三种角色。

  • 客户端:发起请求方。
  • 目标类:特定行为的实现类,也就是真正工作的人
  • 代理类:可以调用目标类的所有功能,并可以在此基础上扩展额外的工作。通过在代理类内部持有目标类的对象来实现代理功能。

以租房为例:

  • 客户端:租客
  • 目标类:房东
  • 代理类:中介。中介不仅代理出租目标房东的房子,还会处理其他工作。
2、代理模式有哪些?

代理模式有分为两类。

  • 静态代理:顾名思义,关键字静态,代理关系一目了然。在编译之前就了然的代理关系。
  • 动态代理:既然了静态代理,为什么还需要动态代理呢?当有多个代理关系时,代码就会凸显代码的冗余。因此使用动态代理,一不变应万变,没错,就是,只需要一个动态代理类,就可以实现多了个代理关系。
    • jdk动态代理:基于接口实现,在创建代理对象时,需要指定生成代理类实现的接口。
    • cglib动态代理:基于继承实现,即使目标类没有实现接口也可以正常生成代理对象。
3、代理模式的作用?

代理的作用就是不改变目标类的情况下,对目标类进行增强。细品后发现和Spring的Aop有些相似,是的,Spring利用了动态代理实现了Aop的强大功能。

4、实操体会一下

下面通过三个简单的代理实现代码,进一步理解代理模式在Java中的基本实现。

4.1、静态代理

静态代理直接将目标对象targeti通过构造方法传递进去,构建出来了代理对象staticProxy。

如下代码:

代码语言:javascript
复制
/**
 * 目标类接口
 */
public interface HelloService {
    public String sayHello(String msg);
}


/**
 * 目标类实现类
 */
public class HelloServiceImpl implements HelloService{
    public String sayHello(String msg){
        System.out.println("你好呀!!");
        return "HelloServiceImpl:  " + msg;
    }
}

/**
 * 代理类
 */
public class StaticProxy implements HelloService {

    /**
     * 目标对象
     */
    private HelloService target;

    public StaticProxy(HelloService target){
        this.target = target;
    }

    @Override
    public String sayHello(String msg){
        // 1、增强逻辑,记录入参
        System.out.println("方法名称:  sayHello, 入参:  " + msg);

        // 2、使用放射调用目标对象方法
        String result = target.sayHello(msg);

        // 3、增强逻辑,记录出参
        System.out.println("方法名称:  sayHello, 返回值:  " + result);
        return result;
    }
}

/**
 * 调用代理类实现目标类的功能
 */ 
public class StaticTest{
    
    public static void main(String args[]){
        HelloService helloService = new HelloServiceImpl();
        // 1、静态代理
        HelloService staticProxy = new StaticProxy(helloService);
        String result = staticProxy.sayHello("静态代理");
        System.out.println("MainTest==静态代理:  " + result);
    }
}
/**
 *  方法名称:  sayHello, 入参:  静态代理
    你好呀!!
    方法名称:  sayHello, 返回值:  HelloServiceImpl:  静态代理
    MainTest==静态代理:  HelloServiceImpl:  静态代理
 */
4.2、jdk动态代理

jdk动态代理是先将目标对象targeti通过构造方法传递进去,然后通过getProxy()方法完成了代理的创建,最后将代理对象强转为了接口类型HelloService,由于jdk动态代理是基于接口实现的,生成的代理类会实现这个HelloService接口,所以是可以这样强转的。

如下代码:

代码语言:javascript
复制
/**
 * jdk动态代理
 */
public class JdkDynamicProxy implements InvocationHandler {

    /**
     * 目标对象
     */
    private Object target;

    public JdkDynamicProxy(Object target){
        this.target = target;
    }

    /**
     * 获取目标对象的代理
     * @return 返回代理对象
     */
    public Object getProxy(){
        // 创建代理对象
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),  // 指定当前目标对象使用类加载器
                target.getClass().getInterfaces(),   // 目标对象实现的接口和类型
                this                                 // 设置回调顺序
        );
    }

    /**
     * 对目标对象的方法进行增强
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 1、增强逻辑,记录入参
        System.out.println("方法名称:  " + method.getName() + ", 入参:  " + Arrays.toString(args));

        // 2、使用放射调用目标对象方法
        Object result = method.invoke(target, args);

        // 3、增强逻辑,记录出参
        System.out.println("方法名称:  " + method.getName() + ", 返回值:  " + result);
        return result;
    }
}

/**
 * 调用代理类实现目标类的功能
 */ 
public class JdkTest{
    
    public static void main(String args[]){
        HelloService helloService = new HelloServiceImpl();
        HelloService jdkProxy = (HelloService) new JdkDynamicProxy(helloService).getProxy();
        String result = jdkProxy.sayHello("jdk动态代理");
        System.out.println("MainTest==jdk动态代理:  " + result);
        System.out.println("====================================");
    }
}
/*
    方法名称:  sayHello, 入参:  [jdk动态代理]
    你好呀!!
    方法名称:  sayHello, 返回值:  HelloServiceImpl:  jdk动态代理
    MainTest==jdk动态代理:  HelloServiceImpl:  jdk动态代理
 */
4.3、cglib动态代理

cglib动态代理是先将目标对象targeti通过构造方法传递进去,然后通过getProxy0方法完成了代理的创建,只不过这里是将代理对象强转为了HelloServicelmpl类型,因为cglib:是基于继承来的,生成的代理类本质是HelloServicelmpl类的子类,所以这里是可以强转为HelloServicelmpl类型的。

如下代码:

代码语言:javascript
复制
/**
 * Cglib动态代理
 */
public class CglibDynamicProxy implements MethodInterceptor {

    /**
     * 目标对象
     */
    private Object target;

    public CglibDynamicProxy(Object target){
        this.target = target;
    }

    /**
     * 获取目标对象的代理
     * @return 返回代理对象
     */
    public Object getProxy(){
        // 字节码增强器, 可以为没有实现接口的类创建代理
        Enhancer enhancer = new Enhancer();
        // 因为Cglib的原理是动态生成要代理类的子类,然后子类重写父类方法,因此设置代理类的父类类型
        enhancer.setSuperclass(target.getClass());
        // 设置回调方法
        enhancer.setCallback(this);
        // 创建代理对象
        return enhancer.create();
    }

    /**
     * 对目标对象的方法进行增强
     */
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 1、增强逻辑,记录入参
        System.out.println("方法名称:  " + method.getName() + ", 入参:  " + Arrays.toString(args));

        // 2、使用放射调用目标对象方法
        Object result = methodProxy.invoke(target, args);

        // 3、增强逻辑,记录出参
        System.out.println("方法名称:  " + method.getName() + ", 返回值:  " + result);
        return result;
    }
}


/**
 * 调用代理类实现目标类的功能
 */ 
public class JdkTest{
    
    public static void main(String args[]){
        HelloServiceImpl cglibProxy = (HelloServiceImpl) new CglibDynamicProxy(new HelloServiceImpl()).getProxy();
        String result = cglibProxy.sayHello("cglib动态代理");
        System.out.println("MainTest==cglib动态代理:  " + result);
        System.out.println("====================================");
    }
}
/*
    方法名称:  sayHello, 入参:  [cglib动态代理]
    你好呀!!
    方法名称:  sayHello, 返回值:  HelloServiceImpl:  cglib动态代理
    MainTest==cglib动态代理:  HelloServiceImpl:  cglib动态代理
 */
5、总结

1、代理模式分为两大类,分别是静态代理和动态代理,而动态代理又分为jdk动态代理和cglib动态代理。

2、单一实现可以使用静态代理,多个目标类需要被代理则需要使用动态代理模式,实现接口使用jdk动态代理,否则使用cglib动态代理。

3、动态代理是Spring中AOP实现的基础。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-10-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java中代理模式的一点理解
    • 1、什么是代理模式?
      • 2、代理模式有哪些?
        • 3、代理模式的作用?
          • 4、实操体会一下
            • 5、总结
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档