JavaWeb -----代理Proxy

    xiaoxiao2021-03-25  83

    (一)引入:为什么会有代理!! 原因是:阻止对目标对象的直接访问,或者就是在执行目标对象时,在执行目标对象前后进行一系列的操作。举个例子来说,1:在执行一个方法之前必须要对该“方法”做“日记”,记录每个操作,这样可以在执行目标对象之前,先执行一个的操作,然后执行该方法。2:又如明星唱歌例子,商家首先找到该明星的代理公司,谈妥后再找该明星去唱歌,中间代理起拦截等的操作 (二)代理类别:步步推进, 静态代理:手动添加被代理对象的方法

    开发步骤: 1)写一个普通类,继承目标对象的接口 2)写一个实例变量,记住代理谁,即目标对象 3)使用构造方法为实例变量赋值,或者可以直接赋值 4)写一个普通方法,该方法的返回值是接口,该接口是目标对象的实现接口 //Star是接口,LiuDeHuaProxy是代理,LiuDeHua是目标对象。最终目的是为了调用LiuDeHua 的sing方法 // (1) 继承了目标对象的接口 public class LiuDeHuaProxy implements Star { //实例化了目标对象,是为了提供给别人使用 private LiuDeHua LiuDeHua= new LiuDeHua(); //代理对象不会唱歌方法,实际还是调用了目标对象的唱歌方法 public void sing() { liyuchun.sing(); } //基于接口编程:提供的Star。这里也就是在提供目标接口时进行一系列操作。比如可以说if的过滤条件,做日志也可以 public Star getProxy() { if(钱不够){ system.out.println("钱不够,不能唱歌") }else{ return LiuDeHua; } } }

    这种静态代理的方法不推荐使用,分析一下,如果说,star里面有多少个方法,在代理对象的类中就有多少个方法。不利于扩展。举个例子,如果说在A类是目标对象,B类是代理对象,A类每个方法执行前都需要做”日志“操作,那么代理对象需要扩展A类所有方法,在执行前+上日志的代码。当A类增加方法时,B类仍然要手动添加一个方法做”日志“。所以这里不推荐使用

    动态代理:自动生成被代理对象的方法,无须手动生成

    开发步骤: 1)写一个普通类,无需任何继承或实现 2)写一个实例变量,记住代理谁,即目标对象 3)使用构造方法为实例变量赋值 4)写一个普通方法,该方法的返回值是接口,该接口是目标对象的实现接口 //代理类 public class LiyuchunProxy{ //代理谁,也可以通过构造方法赋值 private Liyuchun liyuchun = new Liyuchun(); //动态产生代理对象 public Star getProxy(){、 /*这里主要是学习Proxy类。可以去查询一下手册 * Proxy * static newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) * 第一个参数是:loader表示动态代理对象由哪个类加载器完成的 ,这里是LiyuchunProxy * 第二个参数是:interface表示动态代理对象和目标对象有一样的接口的方法。 * 第三个参数是:动态代理对象的拦截方法,即每次都会执行该方法 */ return (Star) Proxy.newProxyInstance( LiyuchunProxy.class.getClassLoader(), liyuchun.getClass().getInterfaces(), new InvocationHandler(){ /*InvocationHandler 是一个接口,只有一个invoke方法。可以看手册 * *第一个参数是:动态产生代理对象本身 *第二个参数是:表示方法 *第三个参数是:表示方法参数,是一个数据,从0-n */ public Object invoke( Object proxy, Method method, Object[] args) throws Throwable { String money = (String) args[0]; //拦截sing方法,如果是sing方法,做什么,如果是其他方法做什么 if("sing".equals(method.getName())){ if("3".equals(money)){ //调用春哥的sing()方法 return method.invoke(liyuchun,args); }else{ System.out.println("不够出场费"); } }else if("dance".equals(method.getName())){ if("5".equals(money)){ return method.invoke(liyuchun,args); }else{ System.out.println("不够出场费"); } }else if("eat".equals(method.getName())){ System.out.println("春哥今天有事,不能来"); } return null; } }); } }

    总结来说:1)推荐使用动态代理的方法。 2)如果说掌握的spring框架的朋友,可以使用spring框架所带的注解的方式去代理,这样会更简单,以后有机会再见 3)学好代理的两个重要的点

    //1:代理谁 设计一个类变量,以及一个构造函数,记住代理类 代理哪个对象。 //2:如何生成代理对象(invoke方法) 设计一个方法生成代理对象(在方法内编写代码生成代理对象是此处编程的难点) //备注,下面有三个例子,会画图具体分析,耐心看完下面一点点点

    (三)案例说明 1. 全站字符编码过滤(request代理) 2. 全站压缩流输出(response代理) 3. 自定义数据库连接池(connection代理) 由于篇幅的原因,这里只能列出第一个案例的源码,其他的一些源码我放在word文档里面,需要的可以执行下载。word里面有配图

    分析:

    public class EncodingFilter implements Filter { public void destroy() { } public void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; MyRequest myRequest = new MyRequest(request); //放行资源 chain.doFilter(myRequest.getProxy(),response); } public void init(FilterConfig filterConfig) throws ServletException { } } //使用动态代理方式产生代理对象 动态代理步骤一:写一个普通的方法,无需要任何的继承 class MyRequest{ //动态代理步骤二:这是一个目标对象实例变量,也就是HttpServletRequest上面分析的 private HttpServletRequest request; //动态代理步骤三:通过构造方法给实力变量赋值 public MyRequest(HttpServletRequest request){ this.request = request; } //写一个普通方法,返回值是接口,提供目标对象的方法 public HttpServletRequest getProxy(){ //三大参数,写法差不多 return (HttpServletRequest) Proxy.newProxyInstance( MyRequest.class.getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler(){ public Object invoke( Object proxy, Method method, Object[] args) throws Throwable { if("getParameter".equals(method.getName())){ //取得请求的类型[POST或GET] String m = request.getMethod(); //如果是GET请求类型 if("get".equalsIgnoreCase(m)){ String value = request.getParameter((String)args[0]);//乱码 byte[] buf = value.getBytes("ISO8859-1"); value = new String(buf,"UTF-8");//正码 return value; }else if("post".equalsIgnoreCase(m)){ request.setCharacterEncoding("UTF-8"); String value = request.getParameter((String)args[0]);//正码 return value; } }else{ //放行 return method.invoke(request,args); } return null; } }); } }

    其他的代码有必要下载word文档咯 下载:http://download.csdn.net/detail/xiaozhegaa/9778527 (四)总结:细心的人会发现好像代理跟filter过滤有一点的相似。还是有一定的相似之处。可以说filter是大局,而代理是细节。举个例子来说,上述的filter过滤的是LoginServlet,也可以在dochain.filter(request,response)放行之前编码。但是这样有点粗糙,如果request中不执行getParameter方法时也会有编码。而代理是细节,精细到request里面的一个方法,当执行这个方法时才会进行设置编码,否则不执行。可以看出。filter是比较宏观,代理比较细节。所以两者配合使用效果会更好

    转载请注明原文地址: https://ju.6miu.com/read-33480.html

    最新回复(0)