Spring的静态代理和动态代理

简介: Spring的静态代理和动态代理文章目录一、前言二、分类2.1、静态代理2.2、动态代理2.2.1、分类2.2.2、对比三、实现3.1 静态代理3.1 动态代理3.1.1基于jdk的动态代理3.1.2基于cglib的动态代理四、结语一、前言        开始接触代理是在设计模式动态代理中了解的,大概是这样的:张三喜欢一个女孩,但是她不敢表白怎么办,很简单,他找李四帮他去表白。

Spring的静态代理和动态代理
文章目录
一、前言
二、分类
2.1、静态代理
2.2、动态代理
2.2.1、分类
2.2.2、对比
三、实现
3.1 静态代理
3.1 动态代理
3.1.1基于jdk的动态代理
3.1.2基于cglib的动态代理
四、结语
一、前言
        开始接触代理是在设计模式动态代理中了解的,大概是这样的:张三喜欢一个女孩,但是她不敢表白怎么办,很简单,他找李四帮他去表白。这里李四就是代理对象,代替张三干活,可以看下面的画面:

        慢慢积累之后,发现很多经典的框架背后都使用了代理的模式,例如Spring的AOP实现原理便是动态代理;常用的ORM模型中mybatis框架实现原理也是动态代理;事务的实现原理反射+动态代理;dubbo的实现中也有动态代理…很多很多,我们可以得出的结论是熟悉代理以及熟悉动态代理的重要性。代理模式是:通过代理控制对目标对象的访问,下面是代理类图,我们先对代理有个整体认识。

二、分类
       代理分为静态代理和动态代理,他们的区别是静态代理有真实的代理类存在,就是我们会代码中创建一个代理类,并在代理类的方法中调用目标对象的方法,以此来完成代理的工作。动态代理的代理类没有在代码中创建一个代理类,而是在运行时在JVM里面创建代理对象。

2.1、静态代理
       我们知道静态代理是有实实在在的代理类存在,并且和目标类实现相同的接口。他的特点是效率高,因为所有的类都是已经编写完成的,客户端只需要取得代理对象并且执行即可,同时他可以实现对目标对象中指定的方法进行增强。但是他也有如下缺点:

与目标类实现相同的接口代码冗余
如果接口发生改变,代理类中的方法也要修改
代理类服务于一种类型的对象,如果要服务多类型的对象,那么势必要为每种类型的对象都生成代理类
2.2、动态代理
       与静态代理的硬编码方式相比,动态代理支持运行时动态生成代理对象这种方式。动态代理能用很少的代码对一个类的所有方法实现一样的增强效果,但是不能增强其中的某一个方法,他的好处很明显,在编码时代理逻辑与业务逻辑互相独立,各不影响,减少侵入,降低耦合。

2.2.1、分类
       动态代理可以分为两种,一种是基于JDk的动态代理一种是基于CGLIB的动态代理。在spring中使用他们的区别是:当目标对象有实现接口时,默认使用jdk动态代理的方式,当目标类没有实现接口时使用cglib的动态代理方式,并且代理对象以目标对象为父类。

2.2.2、对比
       

jdk cglib
依赖 基于spring,不需要引用 需要引用第三方类库
方式 有实现的接口,常见是mybatis的mapper文件是代理 没有,原理目标对象作为父类
对targetObject要求 实现接口 不能用final修饰
生成对象的技术 反射,使用了动态生成字节码技术 使用字节码技术,使用了动态生成字节码技术
三、实现
       没有代码的讲理论等于耍流氓,下面分享一下我在实践中的code,同时进行适当的补充。

3.1 静态代理
       有代理类,实实在在的存在代理类,是动态代理的理论基础,这里有一个work接口,接口中有一个唱歌的方法,我们想通过访问经纪人(代理对象)来达到让明星(目标对象)唱歌的方法。

//接口
public interface Work {

void sing();

}

//目标对象
public class TargetObj implements Work {

@Override
public void sing() {
    System.out.println("明星在唱歌");;
}

}

//代理对象
public class ProxyObj implements Work {

Work obj=null;
public ProxyObj() {
    obj=new TargetObj();
}

@Override
public void sing() {
    System.out.println("先到经济人");
    obj.sing();
}

}

3.1 动态代理
3.1.1基于jdk的动态代理
//接口
public interface Work {

void sing();

}

//目标对象
public class TargetObj implements Work {

@Override
public void sing() {
    System.out.println("明星在唱歌");;
}

}

public class MainTest {

//JDK方式发的动态代理
public static void main(String[] args) {
    //1.创建真实的对象
    Work targetObj=new TargetObj();
    //2.创建代理对象
    Work proxyObj = (Work) Proxy.newProxyInstance( 
            targetObj.getClass().getClassLoader(),//真实类使用什么类加载器
            targetObj.getClass().getInterfaces(),//真实实现的接口
            new InvocationHandler() { //调用处理器
                /**
                 * 处理器的方法
                 * @param proxy 参数一:代理对象,一般不会使用
                 * @param method 参数二:外面的代理对象调用的方法引用,代理对象.sing(),method便是sing这个方法的引用
                 * @param args 参数三:外面的代理对象调用的方法里面的参数。代理对象.sing(“参数"),args就是“参数”
                 * @return
                 * @throws Throwable
                 */
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //反射调用
                    return method.invoke(targetObj,args);//方法的返回参数
                }
            }
    );
    //3让代理工作
    proxyObj.sing("北冰洋");
}

}

       从代码中我们可以get到两点

基于jdk的动态代理需要有实现的接口
动态代理的核心:是创建了处理器 InvocationHandler实例
在调用目标对象时,会调用代理对象,代理对象中请求目标对象,invoke方法便是调用目标对象的方法生成代理对象的过程,同时增强工作也是在invoke方法中进行的。
3.1.2基于cglib的动态代理

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

public class TargetObj2 {

public String sing(String args) {
    System.out.println("明星在唱歌");
    return args;
}
public void dance() {
    System.out.println("明星在跳舞");
}

}

public class MainTest {

public static void main(String[] args) {
    //1.真实对象
    TargetObj2 targetObj2=new TargetObj2();
    //2.创建代理对象
    Enhancer enhancer=new Enhancer();
    enhancer.setSuperclass(targetObj2.getClass());
    enhancer.setCallback(new MethodInterceptor() {
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            //增强功能
            System.out.println("123");
            return method.invoke(targetObj2,objects);
        }
    });
    //创建代理
    TargetObj2 proxyObj = (TargetObj2) enhancer.create();
    //让代理工作
    String ret= proxyObj.sing("丁香花");
    System.out.println(ret);
}

}

       从cglib中我们可以get到两点

基于cglib的动态代理是没有实现接口的,他是以目标类作为代理类的父类
cglib动态代理的关键是基于enhancer.setCallback方法,和其中的MethodInterceptor() 方法
在MethodInterceptor实例中重写intercept方法中调用invoke方法设置代理对象,最后通过enhancer.create()创建代理对象。
四、结语
       理论知识会比较空洞和抽象,但是实践一下我们会有不一样的收获。

       感谢您宝贵的阅读时间。

作者:Viola_tt
来源:CSDN
原文:https://blog.csdn.net/SweetyoYY/article/details/90743578
版权声明:本文为博主原创文章,转载请附上博文链接!

相关文章
|
3月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
21天前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
28 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
21天前
|
Java 数据安全/隐私保护 Spring
Spring进阶:初识动态代理
本文介绍了Spring框架中AOP切面编程的基础——动态代理。通过定义Vehicle接口及其实现类Car和Ship,展示了如何使用动态代理在不修改原代码的基础上增强功能。文章详细解释了动态代理的工作原理,包括通过`Proxy.newProxyInstance()`方法创建代理对象,以及`InvocationHandler`接口中的`invoke()`方法如何处理代理对象的方法调用。最后,通过一个测试类`TestVehicle`演示了动态代理的具体应用。
|
2月前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
|
2月前
|
设计模式 Java Spring
spring源码设计模式分析-代理设计模式(二)
spring源码设计模式分析-代理设计模式(二)
|
3月前
|
缓存 安全 Java
Spring AOP 中两种代理类型的限制
【8月更文挑战第22天】
27 0
|
3月前
|
Java Spring
|
3月前
|
安全 Java 开发者
|
3月前
|
安全 Java 测试技术
Spring Security 中的委托过滤器代理
【8月更文挑战第21天】
35 0
|
4月前
|
缓存 安全 Java
Spring高手之路21——深入剖析Spring AOP代理对象的创建
本文详细介绍了Spring AOP代理对象的创建过程,分为三个核心步骤:判断是否增强、匹配增强器和创建代理对象。通过源码分析和时序图展示,深入剖析了Spring AOP的工作原理,帮助读者全面理解Spring AOP代理对象的生成机制及其实现细节。
46 0
Spring高手之路21——深入剖析Spring AOP代理对象的创建