【发布时间】:2019-09-23 21:49:02
【问题描述】:
我正在使用jdk1.8.0_221,我想根据调用两种不同类型的方法在超类的构造函数中加载特定配置。我正在寻求最佳实践,最好是一种方便的方法。
为了简化,我把代码情况模拟成如下sn-p:
package test;
public class A extends Z{
@Test
@Marker1
public void f1() {
Z.g();
}
@Test
@Marker2
public void f2() {
Z.g();
}
}
package test;
public class B extends Z{
@Test
@Marker1
public void f3() {
Z.g();
}
@Test
@Marker2
public void f4() {
Z.g();
}
}
package core;
public class Z{
public Z() {
//I want to determine here that which type of method calls this constructor
//The caller could be Marker1 or Marker2
//And based on the caller, load the corresponding configuration
}
public static void g(){
//some code goes here
}
}
注意1:有很多来自不同类的方法调用Z.g(),所以我无法使用类的显式名称来获取方法及其注解。
注意2:所有的配置都应该在Z的超类的构造函数中完成。
注意 3:g() 方法不一定是静态的。
我尝试了以下 sn-p 但getMethodName() 总是返回<init>:
public Z() throws NoSuchMethodException, ClassNotFoundException{
StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
StackTraceElement ste = stElements[3];// or stElements[2]
Class<?> aClass = Class.forName(ste.getClassName());
String methodName = ste.getMethodName();
Method method = aClass.getMethod(methodName);
Annotation[] annotations = aClass.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation.getClass().equals(Marker1.class)) {
//load conf1
break;
} else if (annotation.getClass().equals(Marker2.class)) {
//load conf2
break;
}
}
}
另外,我在 stackoverflow 和其他社区尝试了许多无法正常工作的解决方案。
【问题讨论】:
-
这不是一个好的设计。无论谁调用它,方法都应该表现相同。如果您想要不同的行为,请为您的方法提供一个指定该行为的参数。在您的情况下,您可能希望调用者将配置文件或配置对象的路径作为参数传递。
-
亲爱的@VGR,在我看来这是不可能的。我的类之间有很多复杂的关系,为了简化,我在这里忽略它们。事实上,A 类扩展了 Z,我所有的配置设置都应该在 Z 的构造函数中完成(相当于我的 g() 方法)。
-
值得花时间修复它。调试这样的代码将是一场噩梦。但如果你真的不能或不会改变它,我会建议创建一个全局静态对象。如果您使用多个线程,则需要使用同步或锁来保护这个全局对象。
-
如果在构造函数之前调用多个这样的函数怎么办?
-
但是无论如何,你需要在那个“g”方法中调用这个代码,然后像@VGR建议的那样将类型存储在一些静态状态。同样在您的代码中,您应该改用
method.isAnnotationPresent(Marker1.class)
标签: java reflection java-8 annotations stack-trace