设为首页 加入收藏

TOP

动态代理与责任链模式(一)
2023-07-25 21:36:27 】 浏览:47
Tags:任链模

  动态代理和责任链设计模式适用范围广,在Spring和MyBatis有着重要的应用,比如SpringAOP、Mybatis的插件技术,想要搞懂当中的技术原理必须掌握上面两个设计模式。

    代理模式可以理解为您要操作一个对象,但是要经过这个对象的“代理”对象去操作。就好似你在一家软件公司做开发,客户发现程序有Bug,会找到商务对接人说,最后商务的同事再找到你去解决问题。“商务”是代理对象,“你”是真实对象。代理模式分为静态代理和动态代理,其作用是可以在真实对象访问之前或者之后加入自定义的逻辑,又或者根据自定义规则来控制是否使用真实对象。

    静态代理是真实对象与代理对象(Proxy)实现相同的接口,代理对象包含真实对象的引用,客户端通过代理对象去访问真实对象,代理对象可以在真实对象访问之前或之后执行其他操作。假设要你设计一个对外开放的商品库存信息查询接口,并且要限制调用方在一天时间内的调用次数。用代理模式代理库存接口,首先在库存查询前检查用户是否有权限访问,然后在查询后要记录用户查询日志,以便根据查询次数,判断调用上限。

 

 

    动态代理是在程序运行时,通过反射机制创建代理对象,实现动态代理方法。动态代理相比于静态代理的好处,是代理对象不用实现真实对象的接口,这样能代理更多方法。因为静态代理是一个接口对应一个类型,如果接口添加新方法,则所有代理类都要实现此方法,所以动态代理脱离了接口实现,一个代理类就能代理更多方法。一些公共代码逻辑也就可以在多个代理方法里复用,例如:数据库事务开启、提交、回滚,这些公共代码都分别是在真实方法调用的前后出现,而动态代理会帮我们把功能代码织入到方法里。在Java中最常用动态代理有两种,一种是JDK动态代理,这是JDK自带的功能;另一种是CGLIB,由第三方提供的一个技术,Spring是用了JDK代理和CGLIB两种,两者的区别是,JDK代理要提供接口作为于代理参数才能使用,而CGLIB不需要提供接口,只要一个非抽象类就能代理,适用于一些不能提供接口的场景。

1. JDK动态代理

  (1)定义真实对象接口,因为JDK动态代理要借助接口才能代理对象

public interface SayService {
    void sayHello();
}

public class SayServiceImpl implements SayService {
    @override
    public void sayHello() {
        System.out.println("Hello Friend");    
    }
}

  (2)创建代理类,实现java.lang.reflect.InvocationHandler接口

public class JdkProxyExample implements InvocationHandler {
    // 真实对象
    private Object target = null;

    public Object bind(Object target) {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理前");
        System.out.println("调用真实对象");
        Object r = method.invoke(target, args);
        System.out.println("代理后");
        return r;
    }
}

      Proxy.newProxyInstance方法的作用是创建代理对象,并建立代理对象与真实对象的关系。包含3个参数

    • 第1个是类加载器,用于把Java字节码转换成Class类实例对象,这里用了target对象所属的类加载器

    • 第2个是生成的动态代理对象需要挂载到哪些接口下,上面是取了真实对象的接口

    • 第3个是实现InvocationHandler接口的代理类,this表示当前对象

 

      InvocationHandler接口的invoke方法实现代理逻辑,invoke其中参数含义如下

    • proxy:代理对象,就是bind方法生成的对象

    • method:当前调用方法,method.invoke(target, args)调用真实对象方法

    • args:当前调用方法参数

  (3)测试JDK动态代理

public void testJdk() {
    JdkProxyExample jdkProxy = new JdkProxyExample();
    SayService proxy = (SayService) jdkProxy.bind(new SayServiceImpl());
    proxy.sayHello();
}

/*
代理前
调用真实对象
Hello Friend
代理后
*/

 

2. CGLIB动态代理

    JDK动态代理要提供接口才能代理,但在一些不能提供接口的场景下,CGLIB动态代理技术不需要提供接口,只要一个非抽象类就能动态代理。新建类实现MethodInterceptor接口(spring框架的cglib包),使用Enhacer创建代理对象。代码实现如下:

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class CglibProxyExample implements MethodInterceptor {
    public Object bind(Class classz) {
        Enhancer enhancer = new Enhancer();
        enhancer.setCallback(this);
        enhancer.setSuperclass(classz);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("调用真实对象前");
        Object r
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Quartz使用监听器插入定时任务执.. 下一篇JDK中内嵌JS引擎介绍及使用

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目