java静态代理和动态代理

简介: java静态代理和动态代理

什么是代理模式?

给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。 通俗的来讲代理模式就是我们生活中常见的中介。

当我们想要去租房的时候,可能会通过某中介公司去代理商(中介),通过中介去找到我们心仪的房子。此场景就涉及了3个角色: 真实角色-房主(房屋的真正拥有者)、代理角色(房屋中介等代理商)、接口或抽象类(抽象角色-包含了真实角色和代理角色共同维护的方法- 租房)。


代理商是给房屋的主人做代理的,因此在编写代理模式代码的时候要注意:代理角色要包含对原对象的引用。

Java中的代理分为几种?

可以分为静态代理动态代理两种。

静态代理

静态代理是指给每个真实的角色都指定一个代理角色,之后就可以通过这个代理角色来操作真实角色的。之所以称为静态代理,是因为所有的代理关系都是固定写死的。就像一个房东只对应一个租房代理中介,一个车主,对应一个租车代理商。


下面以静态代理“租房“”为例,演示静态代理的具体实现。


租房接口:(抽象角色)

/**
 * @PackageName: com.proxy.demo
 * @author: youjp
 * @create: 2020-10-17 16:06
 * @description: 租房接口(包含了真实角色和代理角色共同维护的方法)
 * @Version: 1.0
 */
public interface Subject {
    /**
     * 租房
     * @param money
     * @return
     */
    public abstract boolean rent(int money);
}

房主(真实角色)

/**
 * @PackageName: com.proxy.demo
 * @author: youjp
 * @create: 2020-10-17 16:09
 * @description: 房主(房屋真实拥有者)
 * @Version: 1.0
 */
public class RealSubject implements Subject {
    @Override
    public boolean rent(int money) {
        System.out.println("租房"+money+"钱");
        return true;
    }
}

中介(代理角色)

/**
 * @PackageName: com.proxy.demo
 * @author: youjp
 * @create: 2020-10-17 16:11
 * @description: 中介(代理角色)
 * @Version: 1.0
 */
public class StaticProxy implements Subject {
    //含有对象的真实引用
    private RealSubject subject;
    public void before(){
        System.out.println("----before租房前,需要找中介,-----");
    }
    public void after(){
        System.out.println("---after房子满意以后,付了款-------");
    }
    public StaticProxy(){
        subject=new RealSubject();
    }
    @Override
    public boolean rent(int money) {
        //
        this.before();
        System.out.println("---中介替替房东出租房");
        //调用真实角色的租房方法
        subject.rent(money);
        this.after();
        return true;
    }
}

测试类

/**
 * @PackageName: com.proxy.demo
 * @author: youjp
 * @create: 2020-10-17 16:53
 * @description: 测试静态代理
 * @Version: 1.0
 */
public class TestStaticProxy {
    public static void main(String[] args) {
        StaticProxy staticProxy= new StaticProxy();
        //调用代理角色的方法
        staticProxy.rent(2000);
    }
}

运行结果:

20200401134307494.png

使用静态代理的好处:

可以发现静态代理的实现方式比较简单,使得真实角色处理的业务更加纯粹,不再去关注一些公共的事情。公共的业务由代理来完成—实现业务的分工。公共业务发生扩展时变得更加集中和方便。


使用静态代理的缺点

如果有多个真实角色,比如:租车、相亲等。就得编写多个代理商对象与之关联。就会增加程序代码量,也不会便于后期的维护。

动态代理

动态代理静态代理中,真实角色和代理角色是“一对一”的关系,而在动态代理中,真实角色和代理角色是“多对一”的关系。动态代理可以使用一个“万能”的代理者来代理任何类型的“真实角色”,这也是动态代理相比静态代理的优势所在。


思考一个问题,静态代理需要实现和真实角色相同的接口。列如:房屋中介和真正的房主都需要“出租房”,因此出租房就是二者共同要实现的接口。但是,动态代理既然是万能代理,那么应该实现什么样的接口呢?例如,房屋的主人和汽车的主人,都需要动态代理,那么这个动态代理是应该实现房屋的接口还是出租车的接口呢~~


为此,JDK中提供了一个万能的动态接口“InvocationHandler”.即使用动态代理时,实现InvocationHandler接口就行。该接口中的 invoke() 方法就是万能的代理方法。


下面,还是以出租房为例,来实现动态代理出租。


租房接口:(抽象角色)

/**
 * @PackageName: com.proxy.demo
 * @author: youjp
 * @create: 2020-10-20 16:06
 * @description: 租房接口(包含了真实角色和代理角色共同维护的方法)
 * @Version: 1.0
 */
public interface Subject {
    /**
     * 租房
     * @param money
     * @return
     */
    public abstract boolean rent(int money);
}

房主(真实角色)

/**
 * @PackageName: com.proxy.demo
 * @author: youjp
 * @create: 2020-10-20 16:09
 * @description: 房主(房屋真实拥有者)
 * @Version: 1.0
 */
public class RealSubject implements Subject {
    @Override
    public boolean rent(int money) {
        System.out.println("租房"+money+"钱");
        return true;
    }
}

代理角色

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * @PackageName: com.proxy.demo
 * @author: youjp
 * @create: 2020-10-17 17:14
 * @description: TODO 动态代理(中介)可以代理任意类型的角色
 * @Version: 1.0
 */
public class DynamicProxy implements InvocationHandler {
    private Object object;
    public DynamicProxy(Object obj){
        this.object=obj;
    }
    public void before(){
        System.out.println("----before---------");
    }
    public void after(){
        System.out.println("---after-----------");
    }
    /**
     *
     * @param proxy 代理的角色
     * @param method 被代理的方法
     * @param args 方法的参数
     * @return 真正被代理的方法rent()的返回值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        this.before();
        /**
         * 以出租房为例,动态代理想要执行的rent()方法,必须调用真实的角色的rent();
         * 动态代理使用 了反射技术,通过method.invoke(object,args),实现了对真实角色的rent()调用。
         * 从代码上看,未发现rent()任何相关的代码,所以实现了万能代理
         */
        Object result=method.invoke(object,args);
        this.after();
        return result;
    }
}

测试类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
 * @PackageName: com.proxy.demo
 * @author: youjp
 * @create: 2020-10-17 17:28
 * @description:
 * @Version: 1.0
 */
public class TestDynamicProxy {
    public static void main(String[] args) {
        //真实对象:房东
        Subject realSubject=new RealSubject();
        //初步的代理对象:handle就是realSubject的初步代理对象
        InvocationHandler handler=new DynamicProxy(realSubject);
        /**
         *  newProxyInstance(a,b,c)
         *  a:初步代理对象的类加载器(固定写法)
         *  b:接口类型的数组。要代理的方法是在哪些接口中定义的,即realSubject的接口
         *  c:要将哪个初步的代理对象转换为最终的代理对象
         *  subjectProxy :最终的代理对象
         */
        Subject subjectProxy=(Subject) Proxy.newProxyInstance(
               handler.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(),
                handler
        );
        //获取到
       boolean result= subjectProxy.rent(2000);
        System.out.println(result?"ok":"error");
        System.out.println(subjectProxy.getClass().getName());
    }
}

运行结果;

20200401134307494.png

可以发现,动态代理就是通过Proxy.newProxyInstance(),创建一个万能的代理对象,因为该万能对象中拥有真实对象的 接口,因此就知道需要代理的对象类型,知道要代理的方法是什么。


有兴趣的老爷,可以关注我的公众号【一起收破烂】,回复【006】获取2021最新java面试资料以及简历模型120套哦~


相关文章
|
13天前
|
设计模式 Java API
[Java]静态代理与动态代理(基于JDK1.8)
本文介绍了代理模式及其分类,包括静态代理和动态代理。静态代理分为面向接口和面向继承两种形式,分别通过手动创建代理类实现;动态代理则利用反射技术,在运行时动态创建代理对象,分为JDK动态代理和Cglib动态代理。文中通过具体代码示例详细讲解了各种代理模式的实现方式和应用场景。
14 0
[Java]静态代理与动态代理(基于JDK1.8)
|
20天前
|
Java
Java访问外网图片地址时,如何添加代理?
【10月更文挑战第14天】Java访问外网图片地址时,如何添加代理?
20 2
|
28天前
|
Java
深入理解Java动态代理
深入理解Java动态代理
19 1
|
16天前
|
Java
Java代码解释静态代理和动态代理的区别
### 静态代理与动态代理简介 **静态代理**:代理类在编译时已确定,目标对象和代理对象都实现同一接口。代理类包含对目标对象的引用,并在调用方法时添加额外操作。 **动态代理**:利用Java反射机制在运行时生成代理类,更加灵活。通过`Proxy`类和`InvocationHandler`接口实现,无需提前知道接口的具体实现细节。 示例代码展示了两种代理方式的实现,静态代理需要手动创建代理对象,而动态代理通过反射机制自动创建。
|
27天前
|
设计模式 缓存 Java
从源码学习Java动态代理|8月更文挑战
从源码学习Java动态代理|8月更文挑战
|
3月前
|
开发者 C# 容器
【独家揭秘】当WPF邂逅DirectX:看这两个技术如何联手打造令人惊艳的高性能图形渲染体验,从环境搭建到代码实践,一步步教你成为图形编程高手
【8月更文挑战第31天】本文通过代码示例详细介绍了如何在WPF应用中集成DirectX以实现高性能图形渲染。首先创建WPF项目并使用SharpDX作为桥梁,然后在XAML中定义承载DirectX内容的容器。接着,通过C#代码初始化DirectX环境,设置渲染逻辑,并在WPF窗口中绘制图形。此方法适用于从简单2D到复杂3D场景的各种图形处理需求,为WPF开发者提供了高性能图形渲染的技术支持和实践指导。
189 0
|
3月前
|
设计模式 Java C++
揭秘!JDK动态代理VS CGLIB:一场关于Java代理界的‘宫心计’,你站哪队?
【8月更文挑战第24天】Java 动态代理是一种设计模式,允许在不改动原类的基础上通过代理类扩展功能。主要实现方式包括 JDK 动态代理和 CGLIB。前者基于接口,利用反射机制在运行时创建代理类;后者采用继承方式并通过字节码技术生成子类实现类的代理。两者在实现机制、性能及适用场景上有明显差异。JDK 动态代理适用于有接口的场景,而 CGLIB 更适合代理未实现接口的类,尽管性能更优但存在一些限制。开发者可根据需求选择合适的代理方式。
162 0
【Java入门提高篇】Day10 Java代理——静态代理
  今天要介绍的是一个Java中一个很重要的概念——代理。   什么是代理?联系生活想想看,代理似乎并不陌生,最形象的代表便是经纪人,明星一般都有经纪人,经纪人作为中间人,负责代理明星的相关事宜,比如说,有人要请明星去唱歌表演,一般不会直接跟明星联系,而是联系他的经纪人,他的经纪人来负责安排行程,而真正唱歌表演的还是明星本人,经纪人仅仅作为一个附加物存在。
946 0
|
8天前
|
安全 Java
java 中 i++ 到底是否线程安全?
本文通过实例探讨了 `i++` 在多线程环境下的线程安全性问题。首先,使用 100 个线程分别执行 10000 次 `i++` 操作,发现最终结果小于预期的 1000000,证明 `i++` 是线程不安全的。接着,介绍了两种解决方法:使用 `synchronized` 关键字加锁和使用 `AtomicInteger` 类。其中,`AtomicInteger` 通过 `CAS` 操作实现了高效的线程安全。最后,通过分析字节码和源码,解释了 `i++` 为何线程不安全以及 `AtomicInteger` 如何保证线程安全。
java 中 i++ 到底是否线程安全?
|
3天前
|
存储 设计模式 分布式计算
Java中的多线程编程:并发与并行的深度解析####
在当今软件开发领域,多线程编程已成为提升应用性能、响应速度及资源利用率的关键手段之一。本文将深入探讨Java平台上的多线程机制,从基础概念到高级应用,全面解析并发与并行编程的核心理念、实现方式及其在实际项目中的应用策略。不同于常规摘要的简洁概述,本文旨在通过详尽的技术剖析,为读者构建一个系统化的多线程知识框架,辅以生动实例,让抽象概念具体化,复杂问题简单化。 ####