【Java代理】【静态代理】【动态代理】【动态代理的2种方式】

简介: 【Java代理】【静态代理】【动态代理】【动态代理的2种方式】

正文


简介讲述代理的一些知识点【Java代理】【静态代理】【动态代理】【动态代理的2种方式】


一、代理模式#


代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。

这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法。

举个例子来说明代理的作用:假设我们想邀请一位明星,那么并不是直接连接明星,而是联系明星的经纪人,来达到同样的目的.明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)来解决。这就是代理思想在现实中的一个例子。

代理模式的关键点是:代理对象与目标对象.代理对象是对目标对象的扩展,并会调用目标对象。


二、代理的分类#


  • 静态代理
  • 动态代理


三、静态代理#


静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。

我们一起看一下静态代理的例子:

1.定义一个接口


/**
 * @author :breakpoint/赵立刚
 * @date : 2020/04/29
 */
public interface SayHelloInterface {
    void sayHello(String name);
}


2.定义实现类


/**
 * @author :breakpoint/赵立刚
 * @date : 2020/04/29
 */
public class SayHelloInterfaceImpl implements SayHelloInterface {
    @Override
    public void sayHello(String name) {
        System.out.println("hello:" + name);
    }
}


3.定义我们的代理类


/**
 * @author :breakpoint/赵立刚
 * @date : 2020/04/29
 */
public class SayHelloProxy implements SayHelloInterface {
    private SayHelloInterface target;
    public SayHelloProxy(SayHelloInterface target) {
        this.target = target;
    }
    @Override
    public void sayHello(String name) {
        System.out.println("pre code");
        target.sayHello(name);
        System.out.println("after code");
    }
}


4.定义测试类


/**
 * @author :breakpoint/赵立刚
 * @date : 2020/04/29
 */
public class Main {
    public static void main(String[] args) {
        SayHelloInterface sayHelloInterface=new SayHelloInterfaceImpl();
        SayHelloProxy proxy=new SayHelloProxy(sayHelloInterface);
        proxy.sayHello("zhaoligang");
    }
}


5.运行结果


pre code
hello:zhaoligang
after code
Process finished with exit code 0


静态代理总结:

  • 1.可以做到在不修改目标对象的功能前提下,对目标功能扩展.
  • 2.缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多。同时,一旦接口增加方法,目标对象与代理对象都要维护。

如何解决静态代理中的缺点呢?答案是可以使用动态代理方式。


四、动态代理#


动态代理有以下特点:

  • 1.代理对象,不需要实现接口
  • 2.代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)
  • 3.动态代理也叫做:JDK代理,接口代理

JDK中生成代理对象的API

  • 代理类所在包:java.lang.reflect.Proxy
  • JDK实现代理只需要使用newProxyInstance方法,但是该方法需要接收三个参数,完整的写法是:

看一下我们动态代理的例子:

1.接口也是使用的我们前面的接口:


public interface SayHelloInterface {
    void sayHello(String name);
}


2.定义我们的实现类


/**
 * @author :breakpoint/赵立刚
 * @date : 2020/04/29
 */
public class SayHelloInterfaceImpl implements SayHelloInterface {
    @Override
    public void sayHello(String name) {
        System.out.println("hello:" + name);
    }
}


  1. 定义 SayHelloProxyHandler


/**
 * @author :breakpoint/赵立刚
 * @date : 2020/04/29
 */
public class SayHelloProxyHandler  implements InvocationHandler{
    private Object target;
    public SayHelloProxyHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("pre Code");
        Object returnValue =method.invoke(target,args);
        System.out.println("after Code");
        return returnValue;
    }
}


4.测试


/**
 * @author :breakpoint/赵立刚
 * @date : 2020/04/29
 */
public class Main {
    public static void main(String[] args) {
//        SayHelloInterface sayHelloInterface=new SayHelloInterfaceImpl();
//
//        SayHelloProxy proxy=new SayHelloProxy(sayHelloInterface);
//
//        proxy.sayHello("zhaoligang");
        SayHelloInterface sayHelloInterface=new SayHelloInterfaceImpl();
        SayHelloProxyHandler sayHelloProxyHandler=new SayHelloProxyHandler(sayHelloInterface);
        SayHelloInterface sayhello=(SayHelloInterface)Proxy.newProxyInstance(sayHelloInterface.getClass().getClassLoader(),
                sayHelloInterface.getClass().getInterfaces(),sayHelloProxyHandler);
        sayhello.sayHello("zhaoligang");
    }
}


5.运行结果


pre Code
hello:zhaoligang
after Code
Process finished with exit code 0


最后的效果是一样的。

具体有如下四步骤:

  • 通过实现 InvocationHandler 接口创建自己的调用处理器;
  • 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
  • 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
  • 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

五、Spring的2种代理方式#


spring容器在创建我们的对象以及注入,使用的是动态代理实现的,怎么看呢?我们看下图:


22.jpg


根据上面的图,我们很明显的看到,Spring容器给我们的对象是代理对象

spring 里面一共有2种代理方式:

  • JDK代理
  • GClib代理方式


5.1 JDK代理#


情况与上面的相似

看一下handler


23.jpg



final class JdkDynamicAopProxy implements AopProxy,
 InvocationHandler, Serializable {


5.2 GCLIB代理#


  • cglib(Code Generation Library )是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。
  • cglib封装了asm,可以在运行期动态生成新的class。
  • cglib用于AOP,jdk中的proxy必须基于接口,cglib却没有这个限制。


5.3 他们之间的区别#


  • 原理区别

java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

  • 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
  • 如果目标对象实现了接口,可以强制使用CGLIB实现AOP
  • 如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

如何强制使用CGLIB实现AOP?

1.添加CGLIB库,SPRING_HOME/cglib/*.jar

2.在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>

JDK动态代理和CGLIB字节码生成的区别?

  • JDK动态代理只能对实现了接口的类生成代理,而不能针对类
  • CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
  • 因为是继承,所以该类或方法最好不要声明成final
相关文章
|
18小时前
|
数据采集 Java 数据安全/隐私保护
使用Java进行网络采集:代理IP与参数传递详解
Java参数传递是按值传递,包括对象引用的值。当传递对象时,方法内部修改对象内容会影响原始对象,但不能改变原始引用。示例展示了如何在爬虫代理中使用此机制,通过`ProxySettings`类传递代理信息,方法内可访问但不能更改原始对象。理解这一机制对编写高效无错的Java代码至关重要。
使用Java进行网络采集:代理IP与参数传递详解
SpringJDK动态代理实现,2024Java面试真题精选干货整理
SpringJDK动态代理实现,2024Java面试真题精选干货整理
|
21天前
|
网络协议 算法 Java
Java中如何通过代理实现对HTTP2网站的访问?
Java中如何通过代理实现对HTTP2网站的访问?
|
21天前
|
Java API 开发者
解密Java反射机制与动态代理
解密Java反射机制与动态代理
19 0
|
21天前
|
设计模式 Java 测试技术
滚雪球学Java(25):动态代理
【4月更文挑战第14天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
14 0
滚雪球学Java(25):动态代理
|
21天前
|
监控 Java 数据安全/隐私保护
Java中的动态代理
Java中的动态代理
|
21天前
|
设计模式 缓存 算法
Java 的静态代理和动态代理
Java 的静态代理和动态代理
12 0
|
21天前
|
设计模式 Java 索引
由反射引出的Java动态代理与静态代理
由反射引出的Java动态代理与静态代理
16 0
|
Java
domino中lotusscprit调用java代理
 Dim sess As New NotesSession Dim db As NotesDatabase Dim agent As NotesAgent Dim doc As NotesDocument  Set db = sess.
890 0
|
5天前
|
Java 开发者 UED
掌握Java多线程编程:从基础到高级
【5月更文挑战第31天】本文深入探讨了Java多线程编程的核心概念,包括线程的创建、生命周期、同步机制以及高级并发工具。通过实际示例和代码片段,读者将学会如何有效地管理和协调线程,以编写高效且稳定的并发应用程序。