浅析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则无限制;

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

目录
相关文章
|
1天前
|
设计模式 中间件 Java
设计模式3:代理、适配器、装饰器模式
代理模式是一种结构型设计模式,通过中间件解耦服务提供者和使用者,使使用者间接访问服务提供者,便于封装和控制。
19 2
|
3月前
|
设计模式 消息中间件 搜索推荐
Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
【11月更文挑战第17天】观察者模式是一种行为设计模式,定义了一对多的依赖关系,使多个观察者对象能直接监听并响应某一主题对象的状态变化。本文介绍了观察者模式的基本概念、商业系统中的应用实例,如优衣库事件中各相关方的动态响应,以及模式的优势和实际系统设计中的应用建议,包括事件驱动架构和消息队列的使用。
|
3月前
|
Java
JAVA 静态代理 & 动态代理
【11月更文挑战第14天】静态代理是一种简单的代理模式实现,其中代理类和被代理类的关系在编译时已确定。代理类实现与被代理类相同的接口,并持有被代理类的实例,通过调用其方法实现功能增强。优点包括代码结构清晰,易于理解和实现;缺点是对于多个被代理类,需为每个类编写相应的代理类,导致代码量大增,维护成本高。动态代理则在运行时动态生成代理类,更加灵活,减少了代码冗余,但可能引入性能损耗和兼容性问题。
|
3月前
|
设计模式 Java 数据库连接
Java编程中的设计模式:单例模式的深度剖析
【10月更文挑战第41天】本文深入探讨了Java中广泛使用的单例设计模式,旨在通过简明扼要的语言和实际示例,帮助读者理解其核心原理和应用。文章将介绍单例模式的重要性、实现方式以及在实际应用中如何优雅地处理多线程问题。
56 4
|
3月前
|
设计模式 JavaScript Java
Java设计模式:建造者模式详解
建造者模式是一种创建型设计模式,通过将复杂对象的构建过程与表示分离,使得相同的构建过程可以创建不同的表示。本文详细介绍了建造者模式的原理、背景、应用场景及实际Demo,帮助读者更好地理解和应用这一模式。
114 0
|
4月前
|
Java Spring 数据库连接
[Java]代理模式
本文介绍了代理模式及其分类,包括静态代理和动态代理。静态代理分为面向接口和面向继承两种形式,分别通过手动创建代理类实现;动态代理则利用反射技术,在运行时动态创建代理对象,分为JDK动态代理和Cglib动态代理。文中通过具体代码示例详细讲解了各种代理模式的实现方式和应用场景。
78 0
[Java]代理模式
|
4月前
|
设计模式 Java 程序员
[Java]23种设计模式
本文介绍了设计模式的概念及其七大原则,强调了设计模式在提高代码重用性、可读性、可扩展性和可靠性方面的作用。文章还简要概述了23种设计模式,并提供了进一步学习的资源链接。
94 0
[Java]23种设计模式
|
4月前
|
Java
Java代码解释静态代理和动态代理的区别
### 静态代理与动态代理简介 **静态代理**:代理类在编译时已确定,目标对象和代理对象都实现同一接口。代理类包含对目标对象的引用,并在调用方法时添加额外操作。 **动态代理**:利用Java反射机制在运行时生成代理类,更加灵活。通过`Proxy`类和`InvocationHandler`接口实现,无需提前知道接口的具体实现细节。 示例代码展示了两种代理方式的实现,静态代理需要手动创建代理对象,而动态代理通过反射机制自动创建。
|
4月前
|
设计模式 网络协议 Java
05.静态代理设计模式
《静态代理设计模式》详细介绍了静态代理的基本概念、原理与实现、应用场景及优缺点。主要内容包括静态代理的由来、定义、使用场景、实现方式、结构图与时序图,以及其在降低耦合、保护对象权限等方面的优势。同时,文章也指出了静态代理的局限性,如缺乏灵活性、难以复用、难以动态添加功能等,并介绍了动态代理如何弥补这些不足。最后,通过多个实际案例和代码示例,帮助读者更好地理解和应用静态代理模式。
58 4
|
4月前
|
Java
Java访问外网图片地址时,如何添加代理?
【10月更文挑战第14天】Java访问外网图片地址时,如何添加代理?
95 2

热门文章

最新文章