概念
为另外一个对象提供一个替身或者占位符以控制对这个对象的访问。
实现
静态代理
- 类图:
Car:
1 | package com.littlehui.design.proxy.statics; |
Bus:
1 | package com.littlehui.design.proxy.statics; |
BusProxy:
1 | package com.littlehui.design.proxy.statics; |
Client:
1 | package com.littlehui.design.proxy.statics; |
- car为接口
- Bus实现car的run方法
- BusProxy负责控制Bus访问方法。
动态代理
- 类图:
动态代理是JDK支持的一种方式 实现例子如下:
Car
1 | package com.littlehui.design.proxy.dymatic; |
Bus:
1 | package com.littlehui.design.proxy.dymatic; |
BusProxyFactory:
1 | package com.littlehui.design.proxy.dymatic; |
Client:
1 | package com.littlehui.design.proxy.dymatic; |
CGLIB动态代理,引入包spring-core-XX.jar
BusProxyFactoryCglib
1 | package com.littlehui.design.proxy.dymatic; |
Client:
1 | package com.littlehui.design.proxy.dymatic; |
result:
1 | /Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/bin/java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:62751,suspend=y,server=n -Dfile.encoding=UTF-8 -classpath "/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/tools.jar:/Users/littlehui/WorkSpaces/Home/pattern/proxy/target/classes:/Users/littlehui/software/repository/org/springframework/spring-core/5.0.0.RC3/spring-core-5.0.0.RC3.jar:/Users/littlehui/software/repository/org/springframework/spring-jcl/5.0.0.RC3/spring-jcl-5.0.0.RC3.jar:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar" com.littlehui.design.proxy.dymatic.Client |
Cglib生成的动态代理类是业务类的子类,重写业务方法进行代理。
可以看到CGLIB调用的 class是 class com.littlehui.design.proxy.dymatic.Bus 这个在Spring类的装配和其他涉及获取Class的地方相当有用。
- car为接口
- Bus实现Car的run方法
- Bus对象的访问交给了BusProxyFactory控制。
- BusProxyFactory执行中动态地加入了run方法执行前后的标识。
场景
- Spring AOP
- 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
- 如果目标对象实现了接口,可以强制使用CGLIB实现AOP
- 如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
总结
代理和装饰模式看起来很相似,但是深入理解,本质上是有区别的 主要的区别是:
使用代理模式,代理和真实对象之间的的关系通常在编译时就已经确定了,而装饰者能够在运行时递归地被构造。也就是那句话:代理模式可以控制被代理的对象
可以控制被代理对象的访问,而装饰模式是被装饰对象的增强。不体现在控制上。