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

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

目录
相关文章
|
5天前
|
设计模式 算法 Java
Java一分钟之-设计模式:策略模式与模板方法
【5月更文挑战第17天】本文介绍了策略模式和模板方法模式,两种行为设计模式用于处理算法变化和代码复用。策略模式封装不同算法,允许客户独立于具体策略进行选择,但需注意选择复杂度和过度设计。模板方法模式定义算法骨架,延迟部分步骤给子类实现,但过度抽象或滥用继承可能导致问题。代码示例展示了两种模式的应用。根据场景选择合适模式,以保持代码清晰和可维护。
10 1
|
5天前
|
设计模式 Java
Java一分钟之-设计模式:装饰器模式与代理模式
【5月更文挑战第17天】本文探讨了装饰器模式和代理模式,两者都是在不改变原有对象基础上添加新功能。装饰器模式用于动态扩展对象功能,但过度使用可能导致类数量过多;代理模式用于控制对象访问,可能引入额外性能开销。文中通过 Java 代码示例展示了两种模式的实现。理解并恰当运用这些模式能提升代码的可扩展性和可维护性。
19 1
|
5天前
|
设计模式 Java
Java一分钟之-设计模式:工厂模式与抽象工厂模式
【5月更文挑战第17天】本文探讨了软件工程中的两种创建型设计模式——工厂模式和抽象工厂模式。工厂模式提供了一个创建对象的接口,延迟实例化到子类决定。过度使用或违反单一职责原则可能导致问题。代码示例展示了如何创建形状的工厂。抽象工厂模式则用于创建一系列相关对象,而不指定具体类,但添加新产品可能需修改现有工厂。代码示例展示了创建颜色和形状的工厂。根据需求选择模式,注意灵活性和耦合度。理解并恰当运用这些模式能提升代码质量。
16 2
|
7天前
|
设计模式 安全 Java
【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
|
5天前
|
设计模式 Java
Java一分钟之-设计模式:观察者模式与事件驱动
【5月更文挑战第17天】本文探讨了Java中实现组件间通信的观察者模式和事件驱动编程。观察者模式提供订阅机制,当对象状态改变时通知所有依赖对象。然而,它可能引发性能问题、循环依赖和内存泄漏。代码示例展示了如何实现和避免这些问题。事件驱动编程则响应用户输入和系统事件,但回调地狱和同步/异步混淆可能造成困扰。JavaFX事件驱动示例解释了如何处理事件。理解这两种模式有助于编写健壮的程序。
10 1
|
5天前
|
设计模式 SQL 安全
Java一分钟之-设计模式:单例模式的实现
【5月更文挑战第16天】本文介绍了单例模式的四种实现方式:饿汉式(静态初始化)、懒汉式(双检锁)、静态内部类和枚举单例,以及相关问题和解决方法。关注线程安全、反射攻击、序列化、生命周期和测试性,选择合适的实现方式以确保代码质量。了解单例模式的优缺点,谨慎使用,提升设计效率。
22 3
|
7天前
|
设计模式 Java
【JAVA基础篇教学】第十四篇:Java中设计模式
【JAVA基础篇教学】第十四篇:Java中设计模式
|
7天前
|
网络协议 算法 Java
Java中如何通过代理实现对HTTP2网站的访问?
Java中如何通过代理实现对HTTP2网站的访问?
|
7天前
|
设计模式 算法 Java
设计模式在Java开发中的应用
设计模式在Java开发中的应用
18 0
|
7天前
|
设计模式 前端开发 Java
19:Web开发模式与MVC设计模式-Java Web
19:Web开发模式与MVC设计模式-Java Web
24 4