AspectJ可以穿过sun.net。*包吗?

我正在使用AspectJ来拦截java.net.Socket调用。

我创造了非常简单的方面

after(): call(* java.net.Socket.connect(..)) { System.out.println("Connect intercepted!"); } 

和aop.xml

        

当调用堆栈是这样的,那么我可以看到控制台输出:

 java.lang.Exception at com.iggroup.lightstreamer.nwtp.SocketExceptionLoggingAspect.ajc$after$com_iggroup_lightstreamer_nwtp_SocketExceptionLoggingAspect$2$6e16217c(SocketExceptionLoggingAspect.aj:39) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:337) at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:134) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353) at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184) at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55) at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:91) at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48) at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:596) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:557) at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:475) at com.iggroup.lightstreamer.nwtp.users.SsoRestClientImpl.lambda$0(SsoRestClientImpl.java:68) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) 

但是当调用堆栈是这样的时候没有注销:

 Caused by: java.net.ConnectException: Connection refused: connect at java.net.DualStackPlainSocketImpl.connect0(Native Method) ~[na:1.8.0_65] at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79) ~[na:1.8.0_65] at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[na:1.8.0_65] at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) ~[na:1.8.0_65] at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) ~[na:1.8.0_65] at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172) ~[na:1.8.0_65] at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[na:1.8.0_65] at java.net.Socket.connect(Socket.java:589) ~[na:1.8.0_65] at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:668) ~[na:1.8.0_65] at sun.security.ssl.BaseSSLSocketImpl.connect(BaseSSLSocketImpl.java:173) ~[na:1.8.0_65] at sun.net.NetworkClient.doConnect(NetworkClient.java:180) ~[na:1.8.0_65] at sun.net.www.http.HttpClient.openServer(HttpClient.java:432) ~[na:1.8.0_65] at sun.net.www.http.HttpClient.openServer(HttpClient.java:527) ~[na:1.8.0_65] at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:781) ~[na:1.8.0_65] at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:647) ~[na:1.8.0_65] at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1536) ~[na:1.8.0_65] at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441) ~[na:1.8.0_65] at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254) ~[na:1.8.0_65] at com.lightstreamer.ls_client.HttpProvider.connectAndGetAnswer(HttpProvider.java:244) ~[lightstreamer-se-client-2.5.2-1110.jar:na] 

我想知道是不是因为sun.net.*软件包由于某些安全管理器的限制而没有加载时编织。

有谁知道如何使用sun.net.*包?

更新1

我确认我可以拦截ls_client.HttpProvider.connectAndGetAnswer调用,但不能拦截它ls_client.HttpProvider.connectAndGetAnswer调用( sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream )。

sun.*可以与AspectJ编织吗?

我还没有看到成功设置JRE(引导程序)类的加载时编织。 如果您需要这个用于调试目的,我将使用JRE类的构建时编织。

这个简短的片段将为您编织JRE jar并将编织的类放在一个输出jar中。 它需要org.aspectj/aspectjtools作为依赖项。 它还会跳过JRE的ext子文件夹中的jar文件,因为这些jar文件将包含一些重复的类,并且创建包含重复文件的jar文件将导致错误。 我也从较新的JRE版本中跳过jfxswt.jar ,因为它会因为缺少类而失败。

 String aspectFileName = "src/main/java/pckg/AspectName.aj"; String jreLibPath = "c:/Program Files/Java/jdk1.8.0_40/jre/lib"; String outputJar = "weavedjre.jar"; List jars = new ArrayList<>(); File dir = new File(jreLibPath); File[] files = dir.listFiles(); for (File file : files) { if (file.isFile() && file.getName().endsWith(".jar") && !file.getName().endsWith("jfxswt.jar")) { jars.add(file.getAbsolutePath()); } } List ajcArgs = new ArrayList<>(Arrays.asList("-showWeaveInfo")); for (String jar : jars) { ajcArgs.add("-inpath"); ajcArgs.add(jar); } ajcArgs.add(aspectFileName); ajcArgs.add("-outjar"); ajcArgs.add(outputJar); org.aspectj.tools.ajc.Main.main(ajcArgs.toArray(new String[] {})); 

然后使用以下VM参数运行程序以使用编织的JRE类(前置于引导类路径):

 -verbose:class -Xbootclasspath/p:path_to/weavedjre.jar 

或者在Eclipse启动配置中:

 -verbose:class -Xbootclasspath/p:${resource_loc:/project_name/weavedjre.jar} 

我也添加了类加载VM参数的详细日志记录,因此您可以看到从哪里加载了哪个类。

Nándor是对的。 我不能在JRE库上执行LTW,因为它们在引导类路径上并且在AspectJ编织它们之前加载。 我不得不进行编译时编织并替换默认库。

这是我做的:

你需要的文件

 workspace |- Aspect.aj |- rt.jar |- aspectjrt-1.8.7.jar |- aspectjtools-1.8.7.jar 

Aspect.aj

 package java.net; import sun.misc.SharedSecrets; import java.io.FileDescriptor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public aspect Aspect { private static Class dualStackPlainSocketImplClass; private static Method localPort0; static { try { dualStackPlainSocketImplClass = Class.forName("java.net.DualStackPlainSocketImpl"); localPort0 = dualStackPlainSocketImplClass.getDeclaredMethod("localPort0", Integer.TYPE); localPort0.setAccessible(true); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } pointcut connect(java.net.DualStackPlainSocketImpl s): target(s) && execution(* java.net.DualStackPlainSocketImpl.socketConnect(..)); after(DualStackPlainSocketImpl s) throwing (Exception e): connect(s) { try { Field fdf = dualStackPlainSocketImplClass.getSuperclass().getSuperclass().getDeclaredField("fd"); fdf.setAccessible(true); FileDescriptor fd = (FileDescriptor) fdf.get(s); int nativeFd = SharedSecrets.getJavaIOFileDescriptorAccess().get(fd); int localPort = (int) localPort0.invoke(dualStackPlainSocketImplClass, nativeFd); System.out.format("[local port=%s][exception=%s]\n", localPort, e.getMessage()); } catch (InvocationTargetException e1) { e1.printStackTrace(); } catch (IllegalAccessException e1) { e1.printStackTrace(); } catch (NoSuchFieldException e1) { e1.printStackTrace(); } catch (NullPointerException e1) { e1.printStackTrace(); } } } 

方面文件非常简单,棘手的一点是如何通过reflection获取本地端口。

注意package java.net; 很重要,因为有些类/方法受到保护。


然后从工作区运行

 java -cp "aspectjrt-1.8.7.jar;aspectjtools-1.8.7.jar" org.aspectj.tools.ajc.Main -1.8 -inpath rt.jar Aspect.aj -outjar newrt.jar 

你会得到一个newrt.jar


用它来运行你的程序,

 java -cp  -Xbootclasspath/p:  

-Xbootclasspath/pnewrt.jar到引导类路径并覆盖JDK默认值。