浅析Java设计模式【2.1】——代理

简介: Java常用设计模式,代理模式

title: 浅析Java设计模式【3】——代理
date: 2019-03-30 21:11:42
categories: 设计模式

description: Java设计模式,代理

目录

Agent

1. 概念

百度百科对它的定义是:对其他对象提供一种代理以控制对这个对象的访问。

代理模式更多的是一种安全层面的考虑,保护被访问对象的安全,在访问者和被访问者之间起一种中介作用。在我们具体应用中都会遇到需要记录掌控方法的执行前后的动作。

从生成方式的不通又在代理中分为静态代理、动态代理以及Cglib代理。

2. 静态代理

代理类在程序运行前就已经定义好,其与目标类(被代理类)的关系在程序运行前就已经确立,属于事前约定的范畴。这一点非常类似于企业与企业法律顾问间的关系,他们之间的代理关系,并不是在“官司“发生后才建立的,而是之前就确立好的一种关系。在这一点上动态代理可以理解为官司已经开始,才临时聘请熟谙法律的律师。


package xyz.wongs.weathertop.design.proxy;

/**
 * @ClassName Loginable
 * @Description 定义接口
 * @author WCNGS@QQ.COM
 * @Github <a>https://github.com/rothschil</a>
 * @date 2019/12/27 15:31
 * @Version 1.0.0
*/
public interface Loginable {
    void login();
}


package xyz.wongs.weathertop.design.proxy.stat;

import lombok.extern.slf4j.Slf4j;
import xyz.wongs.weathertop.design.proxy.Loginable;

import java.util.Random;

/**
 * @ClassName LoginService
 * @Description 登陆实现类
 * @author WCNGS@QQ.COM
 * @Github <a>https://github.com/rothschil</a>
 * @date 2019/12/27 15:32
 * @Version 1.0.0
*/
@Slf4j
public class LoginService implements Loginable {

    @Override
    public void login(){
        try {
            Thread.sleep(new Random().nextInt(5000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.error("登陆成功");
    }
}

package xyz.wongs.weathertop.design.proxy.stat;

import lombok.extern.slf4j.Slf4j;
import xyz.wongs.weathertop.design.proxy.Loginable;

/**
 * @ClassName LoginServiceProxy
 * @Description 实际代理类
 * @author WCNGS@QQ.COM
 * @Github <a>https://github.com/rothschil</a>
 * @date 2019/12/27 15:32
 * @Version 1.0.0
*/
@Slf4j
public class LoginServiceProxy implements Loginable {

    private Loginable loginable;

    public LoginServiceProxy() {
    }

    public LoginServiceProxy(Loginable loginable) {
        this.loginable = loginable;
    }

    @Override
    public void login() {
        long start = System.currentTimeMillis();
        log.error("start proxy : " + start);
        loginable.login();
        long end = System.currentTimeMillis();
        log.error("end proxy : " + end);
        log.error("spend all time : " + (end - start) + " ms.");
    }
}

静态代理

上面的一个登陆例子中,我们通过代理对象来获取我们想要的目标(LoginService),外界并不知道目标是如何实现的,无形之中保护了真正的意图。

小结一下:
静态代理对象(LoginServiceProxy)有两个特征:

  • 它内部包含着被代理对象(Loginable)实现接口的引用。
  • 它又实现了被代理对象(Loginable)实现的接口。

这两个特征既是特点同时也带有劣势,就是代理的对象必须提前知晓,当被代理对象发生变更,相应的代理对象也要跟着变更,还是有点不便捷。那有没有一种手段可在运行过程中动态地产生一个代理对象,非但再也不用维护代理类,更提高整体的效率。答案是有的,这种手段就是下来的动态代理。

3. 动态代理

JAVA中的AOP切面就是基于动态代理来实现的,但是它用到了两种代理模式分别为jdk动态代理和cglib动态代理,当然这两种代理各有优劣,这一点我们在最后会统一总结。

3.1. JDK动态代理

在静态代理的模块上做一下改造,沿用接口和接口实现部分,新增一个

3.1.1. 实现

package xyz.wongs.weathertop.design.proxy.dyc.jdk;

import lombok.extern.slf4j.Slf4j;
import xyz.wongs.weathertop.design.proxy.Loginable;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

@Slf4j
public class LoginServiceDycProxy implements InvocationHandler {

    private Loginable loginable;

    public Object getInstall(Loginable loginable){
        this.loginable = loginable;
        return Proxy.newProxyInstance(loginable.getClass().getClassLoader(),loginable.getClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log.error("Begin 执行方法前的操作");

        if(method.getName().equalsIgnoreCase("login")){
            loginable.login();
        }
        log.error("End 执行方法后的操作");
        return null;
    }
}

3.1.2. 演示结果

@Test
public void testDycProxy(){
    LoginServiceDycProxy lsdp = new LoginServiceDycProxy();
    Loginable loginable = (Loginable)lsdp.getInstall(new LoginService());
    loginable.login();
}

17:48:57.793 [main] ERROR xyz.wongs.weathertop.design.proxy.dyc.jdk.LoginServiceDycProxy - Begin 执行方法前的操作
17:49:00.594 [main] ERROR xyz.wongs.weathertop.design.proxy.LoginService - 登陆成功
17:49:00.594 [main] ERROR xyz.wongs.weathertop.design.proxy.dyc.jdk.LoginServiceDycProxy - End 执行方法后的操作

3.2. cglib代理

3.2.1. 引入依赖包

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

3.2.2. 代理类

package xyz.wongs.weathertop.design.proxy.dyc.cglib;

import lombok.extern.slf4j.Slf4j;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

@Slf4j
public class LoginServiceDycProxyCglib implements MethodInterceptor {

    public Object getInstall(Object object){
        return Enhancer.create(object.getClass(), this);
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        log.error("Begin 执行方法前的操作");
        methodProxy.invokeSuper(o,objects);
        log.error("End 执行方法后的操作");
        return null;
    }
}

3.2.3. 测试


@Test
public void testDycProxyCglib(){
    LoginServiceDycProxyCglib lsdp = new LoginServiceDycProxyCglib();
    Loginable loginable = (Loginable)lsdp.getInstall(new LoginService());
    loginable.login();
}

3.2.4. 演示结果

18:00:53.993 [main] ERROR xyz.wongs.weathertop.design.proxy.dyc.cglib.LoginServiceDycProxyCglib - Begin 执行方法前的操作
18:00:57.787 [main] ERROR xyz.wongs.weathertop.design.proxy.LoginService - 登陆成功
18:00:57.787 [main] ERROR xyz.wongs.weathertop.design.proxy.dyc.cglib.LoginServiceDycProxyCglib - End 执行方法后的操作

3.3. jdk代理与cglib代理比较

  • 实现机制:jdk动态代理是由java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的;
  • 效率上:反射机制在类的生成过程中比较高效,而asm机制在类生成之后的执行过程中比较高效,当然也有可以通过将asm生成的类接入缓存,这样也可以解决asm生成类过程低效问题;
  • 应用上: jdk动态代理的应用需要依赖目标类均基于统一的接口,而cglib则无限制;

综上所述,我们在实际过程中基于第三方库实现的动态代理应用在综合效率上更有优势。

目录
相关文章
|
22天前
|
设计模式 Java API
[Java]静态代理与动态代理(基于JDK1.8)
本文介绍了代理模式及其分类,包括静态代理和动态代理。静态代理分为面向接口和面向继承两种形式,分别通过手动创建代理类实现;动态代理则利用反射技术,在运行时动态创建代理对象,分为JDK动态代理和Cglib动态代理。文中通过具体代码示例详细讲解了各种代理模式的实现方式和应用场景。
17 0
[Java]静态代理与动态代理(基于JDK1.8)
|
22天前
|
设计模式 Java 程序员
[Java]23种设计模式
本文介绍了设计模式的概念及其七大原则,强调了设计模式在提高代码重用性、可读性、可扩展性和可靠性方面的作用。文章还简要概述了23种设计模式,并提供了进一步学习的资源链接。
36 0
[Java]23种设计模式
|
28天前
|
设计模式 网络协议 Java
05.静态代理设计模式
《静态代理设计模式》详细介绍了静态代理的基本概念、原理与实现、应用场景及优缺点。主要内容包括静态代理的由来、定义、使用场景、实现方式、结构图与时序图,以及其在降低耦合、保护对象权限等方面的优势。同时,文章也指出了静态代理的局限性,如缺乏灵活性、难以复用、难以动态添加功能等,并介绍了动态代理如何弥补这些不足。最后,通过多个实际案例和代码示例,帮助读者更好地理解和应用静态代理模式。
33 4
|
29天前
|
Java
Java访问外网图片地址时,如何添加代理?
【10月更文挑战第14天】Java访问外网图片地址时,如何添加代理?
22 2
|
6天前
|
设计模式 JavaScript Java
Java设计模式:建造者模式详解
建造者模式是一种创建型设计模式,通过将复杂对象的构建过程与表示分离,使得相同的构建过程可以创建不同的表示。本文详细介绍了建造者模式的原理、背景、应用场景及实际Demo,帮助读者更好地理解和应用这一模式。
|
1月前
|
设计模式 监控 算法
Java设计模式梳理:行为型模式(策略,观察者等)
本文详细介绍了Java设计模式中的行为型模式,包括策略模式、观察者模式、责任链模式、模板方法模式和状态模式。通过具体示例代码,深入浅出地讲解了每种模式的应用场景与实现方式。例如,策略模式通过定义一系列算法让客户端在运行时选择所需算法;观察者模式则让多个观察者对象同时监听某一个主题对象,实现松耦合的消息传递机制。此外,还探讨了这些模式与实际开发中的联系,帮助读者更好地理解和应用设计模式,提升代码质量。
Java设计模式梳理:行为型模式(策略,观察者等)
|
25天前
|
Java
Java代码解释静态代理和动态代理的区别
### 静态代理与动态代理简介 **静态代理**:代理类在编译时已确定,目标对象和代理对象都实现同一接口。代理类包含对目标对象的引用,并在调用方法时添加额外操作。 **动态代理**:利用Java反射机制在运行时生成代理类,更加灵活。通过`Proxy`类和`InvocationHandler`接口实现,无需提前知道接口的具体实现细节。 示例代码展示了两种代理方式的实现,静态代理需要手动创建代理对象,而动态代理通过反射机制自动创建。
|
2月前
|
存储 设计模式 安全
Java设计模式-备忘录模式(23)
Java设计模式-备忘录模式(23)
|
2月前
|
设计模式 存储 算法
Java设计模式-命令模式(16)
Java设计模式-命令模式(16)
|
2月前
|
设计模式 存储 缓存
Java设计模式 - 解释器模式(24)
Java设计模式 - 解释器模式(24)

热门文章

最新文章

  • 1
    C++一分钟之-设计模式:工厂模式与抽象工厂
    42
  • 2
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    46
  • 3
    C++一分钟之-C++中的设计模式:单例模式
    54
  • 4
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    38
  • 5
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    62
  • 6
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    57
  • 7
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    41
  • 8
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    50
  • 9
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    106
  • 10
    Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
    78