Spring的静态代理与动态代理[通俗易懂]

Spring的静态代理与动态代理[通俗易懂]简述AOP是可以横向扩展功能的,能够在不修改原来代码的前提下实现功能扩展,AOP的实现原理即是动态代理+反射。为什么要使用代理1.什么是代理  代理即是将被代理对象进一步封装后,隐藏被代理对象,在不修改被代理对象代码的前提下完成一些额外的处理。2.场景描述  有一个BookService类,其中有一个add方法,现在想在执行hello方法之前打印一句话,例如是打印”…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

强烈推荐一个大神的人工智能的教程:http://www.captainbed.net/zhanghan

简述

AOP是可以横向扩展功能的,能够在不修改原来代码的前提下实现功能扩展,AOP的实现原理即是动态代理,下文一步步优化介绍一下几种代理方式

为什么要使用代理

##1.什么是代理   代理即是将被代理对象进一步封装后,隐藏被代理对象,在不修改被代理对象代码的前提下完成一些额外的处理。 ##2.场景描述   有一个BookService类,其中有一个add方法,现在想在执行hello方法之前打印一句话,例如是打印”方法之前…”这几个字 “` public class BookService{ public void hello(){ System.out.println(“我是service”); } } “`

####2.1未使用代理时

public class BookService{
    public void  hello(){
        System.out.println("方法之前...");
        System.out.println("我是service");
    }
}

在这个功能上又来了新需求:在这个方法后打印”方法之后…”这几个字,这时候又需要修改现有的代码
缺点:

  • 代码不利于维护
  • 当类似的需求多了,一味的修改原来的代码,工作量越来越大,而且会有很多重复的内容,每个地方都需要修改,一旦需求变了,现在不需要打印了,那全部用到的地方就需要重新修改一遍,想想都觉得有点难过呢...
  • 违背了设计原则:开闭原则(OCP),对扩展开放,对修改关闭
  • 违背了设计原则:单一职责(SRP),每个方法除了自己本质功能外还要考虑不断的添加其他的功能

####2.2 使用静态代理优化

①定义一个抽象接口:

public interface IBookService {
    public void hello();
}

②被代理类实现IBookService接口:

public class BookService implements IBookService{
    public void  hello(){
        System.out.println("我是service");
    }
}

③创建一个代理类,实现共同的接口IBookService

public class Proxy implements IBookService {
    //依赖被代理的对象
    IBookService bookService = new BookService();

    //重写方法
    public void hello() {
        System.out.println("方法之前...");
        //调用被代理对象的接口
        bookService.hello();
    }
}

优点:

  • 符合设计原则:开放封闭原则(OCP),没有修改原来的代码,而是通过代理扩展
  • 符合单一职责原则

缺点:

  • 代理对象和被代理对象之前是一种强耦合,代理对象必须知道被代理对象具体的变量或方法,从而进行调用。一旦被代理对象多起来,那就需要创建多个代理,同样不好维护。
    ####2.3 使用JDK提供的动态代理优化
    JDK提供的动态代理有一个特点是基于接口的,也就是被代理对象必须是实现接口的,否则JDK的动态代理是无法实现代理的。使用JDK的动态代理需要创建接口,让被代理对象实现接口。
    创建一个代理对象:
public class Proxy implements InvocationHandler {
    Object targetObject;

    //3.创建一个方法来生成对象,参数是要代理的对象,getInstance返回的对象是代理对象
    public Object getInstance(Object o){
        //3.1创建LogProxy对象
        //3.2设置这个代理对象
        this.targetObject = o;
        //3.3通过Proxy的方法创建代理对象,第一个参数是要代理对象的classLoader
        //第二个参数是要代理对象实现的所有接口,第三个参数是实现类的InvocationHandler对象
        //此时的result就是一个代理对象,代理的是o
        Object result = java.lang.reflect.Proxy.newProxyInstance(o.getClass().getClassLoader(),o.getClass().getInterfaces(),this);
        return result;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法之前...");
        Object invoke = method.invoke(targetObject, args);
        return invoke;
    }
}

写一个测试类:

public class TestJDK {
    public static void main(String[] args) {
        IBookService instance = (IBookService) new Proxy().getInstance(new BookService());
        instance.hello();
    }
}

执行结果:

方法之前...
我是service

总结:

  • JDK提供的动态代理,被代理的对象必须要有接口,这样就有一些局限性,当需要被代理的对象没有接口时就不能使用这种方式,然而也没有必要为了使用JDK动态代理而抽象出一些不必要的接口。
  • JDK提供的动态代理使用步骤如下:①被代理类实现接口 ②代理类实现InvocationHandler接口 ③通过Proxy.newProxyInstance创建代理对象 ④重写InvocationHandler接口的invoker方法,实现在不修改原来代码的前提下动态扩展
    ####2.4 cglib动态代理优化
    解决JDK提供的代理方式要求被代理对象必须实现接口的这个缺点,cglib提供的动态代理方式不要求被代理对象实现接口
    写一个cglib代理类:
    ①添加maven依赖
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.1</version>
</dependency>

②代理类:

 public class Proxy implements MethodInterceptor 
 
	Enhancer enchancer = new Enhancer();//字节码增强器
	public Object getInstance(Object o){
		enchancer.setSuperclass(User.class);//设置被代理类为父类
        enchancer.setCallback(new UserInterceptor());//设置回调
        return enchancer.create();//创建代理实例
	}
     public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
         System.out.println("方法之前...");
         Object object =  methodProxy.invokeSuper(o,objects);
         return object;
     }
 
 }

③写一个测试类:

public class TestCglib {
    public static void main(String[] args) {
        BookService instance = (BookService) new Proxy().getInstance(new BookService());
        instance.hello();
    }
}

总结:

  • 被代理对象不需要实现接口
  • 因为是继承关系,因此final修饰的方法是无法增强的,这种代理方式也是有限制的

总结

传统方式中,类与类之前的耦合性非常强,未使用代理时想要扩展,需要修改原来代码,这样就不符合设计原则,因此有了静态代理,在不修改原来代码情况下实现扩展,这样,一旦类多了就需要创建多个代理类,不利于维护,因此有了动态代理,两种动态代理各有优缺点,因此代理一次次的优化使得编码更加的灵活

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/181148.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 0基础激光切割怎么学_吉他入门零基础视频教程

    0基础激光切割怎么学_吉他入门零基础视频教程杂谈最近有几个人加我,都说是刚开始学激光slam,基本都是研一,情况也都差不多,有的是课题组里只有自己做slam,有的是完全没人带,自己也没有基础.仔细想一想,其实入门slam真是个不容易的事.首先,编程语言,大多数使用c++,少数用python,c++你得至少能写个小demo吧.知道了如何写c++,还要准备编译环境吧,由于编译以及依赖等问题,做slam基本都用linux,还得知道如何使用ubuntu的命令行,知道怎么编译代码.关于机器人相关的大部分代码都使用ros做接口,因为接口统一,使用方式统

    2022年8月23日
    7
  • 吞食鱼1外星鱼_吞食鱼手机激活成功教程版

    吞食鱼1外星鱼_吞食鱼手机激活成功教程版首先,我们准备工具CE还有就是DX窗口化工具。图1:现给窗口化了,才能调试游戏嘛!先打开dx.点全局钩子。然后手动启用游戏。图2:开始了。打开CE搜生命次数!Fuck!没找到?什么原因?图3莫非加壳了?拿peid一看没壳啊!图4换类型搜一下。图5还不行。各种类型搜:都不行。忽然看到了

    2022年8月24日
    8
  • 多模态融合技术综述和应用[通俗易懂]

    多模态融合技术综述和应用[通俗易懂]文章目录多模态技术基础1,多模态融合架构(神经网络模型的基本结构形式)1.1联合架构1.2协同架构1.3编解码架构(自监督)2,多模态融合方法2.1早期融合2.2晚期融合2.3混合融合3,模态对齐方法3.1显式对齐方法3.2隐式对齐方法4,开放数据与资源应用1:多模态摘要(综合多模态信息生成内容摘要)多模态摘要种类多模态表示基础多模态中的注意力机制多模态词表示(用非语言特征:视频、音频调整词语的表示)教学型视频摘要多模态新闻摘要论文Multi-modelSummarizationforAsync

    2022年6月15日
    38
  • 基本图形算法指南

    基本图形算法指南

    2022年1月5日
    49
  • php数据库常用函数

    php数据库常用函数

    2021年11月6日
    47
  • ftp文件下载工具,三个非常好使的ftp文件下载工具

    ftp文件下载工具,三个非常好使的ftp文件下载工具ftp文件下载工具是什么工具,可能有人会回答说不知道,因为一般只有从事网站管理的工作者会使用的多一点。但不是每个人生来就会的,所以刚开始肯定都会学习怎么使用。这篇文章就来告诉大家有哪些ftp文件下载工具吧。第一款:IIS7服务器管理工具说实话,这个工具算是比较好的管理工具了。里面的功能除了批量管理,还有很多别的功能,主要也是功能也比较全面,相信大多数使用的网站工作人员都比较熟悉了。它里面还能够定时上传下载、定时备份和主动更新。把你花在更新上的经历都省了。IIS7服务器管理工具除了在ftp上面有这么多的

    2022年6月5日
    67

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号