我想编写一个切入点来匹配在带注释的字段上执行公共(public)方法。这似乎永远行不通。 get(@Important) 按您的预期工作(独立),但它当然会匹配对该字段的所有访问。我想将其限制为仅执行公共(public)方法。
这可能吗?我没有收到编译错误,但另一方面它似乎不起作用..
public class Counter {
private int count = 0;
public void add(int value) {
count = count + value;
}
}
public class Visitors {
@Important
Counter counter = new Counter()
public void increaseCounter() {
counter.add(1);
}
}
作品:
@Pointcut(value = "get(@Important * *)")
void testPointCut() {
}
不起作用:
@Pointcut(value = "get(@Important * *) && execution(public * *(..))")
void testPointCut() {
}
最佳答案
对于您想要的,没有开箱即用的 AspectJ 解决方案,因为如果您拦截任何对象的方法执行,则没有与可能指向这些对象的注释字段的连接。拦截注释类或注释方法的方法执行会更容易,但这不是您想要做的。
这里是一个小代码示例,向您展示了一种解决方法,但也说明了它的局限性:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Important {}
public class Counter {
private int count = 0;
public void add(int value) {
count = count + value;
}
@Override
public String toString() {
return super.toString() + "[count=" + count + "]";
}
}
public class Visitors {
@Important
Counter counter = new Counter();
public void increaseCounter() {
counter.add(1);
}
public static void main(String[] args) {
Visitors visitors = new Visitors();
visitors.increaseCounter();
visitors.counter.add(3);
System.out.println("visitors.counter = " + visitors.counter);
System.out.println("--------------------");
Counter unimportantCounter = new Counter();
unimportantCounter.add(11);
unimportantCounter.add(22);
System.out.println("unimportantCounter = " + unimportantCounter);
System.out.println("--------------------");
unimportantCounter = visitors.counter;
unimportantCounter.add(5);
System.out.println("visitors.counter = " + visitors.counter);
System.out.println("unimportantCounter = " + unimportantCounter);
System.out.println("--------------------");
visitors.counter = new Counter();
visitors.increaseCounter();
visitors.counter.add(3);
unimportantCounter.add(100);
System.out.println("visitors.counter = " + visitors.counter);
System.out.println("unimportantCounter = " + unimportantCounter);
System.out.println("--------------------");
Visitors otherVisitors = new Visitors();
otherVisitors.increaseCounter();
otherVisitors.counter.add(50);
System.out.println("otherVisitors.counter = " + otherVisitors.counter);
System.out.println("--------------------");
otherVisitors.counter = visitors.counter;
System.out.println("visitors.counter = " + visitors.counter);
System.out.println("otherVisitors.counter = " + otherVisitors.counter);
System.out.println("--------------------");
otherVisitors.counter = new Counter();
visitors.increaseCounter();
otherVisitors.increaseCounter();
System.out.println("visitors.counter = " + visitors.counter);
System.out.println("otherVisitors.counter = " + otherVisitors.counter);
}
}
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.aspectj.lang.Signature;
import org.aspectj.lang.SoftException;
public aspect ImportantMethodInterceptor {
Map<Object, Set<Object>> importantObjects = new HashMap<Object, Set<Object>>();
pointcut importantSetter(Object newValue, Object target) :
set(@Important * *) && args(newValue) && target(target);
pointcut unimportantSetter(Object newValue, Object target) :
!set(@Important * *) && set(* *) && !withincode(*.new(..)) && args(newValue) && target(target);
pointcut publicMethod(Object target) :
execution(public * *(..)) && target(target) && !execution(public String *..toString());
before(Object newValue, Object target) : importantSetter(newValue, target) {
Object oldValue = getFieldValue(thisJoinPoint.getSignature(), target);
System.out.println("Important object for target " + target + ": " + oldValue + " -> " + newValue);
synchronized (importantObjects) {
Set<Object> referrers;
if (oldValue != null) {
referrers = importantObjects.get(oldValue);
if (referrers != null) {
referrers.remove(target);
if (referrers.size() == 0)
importantObjects.remove(oldValue);
}
}
if (newValue != null) {
referrers = importantObjects.get(newValue);
if (referrers == null) {
referrers = new HashSet<Object>();
importantObjects.put(newValue, referrers);
}
referrers.add(target);
}
}
}
// before(Object newValue, Object target) : unimportantSetter(newValue, target) {
// Object oldValue = getFieldValue(thisJoinPoint.getSignature(), target);
// System.out.println("Unimportant object for target " + target + ": " + oldValue + " -> " + newValue);
// }
before(Object target) : publicMethod(target) {
synchronized (importantObjects) {
if (importantObjects.get(target) != null)
System.out.println("Important method on " + target + ": " + thisJoinPointStaticPart);
else
System.out.println("Unimportant method on " + target + ": " + thisJoinPointStaticPart);
}
}
private Object getFieldValue(Signature signature, Object target) {
try {
Field field = signature.getDeclaringType().getDeclaredField(signature.getName());
field.setAccessible(true);
return field.get(target);
}
catch (Exception e) { throw new SoftException(e); }
}
}
如您所见,我的方面保留了一组“重要对象”。更准确地说,它是一个 Map,其中键是“重要对象”,值是引用集。这是必要的,因为理论上多个引荐来源网址(例如 Visitors 对象)可以指向相同的“重要对象”(例如特定的 Counter)。在我的示例代码的早期版本中,当我刚刚在一个简单的集合中记录“重要对象”时,我可以选择永远不从集合中删除以前的“重要对象”,即使它们不再被引用,或者即使它们不再被引用也总是删除它们如果第二个推荐人仍然指向“重要对象”。 map 方法使我能够为每个“重要对象”记录多个引荐来源网址。
如果您运行 Visitors.main(String[]),您将看到以下输出(请取消注释 before ... : unimportantSetter ... 建议,如果您希望看到更多日志输出):
Important object for target Visitors@1404536: null -> Counter@7fdcde[count=0]
Unimportant method on Visitors@1404536: execution(void Visitors.increaseCounter())
Important method on Counter@7fdcde[count=0]: execution(void Counter.add(int))
Important method on Counter@7fdcde[count=1]: execution(void Counter.add(int))
visitors.counter = Counter@7fdcde[count=4]
--------------------
Unimportant method on Counter@18ac738[count=0]: execution(void Counter.add(int))
Unimportant method on Counter@18ac738[count=11]: execution(void Counter.add(int))
unimportantCounter = Counter@18ac738[count=33]
--------------------
Important method on Counter@7fdcde[count=4]: execution(void Counter.add(int))
visitors.counter = Counter@7fdcde[count=9]
unimportantCounter = Counter@7fdcde[count=9]
--------------------
Important object for target Visitors@1404536: Counter@7fdcde[count=9] -> Counter@1d6096[count=0]
Unimportant method on Visitors@1404536: execution(void Visitors.increaseCounter())
Important method on Counter@1d6096[count=0]: execution(void Counter.add(int))
Important method on Counter@1d6096[count=1]: execution(void Counter.add(int))
Unimportant method on Counter@7fdcde[count=9]: execution(void Counter.add(int))
visitors.counter = Counter@1d6096[count=4]
unimportantCounter = Counter@7fdcde[count=109]
--------------------
Important object for target Visitors@b02e7a: null -> Counter@bb6ab6[count=0]
Unimportant method on Visitors@b02e7a: execution(void Visitors.increaseCounter())
Important method on Counter@bb6ab6[count=0]: execution(void Counter.add(int))
Important method on Counter@bb6ab6[count=1]: execution(void Counter.add(int))
otherVisitors.counter = Counter@bb6ab6[count=51]
--------------------
Important object for target Visitors@b02e7a: Counter@bb6ab6[count=51] -> Counter@1d6096[count=4]
visitors.counter = Counter@1d6096[count=4]
otherVisitors.counter = Counter@1d6096[count=4]
--------------------
Important object for target Visitors@b02e7a: Counter@1d6096[count=4] -> Counter@5afd29[count=0]
Unimportant method on Visitors@1404536: execution(void Visitors.increaseCounter())
Important method on Counter@1d6096[count=4]: execution(void Counter.add(int))
Unimportant method on Visitors@b02e7a: execution(void Visitors.increaseCounter())
Important method on Counter@5afd29[count=0]: execution(void Counter.add(int))
visitors.counter = Counter@1d6096[count=5]
otherVisitors.counter = Counter@5afd29[count=1]
请仔细比较 main 中的代码与日志输出,以查看我测试了哪些常规和特殊情况。
正如我所说,该方法有其局限性:
int)或 String 时会发生什么情况,理论上可以作为“重要对象”多次出现,因为几个不相关的important 成员创建相等的对象。我也没有测试自动(取消)装箱会发生什么,请自行尝试。但是,如果您可以控制边界条件和用例,则可以做出明智的决定并按原样使用代码或使用代码的变体来实现您的需求。该代码可能有改进的潜力,我只是好奇并且想破解一个概念证明。
关于java - 用于匹配注释字段上的公共(public)方法调用的 Aspectj 切入点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15138770/
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg
如何匹配未被反斜杠转义的平衡定界符对(其本身未被反斜杠转义)(无需考虑嵌套)?例如对于反引号,我试过了,但是转义的反引号没有像转义那样工作。regex=/(?!$1:"how\\"#expected"how\\`are"上面的正则表达式不考虑由反斜杠转义并位于反引号前面的反斜杠,但我愿意考虑。StackOverflow如何做到这一点?这样做的目的并不复杂。我有文档文本,其中包括内联代码的反引号,就像StackOverflow一样,我想在HTML文件中显示它,内联代码用一些spanMaterial装饰。不会有嵌套,但转义反引号或转义反斜杠可能出现在任何地方。
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问
我将我的Rails应用程序部署到OpenShift,它运行良好,但我无法在生产服务器上运行“Rails控制台”。它给了我这个错误。我该如何解决这个问题?我尝试更新rubygems,但它也给出了权限被拒绝的错误,我也无法做到。railsc错误:Warning:You'reusingRubygems1.8.24withSpring.UpgradetoatleastRubygems2.1.0andrun`gempristine--all`forbetterstartupperformance./opt/rh/ruby193/root/usr/share/rubygems/rubygems
我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm
我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que
我有一个驼峰式字符串,例如:JustAString。我想按照以下规则形成长度为4的字符串:抓取所有大写字母;如果超过4个大写字母,只保留前4个;如果少于4个大写字母,则将最后大写字母后的字母大写并添加字母,直到长度变为4。以下是可能发生的3种情况:ThisIsMyString将产生TIMS(大写字母);ThisIsOneVeryLongString将产生TIOV(前4个大写字母);MyString将生成MSTR(大写字母+tr大写)。我设法用这个片段解决了前两种情况:str.scan(/[A-Z]/).first(4).join但是,我不太确定如何最好地修改上面的代码片段以处理最后一种
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www