欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java 代理(Proxy)的原理及應(yīng)用

 更新時(shí)間:2021年05月27日 10:38:11   作者:孤傲蒼狼  
動(dòng)態(tài)代理技術(shù)就是用來(lái)產(chǎn)生一個(gè)對(duì)象的代理對(duì)象的。 我們?cè)陂_(kāi)發(fā)中之所以要產(chǎn)生一個(gè)對(duì)象的代理對(duì)象,主要用于攔截對(duì)真實(shí)業(yè)務(wù)對(duì)象的訪問(wèn)。本文主要介紹了Java 代理的使用,感興趣的可以了解一下

一、代理的概念

  動(dòng)態(tài)代理技術(shù)是整個(gè)java技術(shù)中最重要的一個(gè)技術(shù),它是學(xué)習(xí)java框架的基礎(chǔ),不會(huì)動(dòng)態(tài)代理技術(shù),那么在學(xué)習(xí)Spring這些框架時(shí)是學(xué)不明白的。

  動(dòng)態(tài)代理技術(shù)就是用來(lái)產(chǎn)生一個(gè)對(duì)象的代理對(duì)象的。在開(kāi)發(fā)中為什么需要為一個(gè)對(duì)象產(chǎn)生代理對(duì)象呢?
  舉一個(gè)現(xiàn)實(shí)生活中的例子:歌星或者明星都有一個(gè)自己的經(jīng)紀(jì)人,這個(gè)經(jīng)紀(jì)人就是他們的代理人,當(dāng)我們需要找明星表演時(shí),不能直接找到該明星,只能是找明星的代理人。比如劉德華在現(xiàn)實(shí)生活中非常有名,會(huì)唱歌,會(huì)跳舞,會(huì)拍戲,劉德華在沒(méi)有出名之前,我們可以直接找他唱歌,跳舞,拍戲,劉德華出名之后,他干的第一件事就是找一個(gè)經(jīng)紀(jì)人,這個(gè)經(jīng)紀(jì)人就是劉德華的代理人(代理),當(dāng)我們需要找劉德華表演時(shí),不能直接找到劉德華了(劉德華說(shuō),你找我代理人商談具體事宜吧!),只能是找劉德華的代理人,因此劉德華這個(gè)代理人存在的價(jià)值就是攔截我們對(duì)劉德華的直接訪問(wèn)!
  這個(gè)現(xiàn)實(shí)中的例子和我們?cè)陂_(kāi)發(fā)中是一樣的,我們?cè)陂_(kāi)發(fā)中之所以要產(chǎn)生一個(gè)對(duì)象的代理對(duì)象,主要用于攔截對(duì)真實(shí)業(yè)務(wù)對(duì)象的訪問(wèn)。那么代理對(duì)象應(yīng)該具有什么方法呢?代理對(duì)象應(yīng)該具有和目標(biāo)對(duì)象相同的方法

  所以在這里明確代理對(duì)象的兩個(gè)概念:
    1、代理對(duì)象存在的價(jià)值主要用于攔截對(duì)真實(shí)業(yè)務(wù)對(duì)象的訪問(wèn)。
    2、代理對(duì)象應(yīng)該具有和目標(biāo)對(duì)象(真實(shí)業(yè)務(wù)對(duì)象)相同的方法。劉德華(真實(shí)業(yè)務(wù)對(duì)象)會(huì)唱歌,會(huì)跳舞,會(huì)拍戲,我們現(xiàn)在不能直接找他唱歌,跳舞,拍戲了,只能找他的代理人(代理對(duì)象)唱歌,跳舞,拍戲,一個(gè)人要想成為劉德華的代理人,那么他必須具有和劉德華一樣的行為(會(huì)唱歌,會(huì)跳舞,會(huì)拍戲),劉德華有什么方法,他(代理人)就要有什么方法,我們找劉德華的代理人唱歌,跳舞,拍戲,但是代理人不是真的懂得唱歌,跳舞,拍戲的,真正懂得唱歌,跳舞,拍戲的是劉德華,在現(xiàn)實(shí)中的例子就是我們要找劉德華唱歌,跳舞,拍戲,那么只能先找他的經(jīng)紀(jì)人,交錢(qián)給他的經(jīng)紀(jì)人,然后經(jīng)紀(jì)人再讓劉德華去唱歌,跳舞,拍戲。

二、java中的代理

2.1、"java.lang.reflect.Proxy"類介紹

  現(xiàn)在要生成某一個(gè)對(duì)象的代理對(duì)象,這個(gè)代理對(duì)象通常也要編寫(xiě)一個(gè)類來(lái)生成,所以首先要編寫(xiě)用于生成代理對(duì)象的類。在java中如何用程序去生成一個(gè)對(duì)象的代理對(duì)象呢,java在JDK1.5之后提供了一個(gè)"java.lang.reflect.Proxy"類,通過(guò)"Proxy"類提供的一個(gè)newProxyInstance方法用來(lái)創(chuàng)建一個(gè)對(duì)象的代理對(duì)象,如下所示:

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 

  newProxyInstance方法用來(lái)返回一個(gè)代理對(duì)象,這個(gè)方法總共有3個(gè)參數(shù),ClassLoader loader用來(lái)指明生成代理對(duì)象使用哪個(gè)類裝載器,Class<?>[] interfaces用來(lái)指明生成哪個(gè)對(duì)象的代理對(duì)象,通過(guò)接口指定,InvocationHandler h用來(lái)指明產(chǎn)生的這個(gè)代理對(duì)象要做什么事情。所以我們只需要調(diào)用newProxyInstance方法就可以得到某一個(gè)對(duì)象的代理對(duì)象了。

2.2、編寫(xiě)生成代理對(duì)象的類

  在java中規(guī)定,要想產(chǎn)生一個(gè)對(duì)象的代理對(duì)象,那么這個(gè)對(duì)象必須要有一個(gè)接口,所以我們第一步就是設(shè)計(jì)這個(gè)對(duì)象的接口,在接口中定義這個(gè)對(duì)象所具有的行為(方法)

  1、定義對(duì)象的行為接口

package cn.gacl.proxy;

/**
* @ClassName: Person
* @Description: 定義對(duì)象的行為
* @author: 孤傲蒼狼
* @date: 2014-9-14 下午9:44:22
*
*/
public interface Person {

    /**
    * @Method: sing
    * @Description: 唱歌
    * @Anthor:孤傲蒼狼
    *
    * @param name
    * @return
    */
    String sing(String name);
    /**
    * @Method: sing
    * @Description: 跳舞
    * @Anthor:孤傲蒼狼
    *
    * @param name
    * @return
    */
    String dance(String name);
}

  2、定義目標(biāo)業(yè)務(wù)對(duì)象類

package cn.gacl.proxy;

/**
* @ClassName: LiuDeHua
* @Description: 劉德華實(shí)現(xiàn)Person接口,那么劉德華會(huì)唱歌和跳舞了
* @author: 孤傲蒼狼
* @date: 2014-9-14 下午9:22:24
*
*/
public class LiuDeHua implements Person {

    public String sing(String name){
        System.out.println("劉德華唱"+name+"歌?。?);
        return "歌唱完了,謝謝大家!";
    }

    public String dance(String name){
        System.out.println("劉德華跳"+name+"舞??!");
        return "舞跳完了,多謝各位觀眾!";
    }
}

  3、創(chuàng)建生成代理對(duì)象的代理類

package cn.gacl.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
* @ClassName: LiuDeHuaProxy
* @Description: 這個(gè)代理類負(fù)責(zé)生成劉德華的代理人
* @author: 孤傲蒼狼
* @date: 2014-9-14 下午9:50:02
*
*/
public class LiuDeHuaProxy {

    //設(shè)計(jì)一個(gè)類變量記住代理類要代理的目標(biāo)對(duì)象
    private Person ldh = new LiuDeHua();

    /**
    * 設(shè)計(jì)一個(gè)方法生成代理對(duì)象
    * @Method: getProxy
    * @Description: 這個(gè)方法返回劉德華的代理對(duì)象:Person person = LiuDeHuaProxy.getProxy();//得到一個(gè)代理對(duì)象
    * @Anthor:孤傲蒼狼
    *
    * @return 某個(gè)對(duì)象的代理對(duì)象
    */
    public Person getProxy() {
        //使用Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)返回某個(gè)對(duì)象的代理對(duì)象
        return (Person) Proxy.newProxyInstance(LiuDeHuaProxy.class
                .getClassLoader(), ldh.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     * InvocationHandler接口只定義了一個(gè)invoke方法,因此對(duì)于這樣的接口,我們不用單獨(dú)去定義一個(gè)類來(lái)實(shí)現(xiàn)該接口,
                     * 而是直接使用一個(gè)匿名內(nèi)部類來(lái)實(shí)現(xiàn)該接口,new InvocationHandler() {}就是針對(duì)InvocationHandler接口的匿名實(shí)現(xiàn)類
                     */
                    /**
                     * 在invoke方法編碼指定返回的代理對(duì)象干的工作
                     * proxy : 把代理對(duì)象自己傳遞進(jìn)來(lái)
                     * method:把代理對(duì)象當(dāng)前調(diào)用的方法傳遞進(jìn)來(lái)
                     * args:把方法參數(shù)傳遞進(jìn)來(lái)
                     *
                     * 當(dāng)調(diào)用代理對(duì)象的person.sing("冰雨");或者 person.dance("江南style");方法時(shí),
                     * 實(shí)際上執(zhí)行的都是invoke方法里面的代碼,
                     * 因此我們可以在invoke方法中使用method.getName()就可以知道當(dāng)前調(diào)用的是代理對(duì)象的哪個(gè)方法
                     */
                    @Override
                    public Object invoke(Object proxy, Method method,
                            Object[] args) throws Throwable {
                        //如果調(diào)用的是代理對(duì)象的sing方法
                        if (method.getName().equals("sing")) {
                            System.out.println("我是他的經(jīng)紀(jì)人,要找他唱歌得先給十萬(wàn)塊錢(qián)?。?);
                            //已經(jīng)給錢(qián)了,經(jīng)紀(jì)人自己不會(huì)唱歌,就只能找劉德華去唱歌!
                            return method.invoke(ldh, args); //代理對(duì)象調(diào)用真實(shí)目標(biāo)對(duì)象的sing方法去處理用戶請(qǐng)求
                        }
                        //如果調(diào)用的是代理對(duì)象的dance方法
                        if (method.getName().equals("dance")) {
                            System.out.println("我是他的經(jīng)紀(jì)人,要找他跳舞得先給二十萬(wàn)塊錢(qián)??!");
                            //已經(jīng)給錢(qián)了,經(jīng)紀(jì)人自己不會(huì)唱歌,就只能找劉德華去跳舞!
                            return method.invoke(ldh, args);//代理對(duì)象調(diào)用真實(shí)目標(biāo)對(duì)象的dance方法去處理用戶請(qǐng)求
                        }

                        return null;
                    }
                });
    }
}

  測(cè)試代碼:

package cn.gacl.proxy;

public class ProxyTest {

    public static void main(String[] args) {

        LiuDeHuaProxy proxy = new LiuDeHuaProxy();
        //獲得代理對(duì)象
        Person p = proxy.getProxy();
        //調(diào)用代理對(duì)象的sing方法
        String retValue = p.sing("冰雨");
        System.out.println(retValue);
        //調(diào)用代理對(duì)象的dance方法
        String value = p.dance("江南style");
        System.out.println(value);
    }
}

  運(yùn)行結(jié)果如下:

  Proxy類負(fù)責(zé)創(chuàng)建代理對(duì)象時(shí),如果指定了handler(處理器),那么不管用戶調(diào)用代理對(duì)象的什么方法,該方法都是調(diào)用處理器的invoke方法。
  由于invoke方法被調(diào)用需要三個(gè)參數(shù):代理對(duì)象、方法、方法的參數(shù),因此不管代理對(duì)象哪個(gè)方法調(diào)用處理器的invoke方法,都必須把自己所在的對(duì)象、自己(調(diào)用invoke方法的方法)、方法的參數(shù)傳遞進(jìn)來(lái)。

三、動(dòng)態(tài)代理應(yīng)用

  在動(dòng)態(tài)代理技術(shù)里,由于不管用戶調(diào)用代理對(duì)象的什么方法,都是調(diào)用開(kāi)發(fā)人員編寫(xiě)的處理器的invoke方法(這相當(dāng)于invoke方法攔截到了代理對(duì)象的方法調(diào)用)。并且,開(kāi)發(fā)人員通過(guò)invoke方法的參數(shù),還可以在攔截的同時(shí),知道用戶調(diào)用的是什么方法,因此利用這兩個(gè)特性,就可以實(shí)現(xiàn)一些特殊需求,例如:攔截用戶的訪問(wèn)請(qǐng)求,以檢查用戶是否有訪問(wèn)權(quán)限、動(dòng)態(tài)為某個(gè)對(duì)象添加額外的功能。

3.1、在字符過(guò)濾器中使用動(dòng)態(tài)代理解決中文亂碼

  在平時(shí)的JavaWeb項(xiàng)目開(kāi)發(fā)中,我們一般會(huì)寫(xiě)一個(gè)CharacterEncodingFilter(字符過(guò)濾器)來(lái)解決整個(gè)JavaWeb應(yīng)用的中文亂碼問(wèn)題,如下所示:

package me.gacl.web.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
* @ClassName: CharacterEncodingFilter
* @Description: 解決中文亂碼的字符過(guò)濾器
* @author: 孤傲蒼狼
* @date: 2014-9-14 下午10:38:12
*
*/
public class CharacterEncodingFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        //解決以Post方式提交的中文亂碼問(wèn)題
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}

  但是這種寫(xiě)法是沒(méi)有辦法解決以get方式提交中文參數(shù)時(shí)的亂碼問(wèn)題的,我們可以用如下的代碼來(lái)證明上述的解決中文亂碼過(guò)濾器只對(duì)以post方式提交中文參數(shù)時(shí)有效,而對(duì)于以get方式提交中文參數(shù)時(shí)無(wú)效

  jsp測(cè)試頁(yè)面如下:

<%@ page language="java" pageEncoding="UTF-8"%>
<%--引入jstl標(biāo)簽庫(kù) --%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML>
<html>
  <head>
    <title>使用字符過(guò)濾器解決解決get、post請(qǐng)求方式下的中文亂碼問(wèn)題</title>
  </head>
  <body>
       <%--使用c:url標(biāo)簽構(gòu)建url,構(gòu)建好的url存儲(chǔ)在servletDemo1變量中--%>
       <c:url value="/servlet/ServletDemo1" scope="page" var="servletDemo1">
           <%--構(gòu)建的url的附帶的中文參數(shù) ,參數(shù)名是:username,值是:孤傲蒼狼--%>
           <c:param name="username" value="孤傲蒼狼"></c:param>
       </c:url>
      <%--使用get的方式訪問(wèn) --%>
       <a href="${servletDemo1}" rel="external nofollow" >超鏈接(get方式請(qǐng)求)</a>
       <hr/>
       <%--使用post方式提交表單 --%>
       <form action="${pageContext.request.contextPath}/servlet/ServletDemo1" method="post">
           用戶名:<input type="text" name="username" value="孤傲蒼狼" />
           <input type="submit" value="post方式提交">
       </form>

  </body>
</html>

  處理請(qǐng)求的ServletDemo1代碼如下:

package me.gacl.web.controller;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ServletDemo1 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 接收參數(shù)
        String username = request.getParameter("username");
        // 獲取請(qǐng)求方式
        String method = request.getMethod();
        // 獲取輸出流
        PrintWriter out = response.getWriter();
        out.write("請(qǐng)求的方式:" + method);
        out.write("<br/>");
        out.write("接收到的參數(shù):" + username);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

  在web.xml中注冊(cè)上述的CharacterEncodingFilter和ServletDemo1

<filter>
      <filter-name>CharacterEncodingFilter</filter-name>
      <filter-class>me.gacl.web.filter.CharacterEncodingFilter</filter-class>
  </filter>

  <filter-mapping>
      <filter-name>CharacterEncodingFilter</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>

  <servlet>
    <servlet-name>ServletDemo1</servlet-name>
    <servlet-class>me.gacl.web.controller.ServletDemo1</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>ServletDemo1</servlet-name>
    <url-pattern>/servlet/ServletDemo1</url-pattern>
  </servlet-mapping>

  測(cè)試結(jié)果如下所示:

  從運(yùn)行結(jié)果可以看出,上述的過(guò)濾器的確是不能解決以get方式提交中文參數(shù)的亂碼問(wèn)題,下面使用動(dòng)態(tài)代理技術(shù)改造上述的過(guò)濾器,使之能夠解決以get方式提交中文參數(shù)的亂碼問(wèn)題,改造后的過(guò)濾器代碼如下:

package me.gacl.web.filter;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* @ClassName: CharacterEncodingFilter
* @Description: 解決中文亂碼的字符過(guò)濾器
* @author: 孤傲蒼狼
* @date: 2014-9-14 下午10:38:12
*
*/
public class CharacterEncodingFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {

        final HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        //解決以Post方式提交的中文亂碼問(wèn)題
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        //獲取獲取HttpServletRequest對(duì)象的代理對(duì)象
        ServletRequest requestProxy = getHttpServletRequestProxy(request);
        /**
         * 傳入代理對(duì)象requestProxy給doFilter方法,
         * 這樣用戶在使用request對(duì)象時(shí)實(shí)際上使用的是HttpServletRequest對(duì)象的代理對(duì)象requestProxy
         */
        chain.doFilter(requestProxy, response);
    }


    /**
    * @Method: getHttpServletRequestProxy
    * @Description: 獲取HttpServletRequest對(duì)象的代理對(duì)象
    * @Anthor:孤傲蒼狼
    *
    * @param request
    * @return HttpServletRequest對(duì)象的代理對(duì)象
    */
    private ServletRequest getHttpServletRequestProxy(final HttpServletRequest request){
        ServletRequest proxy  = (ServletRequest) Proxy.newProxyInstance(
                CharacterEncodingFilter.class.getClassLoader(),
                request.getClass().getInterfaces(),
                new InvocationHandler(){
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable {
                        //如果請(qǐng)求方式是get并且調(diào)用的是getParameter方法
                        if (request.getMethod().equalsIgnoreCase("get") && method.getName().equals("getParameter")) {
                            //調(diào)用getParameter方法獲取參數(shù)的值
                            String value = (String) method.invoke(request, args);
                            if(value==null){
                                return null;
                            }
                            //解決以get方式提交的中文亂碼問(wèn)題
                            return new String(value.getBytes("iso8859-1"),"UTF-8");
                        }else {
                            //直接調(diào)用相應(yīng)的方法進(jìn)行處理
                            return method.invoke(request, args);
                        }
                    }
                });
        //返回HttpServletRequest對(duì)象的代理對(duì)象
        return proxy;
    }

    @Override
    public void destroy() {

    }
}

  我們?cè)谶^(guò)濾器中使用動(dòng)態(tài)代理技術(shù)生成一個(gè)HttpServletRequest對(duì)象的代理對(duì)象requestProxy,然后把代理對(duì)象requestProxy進(jìn)行chain.doFilter(requestProxy, response)傳遞給用戶使用,這樣用戶實(shí)際上使用的就是HttpServletRequest對(duì)象的代理對(duì)象requestProxy。然而這一過(guò)程對(duì)于用戶來(lái)說(shuō)是透明的,用戶是不知道自己使用的HttpServletRequest對(duì)象是一個(gè)代理對(duì)象requestProxy,由于代理對(duì)象requestProxy和目標(biāo)對(duì)象HttpServletRequest具有相同的方法,當(dāng)用戶調(diào)用getParameter方法接收中文參數(shù)時(shí),實(shí)際上調(diào)用的就是代理對(duì)象requestProxy的invoke方法,因此我們就可以在invoke方法中就判斷當(dāng)前的請(qǐng)求方式以及用戶正在調(diào)用的方法,如果判斷當(dāng)前的請(qǐng)求方式是get方式并且用戶正在調(diào)用的是getParameter方法,那么我們就可以手動(dòng)處理get方式提交中文參數(shù)的中文亂碼問(wèn)題了。

  測(cè)試結(jié)果如下所示:

3.2、在字符過(guò)濾器中使用動(dòng)態(tài)代理壓縮服務(wù)器響應(yīng)的內(nèi)容后再輸出到客戶端

  壓縮過(guò)濾器的代碼如下:

package me.gacl.web.filter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.zip.GZIPOutputStream;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* @ClassName: GzipFilter
* @Description: 壓縮過(guò)濾器,將web應(yīng)用中的文本都經(jīng)過(guò)壓縮后再輸出到瀏覽器
* @author: 孤傲蒼狼
* @date: 2014-9-15 下午9:35:36
*
*/
public class GzipFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {

        final HttpServletRequest request = (HttpServletRequest) req;
        final HttpServletResponse response = (HttpServletResponse) resp;
        final ByteArrayOutputStream bout = new ByteArrayOutputStream();
        final PrintWriter pw = new PrintWriter(new OutputStreamWriter(bout,"UTF-8"));

        chain.doFilter(request, getHttpServletResponseProxy(response, bout, pw));
        pw.close();
        //拿到目標(biāo)資源的輸出
        byte result[] = bout.toByteArray();
        System.out.println("原始大小:" + result.length);

        ByteArrayOutputStream bout2 = new ByteArrayOutputStream();
        GZIPOutputStream gout = new GZIPOutputStream(bout2);
        gout.write(result);
        gout.close();

        //拿到目標(biāo)資源輸出的壓縮數(shù)據(jù)
        byte gzip[] = bout2.toByteArray();
        System.out.println("壓縮大?。? + gzip.length);

        response.setHeader("content-encoding", "gzip");
        response.setContentLength(gzip.length);
        response.getOutputStream().write(gzip);
    }

    /**
    * @Method: getHttpServletResponseProxy
    * @Description: 獲取HttpServletResponse對(duì)象的代理對(duì)象
    * @Anthor:孤傲蒼狼
    *
    * @param response
    * @param bout
    * @param pw
    * @return HttpServletResponse對(duì)象的代理對(duì)象
    */
    private ServletResponse getHttpServletResponseProxy(
            final HttpServletResponse response,
            final ByteArrayOutputStream bout,
            final PrintWriter pw) {

        return (ServletResponse) Proxy.newProxyInstance(GzipFilter.class.getClassLoader(),
                response.getClass().getInterfaces(),
                new InvocationHandler(){
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable {
                        if(method.getName().equals("getWriter")){
                            return pw;
                        }else if(method.getName().equals("getOutputStream")){
                            return new MyServletOutputStream(bout);
                        }else{
                            return method.invoke(response, args);
                        }
                    }
                });
    }

    @Override
    public void destroy() {

    }

    class MyServletOutputStream extends ServletOutputStream{

        private ByteArrayOutputStream  bout = null;
        public MyServletOutputStream(ByteArrayOutputStream  bout){
            this.bout = bout;
        }
        @Override
        public void write(int b) throws IOException {
            bout.write(b);
        }

    }
}

  在web.xml中注冊(cè)上述的GzipFilter

<filter>
      <description>配置壓縮過(guò)濾器</description>
      <filter-name>GzipFilter</filter-name>
      <filter-class>me.gacl.web.filter.GzipFilter</filter-class>
  </filter>

  <!--jsp文件的輸出的內(nèi)容都經(jīng)過(guò)壓縮過(guò)濾器壓縮后才輸出 -->
  <filter-mapping>
      <filter-name>GzipFilter</filter-name>
      <url-pattern>*.jsp</url-pattern>
      <!-- 配置過(guò)濾器的攔截方式-->
      <!-- 對(duì)于在Servlet中通過(guò)
          request.getRequestDispatcher("jsp頁(yè)面路徑").forward(request, response)
      方式訪問(wèn)的Jsp頁(yè)面的要進(jìn)行攔截 -->
      <dispatcher>FORWARD</dispatcher>
      <!--對(duì)于直接以URL方式訪問(wèn)的jsp頁(yè)面進(jìn)行攔截,過(guò)濾器的攔截方式默認(rèn)就是REQUEST-->
      <dispatcher>REQUEST</dispatcher>
  </filter-mapping>
  <!--js文件的輸出的內(nèi)容都經(jīng)過(guò)壓縮過(guò)濾器壓縮后才輸出 -->
  <filter-mapping>
      <filter-name>GzipFilter</filter-name>
      <url-pattern>*.js</url-pattern>
  </filter-mapping>
  <!--css文件的輸出的內(nèi)容都經(jīng)過(guò)壓縮過(guò)濾器壓縮后才輸出 -->
  <filter-mapping>
      <filter-name>GzipFilter</filter-name>
      <url-pattern>*.css</url-pattern>
  </filter-mapping>
  <!--html文件的輸出的內(nèi)容都經(jīng)過(guò)壓縮過(guò)濾器壓縮后才輸出 -->
  <filter-mapping>
      <filter-name>GzipFilter</filter-name>
      <url-pattern>*.html</url-pattern>
  </filter-mapping>

  GzipFilter過(guò)濾器會(huì)將*.jsp,*.js,*.css,*.html這些文件里面的文本內(nèi)容都經(jīng)過(guò)壓縮后再輸出到客戶端顯示。

到此這篇關(guān)于Java 代理(Proxy)的具體使用的文章就介紹到這了,更多相關(guān)Java 代理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java詳解AVL樹(shù)的應(yīng)用

    Java詳解AVL樹(shù)的應(yīng)用

    AVL樹(shù)是高度平衡的二叉樹(shù),它的特點(diǎn)是AVL樹(shù)中任何節(jié)點(diǎn)的兩個(gè)子樹(shù)的高度最大差別為1,本文主要給大家介紹了Java如何實(shí)現(xiàn)AVL樹(shù),需要的朋友可以參考下
    2022-07-07
  • SpringBoot和Swagger結(jié)合提高API開(kāi)發(fā)效率

    SpringBoot和Swagger結(jié)合提高API開(kāi)發(fā)效率

    這篇文章主要介紹了SpringBoot和Swagger結(jié)合提高API開(kāi)發(fā)效率的相關(guān)資料,需要的朋友可以參考下
    2017-09-09
  • 關(guān)于ireport中傳入list的處理方式

    關(guān)于ireport中傳入list的處理方式

    這篇文章主要介紹了關(guān)于ireport中傳入list的處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • shardingJdbc3.x?版本的分頁(yè)bug問(wèn)題解析

    shardingJdbc3.x?版本的分頁(yè)bug問(wèn)題解析

    這篇文章主要為大家介紹了shardingJdbc3.x?版本的分頁(yè)問(wèn)題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • mybatis 集合嵌套查詢和集合嵌套結(jié)果的區(qū)別說(shuō)明

    mybatis 集合嵌套查詢和集合嵌套結(jié)果的區(qū)別說(shuō)明

    這篇文章主要介紹了mybatis 集合嵌套查詢和集合嵌套結(jié)果的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • SpringBoot中的Spring Cloud Hystrix原理和用法詳解

    SpringBoot中的Spring Cloud Hystrix原理和用法詳解

    在Spring Cloud中,Hystrix是一個(gè)非常重要的組件,Hystrix可以幫助我們構(gòu)建具有韌性的分布式系統(tǒng),保證系統(tǒng)的可用性和穩(wěn)定性,在本文中,我們將介紹SpringBoot中的Hystrix,包括其原理和如何使用,需要的朋友可以參考下
    2023-07-07
  • 詳解JavaSE中抽象類與接口的定義及使用

    詳解JavaSE中抽象類與接口的定義及使用

    這篇文章主要為大家詳細(xì)介紹了JavaSe的抽象類和接口,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-07-07
  • Java8新特性:Lambda表達(dá)式之方法引用詳解

    Java8新特性:Lambda表達(dá)式之方法引用詳解

    這篇文章主要給大家介紹了關(guān)于Java8新特性:Lambda表達(dá)式之方法引用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • 詳解Spring Boot實(shí)戰(zhàn)之Filter實(shí)現(xiàn)使用JWT進(jìn)行接口認(rèn)證

    詳解Spring Boot實(shí)戰(zhàn)之Filter實(shí)現(xiàn)使用JWT進(jìn)行接口認(rèn)證

    本篇文章主要介紹了詳解Spring Boot實(shí)戰(zhàn)之Filter實(shí)現(xiàn)使用JWT進(jìn)行接口認(rèn)證,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-07-07
  • Java?synchronized與死鎖深入探究

    Java?synchronized與死鎖深入探究

    這篇文章主要介紹了Java?synchronized與死鎖,Java中提供了synchronized關(guān)鍵字,將可能引發(fā)安全問(wèn)題的代碼包裹在synchronized代碼塊中,表示這些代碼需要進(jìn)行線程同步
    2023-01-01

最新評(píng)論