设计模式之代理设计模式

一 设计模式概念及分类

设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。简单来说,方便我们编程的设计模式。设计模式共有23种。分为三类:创建型模式、结构型模式和行为型模式。代理设计模式是一种结构型模式。简化我们对结构的设计。

二 代理设计模式概念理解:

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不能或者不想直接引用一个对象,此时可以通过一个“代理”的第三者来实现间接引用。代理对象可以在客户端和目标对象中间起到中介的作业。并通过代理对象对目标对象原有功能增强或减弱。

代理模式角色代理类目标类代理类和目标类的公共接口

三 代理设计模式场景使用

1.当目标对象需要受到保护时,可以采用代理设计模式

2.当目标对象的目标方法需要进行功能增强时,可以采用代理设计模式

3.当多个目标对象无法直接交互时,可以才去代理设计模式

四 代理模式之动态代理

在程序运行阶段,在内存中动态生成代理类,被称为动态代理。目的为了减少代理类的数量,提高代码复用

a 动态代理之JDK动态代理

JDK动态代理只能代理接口,无法代理类,示例如下。以下代码对方法消耗时长进行统计为增强目的。

目标接口有俩个方法,登录登出

/**
 * 目标接口
 */
public interface userService {

    void userLogin(String uName , String password) ;

    void userLoginOut() ;

}

 目标接口实现类:

public class userServiceImpl implements userService {


    /***
     * 目标方法
     * @param uName
     * @param password
     */
    @Override
    public void userLogin(String uName, String password) {

        if ("admin".equals(uName) && "132465".equals(password)){
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("用户名密码正确,即将跳转首页.....");
        }
    }

    /***
     * 目标方法
     */
    @Override
    public void userLoginOut() {
        System.out.println("即将退出登录...");
    }
}

 假设我们需要目标类进行userServiceImpl功能增强,则需要去创建此类的代理类来帮助我们增强原有类功能。

import java.lang.reflect.Proxy;

public class client {


    /***
     * JDK动态代理例子
     * @param args
     *Proxy.newProxyInstance()三个参数讲解:
     * ClassLoader loader    要求代理对象的类加载器与目标对象的类加载器必须一致。
     * Class<?>[] interfaces 目标类和代理类要实现的同一个接口或同一些接口。
     * InvocationHandler h   调用处理器,是一个接口。实现增强的接口。编写增强代码增强程序
     */
    public static void main(String[] args) {

        //目标对象
        userService target = new userServiceImpl() ;

        //返回目标对象的代理对象
        userService o = (userService)Proxy.newProxyInstance(target.getClass().getClassLoader(),
                                                            target.getClass().getInterfaces(),
                                                            new TimerInvocationHandler(target));

        o.userLogin("admin","132465");

    }

}

 再进行Proxy.newProxyInstance创建时第三个参数为调用处理器,编写TimerInvocationHandler(统计消耗时长处理器)去实现InvocationHandler接口。实现接口必须实现接口中的invoke方法。invoke方法不由我们编写程序者调用,由Jdk后台自动调用。

/**
 * 负责计时的调用处理器
 */
public class TimerInvocationHandler implements InvocationHandler {

    private Object target ;

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

    /***
     *强制实现invoke的目的就是为了在实现的方法里实现增强的步骤。
     *invoke方法并不会在Proxy.newProxyInstance时被执行,而是在代理对象调用目标方法时,             invoke才会被调用。
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("jdk" + "已调用invoke...");

        //前置增强
        long begin = System.currentTimeMillis();

        //调用目标对象的目标方法
        //调用方法四要素:哪个对象,哪个方法,传什么参数,返回什么东西
        
        //Object 返回值 = 目标方法.invoke(目标对象,参数);
        Object retValue = method.invoke(target,args);

        //后置增强
        long last = System.currentTimeMillis();


        System.out.println("耗时:"+(last-begin)+"毫秒");
        return retValue ;
    }
}

 如果不在触发器中的invoke方法中调用Object retValue = method.invoke(target,args); 那么我们在客户端调用代理对象生成的方法(o.userLogin("admin","132465");)程序也不会调用我们的目标方法,只会执行我们的增强invoke方法。

执行结果:

b 动态代理之cglib动态代理

与上JDK动态代理方案例相同

引入依赖:        

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>

 客户端API

    @Test
    public void cglibTest(String[] args){

        //创建字节码增强器对象
        //这个对象是cglib库当中的核心对象,就是依靠他来生成代理类.
        Enhancer enhancer = new Enhancer();

        //指定cjlib的父类是谁?
        enhancer.setSuperclass(userService.class);

        //设置回调(等同于JDK动态代理当中的调用处理器(IncocationHandler))
        //在cglib当中不是IncocationHandler接口,是方法拦截器接口,MethodInterceptor
        enhancer.setCallback(new TimerInvocationHandlerCGLIB());

        //创建代理对象
        userService proxy = (userService) enhancer.create();

        //调用代理对象的代理方法.
        proxy.userLogin("admin","123");
    }

 处理器编写,增强接口

/**
 * CGLIB负责计时的调用处理器
 */
public class TimerInvocationHandlerCGLIB implements MethodInterceptor {


    @Override
    public Object intercept(Object target, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //前置增强
        long before = System.currentTimeMillis();

        Object retValue = methodProxy.invokeSuper(target, objects);
        //后置增强
        long last = System.currentTimeMillis();

        System.out.println("耗时:"+(last-before)+"毫秒");
        return retValue;
    }
}

五 二者区别:

第一来源:JDK动态代理:有原生JavaJdk提供支持。而cglib动态代理需要额外提供依赖。

第二代理形式:JDK动态代理只能去代理接口。而cglib接口和类都支持。注意, CGLIB 是通过继承的方式做的动态代理,因此如果某个 类被标记为 final ,那么它是无法使用 CGLIB 做动态代理的。

学习笔记,如上诉表达有误区,请指导

  • 11
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

if else

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值