代理简析(静态代理与动态代理)
来源:互联网 发布:wps文字软件下载 编辑:程序博客网 时间:2024/06/01 10:44
1、代理
代理,简称为Proxy。意思就是你什么都不用去做,别人代替你去做。
她在程序开发中起到了非常重要的作用,比如AOP,就是针对代理的一种应用。此外,在设计模式中,还有一个“代理模式”。
接下来,通过一个例子,由浅及深学习
public interface Hello{ void say(String name)}
上面是一个Hello的接口,接下来是实现类
public class HelloImpl implements Hello{ @Override public void say(String name){ System.out.println("Hello!"+name); }}
如果要在println方法前面和后面分别需要处理一些逻辑,如果把这些逻辑写进say方法了,肯定是不行的。
那么此时,就需要用代理模式,写一个HelloProxy类,让他去调用HelloImpl的say方法,在调用前后分别进行逻辑处理。具体如下:
public class HelloProxy implements Hello{ private Hello hello; public HelloProxy(){ hello=new HelloImpl(); } @Override public void say(String name){ before(); hello.say(name); after(); } private void before(){ System.out.println("Before"); } private void after(){ System.out.println("After"); }}
用HelloProxy类实现了Hello接口,并且哎构方法中new出一个HelloImpl类的实例。这样,我们就可以在HelloProxy的say方法里面调用HelloImpl的say方法了。更重要的是,我们在调用前加上了before和after方法,在这两个方法实现那些前后逻辑。
用一个main方法测试一下:
public static void main(String[] args){ Hello helloProxy=new HelloProxy(); helloProxy.say("Jack");}
打印的结果为:
BeforeHello!JackAfter
这样,我们就写了一个HelloProxy的“代理模式”。
2、JDK动态代理
上述中,使用的就是静态代理,那么什么是动态代理呢?
下面用JDK提供额动态代理方案写一个DynamicProxy:
public class DynamicProxy implements InvocationHandler{ private Object target; public DynamicProxy(Object target){ this.target=target; } @Override public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{ before(); Object result=method.invoke(target,args); after(); return result; } .....}
在DynamicProxy类中,定义了一个Object类型的target变量他就是被代理的目标对象,通过构造函数来初始化,也就是注入。构造方法称为反射。
在DynamicProxy类中,实现了 InvocationHandler接口 ,那么必须实现该接口的invoke方法。该方法是jar“反射”过来的。在invoke中,在调用前后分别处理before和after,左后result返回。
public static void main(String[] args){ Hello hello=new HelloImpl(); DynamicProxy dynamicProxy=new DynamicProxy(hello); Hello helloProxy=(Hello)Proxy.newProxyInstance( hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), dynamicProxy ); helloProxy.say("Jack");}
意思就是通过用这个通用的DynamicProxy 类去包装HelloImpl实例,然后再调用JDK给我们提供的Proxy类的工厂方法newProxyInstance去动态创建一个Hello接口的代理类,最后调用这个代理类的say方法。
运行的结果是一样的,动态代理成功了。那么,动态代理就是帮我们自动生成XxxProxy类的法宝。
但是,Proxy.newProxyInstance方法参数有点令人烦躁
- 参数1:ClassLoader
- 参数2:该实现类的所有接口
参数3:动态代理对象
调用完后,还需要强制转换一下。
如果需要的代理对象比较多,那么意味着,到处都出现Proxy.newProxyInstance方法的情况。所有需要把DynamicProxy 重构一下:
public class DynamicProxy implements InvocationHandler{ @SuppressWarnings("unchecked") public <T> T getProxy(){ return (T)Proxy.newProxyInstance( target.getClass().getClassLoader(), target..getClass().getInterfaces(), this ); } .....}
在DynamicProxy 里添加了一个getProxy方法,无须传入任何参数,将刚才说的那一块代码放入这个方法中,并且该方法返回一个泛型类型就不会强制转换类型。方法上添加一个@SuppressWarnings(“unchecked”)注解表示忽略编译时的警告(因为Proxy.newProxyInstance方法返回的是一个Object,这里强制转换为T了,这是向下转型。)
那么此时使用DynamicProxy 就简单了。
public static void main(String[] args){ DynamicProxy dynamicProxy=new DynamicProxy(new HelloImpl()); Hello helloProxy=dynamicProxy.getProxy(); helloProxy.say("Jack");}
此时,代码简洁多了,那么动态代理大概也就懂了。
3、CGlib动态代理
动态代理并不是万能的,总有用不了的地方。那么在Spring、Hibernate中的高端框架中都有用到过CGlib类库。它是一个在运行期间动态生成字节码的工具,也就是动态生成代理类。
下面通过代码简洁的说下,我理解的也不深~
public class CGlibProxy implements MethodInterceptor{ public <T> T getProxy(Class<T> cls){ return(T)Enhancer.create(cls,this); } public Object intercept(Object obj,Method method,Object[] args,MethodProxy proxy) throws Throwable{ before(); Object result=proxy.invokeSuper(obj,args); after(); result result; } ...}
需要实现CGlib给我们提供的MethodInterceptor实现类,并填充intercept方法。方法中最后一个MethodProxy类型的参数proxy值得注意。Cglib给我们提供的是方法级别的代理,也可以理解为对方法的拦截(这就是“方法拦截器”)。我们直接调用proxy的invokeSuper方法,将被代理的对象obj以及方法参数args传入其中即可。
与DynamicProxy 类似,在CGlib中也添加一个泛型的getProxy方法,便于我们快速地获取自动生成的代理对象。
public static void main(String[] args){ CGlibProxy cglibProxy=new CGlibProxy(); Hello helloProxy=cglibProxy.getProxy(HelloImpl.class); helloProxy.say("Jack");}
对于此刻的代码,如果用“单例模式”后,会不会更加简洁些呢。
public class CGlibProxy implements MethodInterceptor{ private static CGlibProxy instance=new CGlibProxy(); private CGlibProxy(){ } public static CGlibProxy getInstance(){ return instance; } ...}
那么此时,main中:
public static void main(String[] args){ Hello helloProxy=CGlibProxy.getInstance.getProxy(HelloImpl.class); helloProxy.say("Jack");}
以上,简述了静态代理和动态代理,如果有更好的见解,欢迎指点~
- 代理简析(静态代理与动态代理)
- 静态代理与动态代理
- 静态代理与动态代理
- 静态代理与动态代理
- 静态代理与动态代理
- 静态代理与动态代理
- 静态代理与动态代理
- 静态代理与动态代理
- 静态代理与动态代理
- 静态代理与动态代理
- 静态代理与动态代理
- 静态代理与动态代理
- 静态代理与动态代理
- 静态代理与动态代理
- 静态代理与动态代理
- 静态代理与动态代理
- 静态代理与动态代理
- 静态代理与动态代理
- STM32CubeMX的SDIO模式下对SD卡读写测试(附源码)
- ubuntu上解决访问github慢的方法
- Selenium2+Python2.0自动化测试【12】 多表单切换
- 自定义控件:带有清除功能的 ClearEditText
- Hibernate常见面试题
- 代理简析(静态代理与动态代理)
- 解决奖惩信息更新页面信息id不能传到controler层,其他都可以
- redis 安装问题汇总
- 安装XGboost
- jeesite集成cas之多点登出
- Material Design颜色xml
- 【解决】SpringMVC整合Shiro之 Error creating bean with name 'shiroFilter' defined in class path resource...
- Error Code: 1175. You are using safe update...
- nginx access_log日志