代理模式及其他拓展

设计模式很大程度上,都是为了java代码能够做到高内聚,低耦合,对扩展开放,对修改关闭;对于未来任何新功能添加的可能性开放,已有代码的修改关闭,为了更好的兼容同类型操作的添加,原始添加类型的尽可能不与变更

策略模式:当多个对象可能具有多个行为时,将行为抽象为一个父类,再为具体的行为做具体的实现,在需要进行更改,添加某个具体的行为时,原始各个对象的调用代码不需要进行修改

责任链模式:当程序,或者两个对象,需要重复经过很多次的不同的事件处理,或者重复经过多次不同的事件处理,可以将 这个处理的过程,抽象为一个具体的父类,再为不同对象之间不同处理具象不同的子类实现,然后将子类的创建管理动态绑定交付给父类的另一个子类-责任链,由责任链负责多个子类的管理,进行不同对象的不同事件处理的托管行为;

观察者模式:用于对事件进行监听并根据具体事件进行一定的处理(常和责任链模式搭配使用,进行事件的监听处理),可以将事件的产生者抽象以及将不同的事件抽象为同一个观察者父类,然后为不同的事件的监听处理者做具体实现;

组合模式(node,将对象组合成树形结构展现部分-整体的结构,可以用一致的处理方式处理对象及对象集合,常用遍历)

享元模式:共享元数据,将某些数据作为元数据,放入常量池,供多个请求者共享(string定义的字符串常量就是,在非new情况下定义的多个相同内容的string类型字符串,其实是同一个);

代理模式:

静态代理:代理是基于类的代理,类中可以有一些方法(行为),如果方法中需要做的实现太多(方之大,一锅炖不下),可以用代理来实现,具体方法为:(新增一个代理接口),新增一个代理类,在代理类中添加代理所需要执行的一些操作,然后对原始类中的方法进行具体的实现;如果原始类需要更多的方法实现,可以将不同的方法实现抽象为不同的代理类,并将代理类实现同一个代理接口,则多个代理类之间可以相互嵌套;

动态代理: 缺点是,代理类必须实现某个接口

 

 

生成代理,除了jdk反射代理外,还可以用cglib生成代理

 

底层都是用的ASM,可以直接获取java字节码文件的二进制数据,直接修改

jdk反射实现的动态代理,可以随时为类的某个行为创建一个代理,即用Proxy.newProxyInstance(a,b,c)方法来用被代理类的类加载器a加载出来的实现了接口b的代理,代理中的具体实现放在另一个类C中,c为该类的一个实例化对象;其中C是InvocationHandler的一个实现类;

在newProxyInstance方法中,有对代理类C的判空,也有对系统安全性的校验:

在1.8版本中,判空和系统安全校验之后,是一个getProxyClass的方法,会先去proxyClassCache中获取一个已有的实现了与被代理类实现同一个接口的类,如果没有的话,用懒加载初始化一个新的代理类,或者用工厂创建一个代理类返回去,然后用getProxyClass方法获取到的类对象调用getConstructor()方法获取该类的构造器,在调用newInstance方法最终生成一个代理类实例,在多次方法的调用中,会将被代理类的实现接口以及代理类的具体实现类作为参数传入,让程序知道具体代理的是哪个类,该执行的是哪个方法;

在jdk11版本中,判空和系统安全校验之后,是一个getProxyConstructor 方法,该方法直接从一个proxyCache中获取代理类的构造方法,如果没有,就利用代理类builder重新构建一个,而在build()方法中,同样也是通过defineProxyClass来定义一个代理类,在通过该代理类获取构造方法;

 

具体在defineProxyClass中,是如何凭空生成一个代理类的?

--调用ProxyGenerator.generateProxyClass方法,在该方法中传入代理类相关信息(类名,类所实现的接口,类的访问控制权限)后,写入类中的具体方法(包括hashcodo方法,equals方法,toString方法,以及代理类的代理方法)

 

 

具体method.add方法,是如何将这些方法加入类中的?

--正常来说,java运行程序,是通过开发源码后,通过jvm编译后生成class文件,并加载到内存中;methods.add方法源自ASM包,ASM可以直接对二进制文件进行修改。这也是java被称为动态语言的重要原因之一;理论上,装载了ASM-API的任何语言程序都可以在jvm上运行;

还有一个生成代理的方法,Instrument-调琴,java自带,相当于一个狗子函数(拦截器),在每一个class文件装载到内存之前,进行拦截并可以直接修改二进制码文件;而ASM需要通过其API来进行对二进制文件的修改,由诸多限制;但是使用Instrument,要求较多,需要了解二进制文件中每一个16位字节码的含义

动态代理和spring-aop:

代理的意义在于随时随地在运行的程序中插入一些需要额外处理的行为,而不影响原有程序的执行线路;spring-aop:面向切面编程,spring有多种方式来将定义好的代理类(切面)在任意位置对原始类进行代理(切入)

eg1:

 

在引入aop的相关jar包后,可以在spring配置文件中,定义原始类tank以及其代理类timeProxy,并添加aop相关配置,定义切入点(原始类中需要被额外操作的方法),以及代理类中额外处理的部分;

此外,在原始类中,保留原有move方法不更改,不需要添加多余的实现类;在代理类中,调用method.invoke方法即可完成基于Tank类的move方法的切入,即在move方法执行前后分别切入onmove方法的实现;

eg2:

使用注解的方法,对定义好的代理类(切面)进行自动装载,需要额外引入org-aspectj.jar,然后只需在配置文件中加一行<aop:aspectj-autoproxy>,自动代理;

 

@Aspect:标明该类是一个切面类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值