如何使用Proxy模式及Java内建的动态代理机制?

1小时前 (04:11:57)阅读2回复0
wojiukan
wojiukan
  • 管理员
  • 注册排名1
  • 经验值2724075
  • 级别管理员
  • 主题544815
  • 回复0
楼主

如何在Java中利用动态代理模式与内置Java中的静态代理机制进行通信?动态代理就如同一个中间人,允许我们在不修改源类的情况下,为请求代理目标对象的行为进行一系列转换,包括打印日志、处理事务等,以下是一种使用静态代理(例如Java中的HttpURLConnection类)和动态代理机制(如Apache HTTP Client)的实践示例:

import org.apache.http.HttpMethod;
import org.apache.http.client.DefaultHttpClient;
import org.apache.http.client.methods.HttpGet;
public class HttpProxy {
    private static final String URL = "http://example.com";
    public static void main(String[] args) throws Exception {
        // 创建一个新的HttpClient实例
        DefaultHttpClient httpClient = new DefaultHttpClient();
        // 定义一个静态代理接口,其中包含HTTP方法调用和响应体处理逻辑
        @Override
        public Object getMethod(HttpMethod method, RequestEntity entity) throws IOException {
            System.out.println("原始方法名称: " + method);
            System.out.println("原始方法URL: " + entity.getRequestLine());
            return super.getMethod(method, entity);
        }
        // 创建一个动态代理对象,并注入代理代理接口
        HttpProxy proxy = new HttpProxy();
        proxy.setProxy(new HttpProxyInvocationHandler());
        // 调用原始方法并传入代理对象
        Object result = httpClient.executeMethod(new HttpGet(URL));
        if (result instanceof HttpResponse) {
            System.out.println("原始响应体内容:");
            System.out.println((HttpResponse) result);
        }
        else {
            throw new RuntimeException("原始响应体类型不是HttpResponse");
        }
    }
    // 动态代理代理接口实现
    private static class HttpProxyInvocationHandler implements InvocationHandler {
        private HttpClient httpClient;
        public HttpProxyInvocationHandler(HttpClient httpClient) {
            this.httpClient = httpClient;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 在这里实现代理对象对HTTP方法的实际操作,这里以发送GET请求为例
            System.out.println("执行方法: " + method.getName());
            HttpResponse httpResponse = (HttpResponse) method.invoke(httpClient, args);
            if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                System.out.println("响应体内容: " + httpResponse.getEntity().getContent());
            } else {
                System.err.println("响应体编码错误:" + httpResponse.getEntity().getCharacterEncoding());
            }
            return httpResponse;
        }
    }
}

Java内建的动态代理实现

要使用内置Java中的动态代理机制,我们首先需要创建一个实现了InvocationHandler接口的对象,该对象接收HttpURLConnection对象作为参数,然后在其中定义实际的方法,例如读取HTTP响应体或设置代理。

以下是一个简单的例子:

import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class DynamicProxy {
    private static ExecutorService executorService = Executors.newFixedThreadPool(5);
    public static void main(String[] args) throws Exception {
        URL url = new URL("https://example.com");
        // 创建一个空的InvocationHandler对象用于处理HTTP请求
        Object invocationHandler = () -> executorService.submit(() -> {
            // 创建一个简单的HttpGet请求,模拟调用原始方法
            HttpGet httpGet = new HttpGet(url);
            System.out.println("原始方法名称: " + httpGet.getMethod());
            System.out.println("原始方法URL: " + httpGet.getRequestLine());
            httpGet.sendHeaders(null, null);
            try (HttpURLConnection conn = (HttpURLConnection) httpGet.openConnection()) {
                // 设置请求头,添加代理信息
                conn.setRequestProperty("User-Agent", "MyCustomAgent");
                conn.setRequestProperty("Proxy-Host", "proxy-server.example.com");
                conn.setRequestProperty("Proxy-Port", 8080);
                conn.setRequestProperty("Proxy-Authorization", "Basic " + base64encode("username:password"));
                // 接收HTTP响应
                BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                String inputLine;
                StringBuffer response = new StringBuffer();
                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }
                in.close();
                return response.toString();
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        // 阻塞直到任务完成
        executorService.shutdown();
    }
    // Base64将字符串编码成Base64形式
    private static String base64encode(String s) {
        byte[] bytes = s.getBytes();
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(Base64.getEncoder().encodeToString(b));
        }
        return sb.toString();
    }
}

在这个例子中,我们创建了一个固定大小的线程池(ExecutorService),每个线程都会负责一次HTTP GET 请求并传递到动态代理接口中处理,代理对象会检查请求头(User-AgentProxy-Host),并将它们设置为代理服务器的IP地址和端口,代理对象还会尝试将请求头的值(包含用户名和密码)加密,然后将这些值添加到请求体(body 字符串)中。

代理对象将这个请求提交到HTTP服务器上,并接收其返回的HTTP响应,在处理完响应后,它将响应体的内容返回给调用者。

需要注意的是,这段代码假设你的目标对象(HTTP服务器的实例)已暴露了一个invoke()方法供外部调用,目标对象可能像这样:

public interface MyInterface {
    void doSomething();
}
public class MyClass {
    private final MyInterface myObject;
    public MyClass(MyInterface myObject) {
        this.myObject = myObject;
    }
    @Override
    public void doSomething() {
        System.out.println("This is my method called by the proxy.");
    }
}

在这个例子中,MyInterface 接收doSomething() 方法,而 MyClass 则暴露了这个方法,当客户端调用 myObject.doSomething() 时,实际上调用了 MyClass.myObject.doSomething() 方法,这是通过代理对象完成的。

0
回帖

如何使用Proxy模式及Java内建的动态代理机制? 期待您的回复!

取消
载入表情清单……
载入颜色清单……
插入网络图片

取消确定

图片上传中
编辑器信息
提示信息