如何使用Proxy模式及Java内建的动态代理机制?
如何在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-Agent 和 Proxy-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() 方法,这是通过代理对象完成的。
