那时候可以拦截对象方法调用并修改那些对象属性吗?
到目前为止我有什么
@Pointcut("execution(* java.net.HttpURLConnection.setRequestProperty(..))")
public void connectMethodCall() {
}
@Around("connectMethodCall()")
public Object onGetUrlConnection(ProceedingJoinPoint pjp) throws Throwable {
HttpURLConnection connection = (HttpURLConnection) pjp.proceed();
connection.setRequestProperty("header key", "header value");
return pjp.proceed();
}
在此示例中,我想设置连接头并将对象返回到执行点。编织在编译时完成。我尝试在此之后记录标题,但在@Around建议中没有设置标题。也不会引发任何错误。
答案 0 :(得分:1)
如果我正确理解了问题,那么有关如何获取 target 对象实例的后续问题的答案很简单:只需使用'use strict';
// combination origin-request, origin-response trigger to emulate the S3
// website hosting index document functionality, while using the REST
// endpoint for the bucket
// https://stackoverflow.com/a/54263794/1695906
const INDEX_DOCUMENT = 'index.html'; // do not prepend a slash to this value
const HTTP_REDIRECT_CODE = '302'; // or use 301 or another code if desired
const HTTP_REDIRECT_MESSAGE = 'Found';
exports.handler = (event, context, callback) => {
const cf = event.Records[0].cf;
if(cf.config.eventType === 'origin-request')
{
// if path ends with '/' then append INDEX_DOCUMENT before sending to S3
if(cf.request.uri.endsWith('/'))
{
cf.request.uri = cf.request.uri + INDEX_DOCUMENT;
}
// return control to CloudFront, to send request to S3, whether or not
// we modified it; if we did, the modified URI will be requested.
return callback(null, cf.request);
}
else if(cf.config.eventType === 'origin-response')
{
// is the response 403 or 404? If not, we will return it unchanged.
if(cf.response.status.match(/^40[34]$/))
{
// it's an error.
// we're handling a response, but Lambda@Edge can still see the attributes of the request that generated this response; so, we
// check whether this is a page that should be redirected with a trailing slash appended. If it doesn't look like an index
// document request, already, and it doesn't end in a slash, and doesn't look like a filename with an extension... we'll try that.
// This is essentially what the S3 web site endpoint does if you hit a nonexistent key, so that the browser requests
// the index with the correct relative path, except that S3 checks whether it will actually work. We are using heuristics,
// rather than checking the bucket, but checking is an alternative.
if(!cf.request.uri.endsWith('/' + INDEX_DOCUMENT) && // not a failed request for an index document
!cf.request.uri.endsWith('/') && // unlikely, unless this code is modified to pass other things through on the request side
!cf.request.uri.match(/[^\/]+\.[^\/]+$/)) // doesn't look like a filename with an extension
{
// add the original error to the response headers, for reference/troubleshooting
cf.response.headers['x-redirect-reason'] = [{ key: 'X-Redirect-Reason', value: cf.response.status + ' ' + cf.response.statusDescription }];
// set the redirect code
cf.response.status = HTTP_REDIRECT_CODE;
cf.response.statusDescription = HTTP_REDIRECT_MESSAGE;
// set the Location header with the modified URI
// just append the '/', not the "index.html" -- the next request will trigger
// this function again, and it will be added without appearing in the
// browser's address bar.
cf.response.headers['location'] = [{ key: 'Location', value: cf.request.uri + '/' }];
// not strictly necessary, since browsers don't display it, but remove the response body with the S3 error XML in it
cf.response.body = '';
}
}
// return control to CloudFront, with either the original response, or
// the modified response, if we modified it.
return callback(null, cf.response);
}
else // this is not intended as a viewer-side trigger. Throw an exception, visible only in the Lambda CloudWatch logs and a 502 to the browser.
{
return callback(`Lambda function is incorrectly configured; triggered on '${cf.config.eventType}' but expected 'origin-request' or 'origin-response'`);
}
};
参数绑定。快速浏览AspectJ documentation可能会向您显示,例如关于pointcut parameters的部分。我确实相信,与在这里提出问题相比,这样做要容易得多,也省时(也需要等待SO的答案)。但是无论如何,这是开发人员互相帮助的地方。所以我们开始:
不管您的MVCE示例代码对Google API所做的事情没有任何意义,我们只添加一行诊断输出,以验证方面是否确实添加了请求参数:
target()
然后使用此方面:
// (...)
urlConnection.connect();
// Just in order to check if the property has indeed been set in the aspect
System.out.println(urlConnection.getRequestProperty("From"));
OutputStream outputStream = urlConnection.getOutputStream();
// (...)
或者更紧凑一些,如果您不需要Poinctut可重复使用,因为您只在一个建议中使用它:
package de.scrum_master.aspect;
import java.net.HttpURLConnection;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class MyAspect {
@Pointcut("call(* java.net.HttpURLConnection.connect()) && target(connection)")
public void connectMethodCall(HttpURLConnection connection) {}
@Around("connectMethodCall(connection)")
public Object onGetUrlConnection(ProceedingJoinPoint pjp, HttpURLConnection connection) throws Throwable {
connection.setRequestProperty("From", "user@example.com");
return pjp.proceed();
}
}
控制台日志为:
@Aspect
public class MyAspect {
@Around("call(* java.net.HttpURLConnection.connect()) && target(connection)")
public Object onGetUrlConnection(ProceedingJoinPoint pjp, HttpURLConnection connection) throws Throwable {
connection.setRequestProperty("From", "user@example.com");
return pjp.proceed();
}
}
答案 1 :(得分:0)
我设法做到了这一点
@Pointcut("call(* java.net.URL.openConnection())")
public void connectMethodCall() {
}
@Around("connectMethodCall()")
public Object onGetUrlConnection(ProceedingJoinPoint pjp) throws Throwable {
HttpURLConnection connection = (HttpURLConnection) pjp.proceed();
connection.setRequestProperty("From", "user@example.com");
return connection;
}
并在此处使用它来设置标题
public static void main(String[] args) {
HttpURLConnection urlConnection;
String result;
try {
urlConnection = (HttpURLConnection) (new URL("http://www.google.com").openConnection());
urlConnection.setDoOutput(true);
urlConnection.setRequestProperty("Content-Type", "application/json");
urlConnection.setRequestProperty("Accept", "application/json");
urlConnection.setRequestMethod("POST");
urlConnection.setConnectTimeout(10000);
urlConnection.connect();
OutputStream outputStream = urlConnection.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));
writer.write("test");
writer.close();
outputStream.close();
int responseCode = urlConnection.getResponseCode();
if (responseCode == HttpsURLConnection.HTTP_OK) {
//Read
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), StandardCharsets.UTF_8));
String line;
StringBuilder sb = new StringBuilder();
while ((line = bufferedReader.readLine()) != null) {
sb.append(line);
}
bufferedReader.close();
result = sb.toString();
} else {
result = "false : " + responseCode;
}
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
有问题的代码的问题是,我拦截了返回void的方法调用,而在这种情况下pjp.proceed()实际上返回null。 (仍然不确定是否有办法从void方法切入点中找出调用对象吗?)。理想情况下,我会拦截urlConnection.connect();。并从切入点获取urlConnection对象。有办法吗?