- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想在调用非公共方法(栏)之后执行一些特定的操作。在另一个方法(foo)内部调用此方法。请注意,“ bar”和“ foo”都在第三方jar文件中定义。
我尝试在使用spring的面向方面的编程中使用@before
批注进行此操作。 However, I could not do that。
有人可以让我知道从jar文件中调用特定功能后如何执行特定操作(调用特定功能)吗?
最佳答案
正如Gervasio Amy所建议的那样,您需要使用AspectJ,而不是Spring AOP。如果您在Spring环境中,可以使用use AspectJ within Spring代替Spring AOP,这没有问题。如果尚未使用Spring,则不是开始使用AOP的理由,AspectJ可以在没有Spring的简单Java SE(或EE)版本中使用。
您需要做的是:
使用AspectJ编译器ajc编译Aspect代码。 (您还可以使用它编译整个应用程序,因为它也是Java编译器javac的替代。)
创建一个加载时编织配置aop.xml,以使您的应用程序可以在类加载期间将方面代码实时地编织到第三方库中。我要由您自己决定如何执行此操作,只需检查LTW documentation。
通过-javaagent:/path/to/aspectjweaver.jar
开关在命令行上使用AspectJ编织代理启动JVM或应用程序服务器。
现在您想要的外观是什么样的?让我们尝试一些变体并完善切入点,以使其匹配。但是首先让我们通过一些示例第三方类(Foo
和Bar
)和一些驱动程序应用程序(Application
)为实验做一个准备:
示例应用程序和第三方代码:
package my.thirdparty.application;
public class Foo {
void blah() {
zot();
}
void foo() {}
void zot() {
foo();
}
}
package my.thirdparty.application;
public class Bar {
Foo foo = new Foo();
public void doSomething() {
someMethod();
bar();
anotherMethod();
}
private void someMethod() {
foo.blah();
foo.foo();
foo.zot();
}
private void bar() {
foo.blah();
// This is the only call we want to intercept, 'foo' called by 'bar'
foo.foo();
foo.zot();
anotherMethod();
}
private void anotherMethod() {
foo.blah();
foo.foo();
foo.zot();
}
}
package de.scrum_master.app;
import my.thirdparty.application.Bar;
public class Application {
public static void main(String[] args) {
new Bar().doSomething();
}
}
Application.main
创建一个
Bar
对象并调用公共方法
Bar.doSomething
。该方法触发了一系列其他方法调用,其中一些最终以
Foo.foo
间接调用,但是从
Bar.bar
到
Foo.foo
仅进行了一个直接调用(根据我们的兴趣,根据你的问题)。
Foo.foo
的所有调用
package de.scrum_master.aspect;
import my.thirdparty.application.Foo;
import my.thirdparty.application.Bar;
public aspect MethodInterceptor {
pointcut allCalls() :
call(* Foo.foo(..));
Object around(Foo fooObject) : allCalls() && target(fooObject) {
System.out.println(thisJoinPointStaticPart + " -> caller = " + thisEnclosingJoinPointStaticPart);
//new Exception("printing stack trace").printStackTrace(System.out);
//System.out.println();
return proceed(fooObject);
}
}
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.someMethod())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.bar())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.anotherMethod())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.anotherMethod())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
Foo.foo
的所有调用。但是,如何将侦听限制为在
cflow
的控制流(
Bar.bar
)中进行的那些调用呢?
Foo.foo
直接(在内部)对
Bar.bar
进行的调用
package de.scrum_master.aspect;
import my.thirdparty.application.Foo;
import my.thirdparty.application.Bar;
public aspect MethodInterceptor {
pointcut indirectCalls() :
call(* Foo.foo(..)) && cflow(execution(* Bar.bar(..)));
Object around(Foo fooObject) : indirectCalls() && target(fooObject) {
System.out.println(thisJoinPointStaticPart + " -> caller = " + thisEnclosingJoinPointStaticPart);
//new Exception("printing stack trace").printStackTrace(System.out);
//System.out.println();
return proceed(fooObject);
}
}
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.bar())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.anotherMethod())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
Foo.zot
和
Bar.anotherMethod
这样的调用者又会如何发生呢?将控制流限制为
Bar.bar
?答案很简单:这两个方法也被
Bar.bar
直接或间接调用,因此位于控制流中。如果我们检查调用堆栈,我们会更清楚地看到这一点(只需取消注释代码中的两个日志语句):
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
java.lang.Exception: printing stack trace
at my.thirdparty.application.Foo.foo_aroundBody1$advice(Foo.java:22)
at my.thirdparty.application.Foo.zot(Foo.java:11)
at my.thirdparty.application.Foo.blah(Foo.java:5)
at my.thirdparty.application.Bar.bar(Bar.java:19)
at my.thirdparty.application.Bar.doSomething(Bar.java:8)
at de.scrum_master.app.Application.main(Application.java:7)
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.bar())
java.lang.Exception: printing stack trace
at my.thirdparty.application.Bar.foo_aroundBody3$advice(Bar.java:22)
at my.thirdparty.application.Bar.bar(Bar.java:21)
at my.thirdparty.application.Bar.doSomething(Bar.java:8)
at de.scrum_master.app.Application.main(Application.java:7)
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
java.lang.Exception: printing stack trace
at my.thirdparty.application.Foo.foo_aroundBody1$advice(Foo.java:22)
at my.thirdparty.application.Foo.zot(Foo.java:11)
at my.thirdparty.application.Bar.bar(Bar.java:22)
at my.thirdparty.application.Bar.doSomething(Bar.java:8)
at de.scrum_master.app.Application.main(Application.java:7)
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
java.lang.Exception: printing stack trace
at my.thirdparty.application.Foo.foo_aroundBody1$advice(Foo.java:22)
at my.thirdparty.application.Foo.zot(Foo.java:11)
at my.thirdparty.application.Foo.blah(Foo.java:5)
at my.thirdparty.application.Bar.anotherMethod(Bar.java:27)
at my.thirdparty.application.Bar.bar(Bar.java:23)
at my.thirdparty.application.Bar.doSomething(Bar.java:8)
at de.scrum_master.app.Application.main(Application.java:7)
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.anotherMethod())
java.lang.Exception: printing stack trace
at my.thirdparty.application.Bar.foo_aroundBody5$advice(Bar.java:22)
at my.thirdparty.application.Bar.anotherMethod(Bar.java:28)
at my.thirdparty.application.Bar.bar(Bar.java:23)
at my.thirdparty.application.Bar.doSomething(Bar.java:8)
at de.scrum_master.app.Application.main(Application.java:7)
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
java.lang.Exception: printing stack trace
at my.thirdparty.application.Foo.foo_aroundBody1$advice(Foo.java:22)
at my.thirdparty.application.Foo.zot(Foo.java:11)
at my.thirdparty.application.Bar.anotherMethod(Bar.java:29)
at my.thirdparty.application.Bar.bar(Bar.java:23)
at my.thirdparty.application.Bar.doSomething(Bar.java:8)
at de.scrum_master.app.Application.main(Application.java:7)
Bar.bar
。因此,
cflow
切入点已经完成了我们告诉它的操作。
Foo
,而且还将调用方(此)对象限制为
Bar
?
Foo.foo
直接(内)进行的
Bar.bar
调用,但肯定是来自
Bar
对象
package de.scrum_master.aspect;
import my.thirdparty.application.Foo;
import my.thirdparty.application.Bar;
public aspect MethodInterceptor {
pointcut callsFromBar(Bar barObject) :
call(* Foo.foo(..)) && cflow(execution(* Bar.bar(..))) && this(barObject);
Object around(Foo fooObject, Bar barObject) : callsFromBar(barObject) && target(fooObject) {
System.out.println(thisJoinPointStaticPart + " -> caller = " + thisEnclosingJoinPointStaticPart);
new Exception("printing stack trace").printStackTrace(System.out);
System.out.println();
return proceed(fooObject, barObject);
}
}
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.bar())
java.lang.Exception: printing stack trace
at my.thirdparty.application.Bar.foo_aroundBody3$advice(Bar.java:22)
at my.thirdparty.application.Bar.bar(Bar.java:21)
at my.thirdparty.application.Bar.doSomething(Bar.java:8)
at de.scrum_master.app.Application.main(Application.java:7)
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.anotherMethod())
java.lang.Exception: printing stack trace
at my.thirdparty.application.Bar.foo_aroundBody5$advice(Bar.java:22)
at my.thirdparty.application.Bar.anotherMethod(Bar.java:28)
at my.thirdparty.application.Bar.bar(Bar.java:23)
at my.thirdparty.application.Bar.doSomething(Bar.java:8)
at de.scrum_master.app.Application.main(Application.java:7)
Bar.anotherMethod
仍然是不需要的,因为它只是由
Bar.bar
间接触发的,我们的目标是仅截获直接呼叫。好吧,接下来让我们变得更加精确:
Foo.foo
直接进行的对
Bar.bar
的调用,不允许间接访问
package de.scrum_master.aspect;
import my.thirdparty.application.Foo;
import my.thirdparty.application.Bar;
public aspect MethodInterceptor {
pointcut directCalls(Bar barObject) :
call(* Foo.foo(..)) && cflow(execution(* Bar.bar(..))) && this(barObject) &&
if("bar".equals(thisEnclosingJoinPointStaticPart.getSignature().getName()));
Object around(Foo fooObject, Bar barObject) : directCalls(barObject) && target(fooObject) {
System.out.println(thisJoinPointStaticPart + " -> caller = " + thisEnclosingJoinPointStaticPart);
new Exception("printing stack trace").printStackTrace(System.out);
System.out.println();
return proceed(fooObject, barObject);
}
}
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.bar())
java.lang.Exception: printing stack trace
at my.thirdparty.application.Bar.foo_aroundBody3$advice(Bar.java:22)
at my.thirdparty.application.Bar.bar(Bar.java:21)
at my.thirdparty.application.Bar.doSomething(Bar.java:8)
at de.scrum_master.app.Application.main(Application.java:7)
call(* Foo.foo(..))
-仅呼叫
Foo.foo
cflow(execution(* Bar.bar(..)))
-仅在控制流中执行
Bar.bar
this(barObject)
-调用者必须是Bar对象
target(fooObject)
-被调用方必须是Foo对象
if("bar".equals(thisEnclosingJoinPointStaticPart.getSignature().getName()))
-动态运行时条件检查直接调用者的方法名称是否真的
bar
关于java - 在另一个方法中调用一个方法后执行一些操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33909874/
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!