java进阶--动态代理核心知识及应用
一、静态代理
eg:
package test.tmp; interface interfDog { void info(); } class OriginDog implements interfDog { @Override public void info() { System.out.println("this is originDog"); } } //代理dog1 class StaticProxyDog1 implements interfDog{ private OriginDog orDog = new OriginDog(); @Override public void info() { System.out.println("StaticProxyDog1 doSomething before exec"); orDog.info(); System.out.println("StaticProxyDog1 doSomething after exec"); } } //代理dog2 class StaticProxyDog2 implements interfDog{ private OriginDog orDog = new OriginDog(); @Override public void info() { System.out.println("StaticProxyDog2 doSomething before exec"); orDog.info(); System.out.println("StaticProxyDog2 doSomething after exec"); } } public class StaticProxy { public static void main(String[] args) { StaticProxyDog1 p1 = new StaticProxyDog1(); p1.info(); System.out.println("==================================================="); StaticProxyDog2 p2 = new StaticProxyDog2(); p2.info(); } }
二、静态代理和代理设计模式及应用
(1)概念
代理模式:对某一个目标对象提供它的代理对象,并且由代理对象控制对原对象的引用。
静态代理:只能为给定接口的实现类做代理,如果接口不同则需要重新定义不同的代理类。(在代码运行前代理类的class编译文件就已经存在)
(2)作用
(2.1)权利代理功能:可屏蔽对原对象(主对象)的直接访问,代替原对象执行操作,实现原有对象与外部操作的隔离。
例如:
(2.1.1)权限身份验证(通过代理对象增加权限功能)。
(2.1.2)RPC通过建立代理,直接实现了不存在的接口实现(消费者中只有接口,没有实现类)。
(2.2)功能增强:代理对象可以在原有对象的基础上对原有功能进行扩展(增强)。例如:AOP中的切面操作是通过建立代理实现的。
三、装饰者模式
(1)概念:
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
(2)代码示例:
package test.decor; interface Dog { public void info(); } class YelloDog implements Dog { @Override public void info() { System.out.println("this is yello dog"); } } class WhiteDog implements Dog { @Override public void info() { System.out.println("this is White dog"); } } abstract class DogDecorator implements Dog { protected Dog dog; protected DogDecorator(Dog dog) { this.dog = dog; } public void info() { dog.info(); } } class DogDecoratorImpl extends DogDecorator { protected DogDecoratorImpl(Dog dog) { super(dog); } @Override public void info() { dog.info(); System.out.println("this is dog decorate"); } } public class DecoratorDemo { public static void main(String[] args) { DogDecorator yg = new DogDecoratorImpl(new YelloDog()); yg.info(); DogDecorator wg = new DogDecoratorImpl(new WhiteDog()); wg.info(); } }
(4)引申:代理模式和装饰者模式区别
网络上有些说法过于较真哈,简单理解,主要是代码用法上的区别(万变不离其宗,其实是原始概念上的区别),代理模式中代理对象可以对原有对象隐藏一些的具体信息(主要是代理执行)。使用代理模式的时候,一般在一个代理类中创建一个对象的实例(代理对象)。装饰者模式中将原始对象作为一个参数传给装饰者的构造方法。共同点是都可以对原有功能进行增强。
其实设计模式主要的作用是看在项目中主要的应用场景,综合考虑项目的可扩展性、可维护性、以及尽量避免不必要的bug、工作量等因素,需要优化代码的逻辑实现,结合这些前辈们总结的设计模式,有相似的tip可以直接采用,或者结合项目需要进行优化组装。
四、动态代理
这种没有实现类但是在运行期动态创建了一个接口对象的方式,我们称为动态代码。JDK提供的动态创建接口对象的方式,就叫动态代理。
(1)jdk动态代理
(1.1)代码示例:
package test.tmp; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface InterfDog { void info(); } class OriginDog implements InterfDog { @Override public void info() { System.out.println("this is Origin dog"); } } public class DynamicProxyHandler implements InvocationHandler { private Object target; protected DynamicProxyHandler(Object target) { super(); this.target = target; } protected DynamicProxyHandler() { super(); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("bofore invoke"); Object result = method.invoke(target, args);// 执行方法 System.out.println("after invoke"); return result; } public static void main(String[] args) { OriginDog yg = new OriginDog(); DynamicProxyHandler proxyHandler = new DynamicProxyHandler(yg); // 基于接口动态生成实现类(生成代理对象) InterfDog proxyDog = (InterfDog) Proxy.newProxyInstance(InterfDog.class.getClassLoader(), new Class[] { InterfDog.class }, proxyHandler); proxyDog.info(); } }
(1.2)jdk动态代理实现原理
调用Proxy.newProxyInstance生成代理类的实现类:
- 调用getProxyClass0寻找或生成指定代理类(从缓存中取,如果没有,就生成一个放在缓存中 : 通过ProxyClassFactory生成);
- 缓存调用ProxyClassFactory生成代理类,proxy class的生成最终调用ProxyClassFactory的apply方法;
- ProxyGenerator.generateProxyClass使用生成的代理类的名称,接口,访问标志生成proxyClassFile字节码。
byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { throw new IllegalArgumentException(e.toString()); }
生成字节码之后利用反射生成实例Proxy.newProxyInstance创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行时动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号。
如图所示:
(2)CGLib动态代理
(2.1)代码示例:
package test.tmp; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; class OriginDog { public void info(){ System.out.println("this is origin dog"); } } class MyMethodInterceptor implements MethodInterceptor{ @Override public Object intercept(Object sub, Method method, Object[] objs, MethodProxy methodProxy) throws Throwable { System.out.println("before invokeSuper"); Object obj = methodProxy.invokeSuper(sub, objs); System.out.println("after invokeSuper"); return obj; } } public class CGLibProxy { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(OriginDog.class); enhancer.setCallback(new MyMethodInterceptor()); OriginDog proxy = (OriginDog)enhancer.create(); proxy.info(); } }
(2.1)CGLib动态代理原理
//TODO 后续补充,一点点来嘛,精彩还在后面
五、AOP和动态代理及应用
推荐一个帖子,对AOP理解很透彻,语言组织也好,诙谐幽默,感谢这些有价值的贡献者,地址 https://mp.weixin.qq.com/s/J-RQ2ltvo4d8hBuMrsvGGg
查阅和参考了不少资料,感谢各路大佬分享,如需转载请注明出处,谢谢:https://www.cnblogs.com/huyangshu-fs/p/11454369.html