我不确定您到底想要实现什么,所以我提出了两种替代解决方案。
首先,让我们创建一些应用程序类,以获得完全可编译的示例:
package de.scrum_master.app;
public interface AccountSummary {
void doSomething();
}
package de.scrum_master.app;
public class LegacyAccountSummary implements AccountSummary {
@Override
public void doSomething() {
System.out.println("I am " + this);
}
}
package de.scrum_master.app;
public class NewAccountSummary implements AccountSummary {
@Override
public void doSomething() {
System.out.println("I am " + this);
}
}
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectServiceClientAdapter {
Class<?> legacyImpl();
Class<?> newImpl();
}
package de.scrum_master.app;
public class PoolableBusinessLogic {
@InjectServiceClientAdapter(legacyImpl = LegacyAccountSummary.class, newImpl = NewAccountSummary.class)
private AccountSummary accountSummary;
public void foo() {
accountSummary.doSomething();
}
public void bar() {
System.out.println("Account summary is " + accountSummary);
}
}
现在我们需要一个入口点:
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
PoolableBusinessLogic businessLogic = new PoolableBusinessLogic();
businessLogic.foo();
businessLogic.bar();
System.out.println();
}
}
}
显然这会产生错误,因为成员 accountSummary 尚未初始化:
Exception in thread "main" java.lang.NullPointerException
at de.scrum_master.app.PoolableBusinessLogic.foo(PoolableBusinessLogic.java:8)
at de.scrum_master.app.Application.main(Application.java:7)
现在我们有两种选择,具体取决于您想要实现的目标:
选项 A:动态注入
场景:对于每个字段访问(即使在同一个PoolableBusinessLogic 实例中)动态决定要返回什么类型的对象实例。在此示例中,我将随机化以模拟另一个 if-else 标准。
顺便说一句,我希望我可以使用更具表现力的原生 AspectJ 语法。您可以轻松地将方面转换为注释样式。
package de.scrum_master.aspect;
import java.util.Random;
import org.aspectj.lang.SoftException;
import de.scrum_master.app.InjectServiceClientAdapter;
public aspect DynamicInjectionAspect {
private static final Random RANDOM = new Random();
Object around(InjectServiceClientAdapter adapterAnn) :
get(* *) && @annotation(adapterAnn)
{
try {
Class<?> implClass = RANDOM.nextBoolean() ? adapterAnn.legacyImpl() : adapterAnn.newImpl();
return implClass.newInstance();
} catch (Exception e) {
throw new SoftException(e);
}
}
}
这会产生以下输出:
I am de.scrum_master.app.LegacyAccountSummary@4d9cfefb
Account summary is de.scrum_master.app.NewAccountSummary@7e28388b
I am de.scrum_master.app.NewAccountSummary@2986e62
Account summary is de.scrum_master.app.LegacyAccountSummary@6576e542
I am de.scrum_master.app.NewAccountSummary@60c58418
Account summary is de.scrum_master.app.LegacyAccountSummary@4763754a
I am de.scrum_master.app.NewAccountSummary@52a971e3
Account summary is de.scrum_master.app.NewAccountSummary@7274187a
I am de.scrum_master.app.LegacyAccountSummary@23f32c4a
Account summary is de.scrum_master.app.LegacyAccountSummary@31e0c0b6
如您所见,在五个输出组中的每一个(即对于每个 PoolableBusinessLogic 实例)都有不同的帐户摘要对象 ID,有时(并非总是)甚至不同的类名。
选项 B:静态注入
场景:每个PoolableBusinessLogic 实例动态决定如果其值为null,则静态分配给带注释的成员的对象实例类型。之后,不再覆盖该成员,而是返回先前初始化的值。我将再次进行随机化以模拟另一个 if-else 标准。
注意:不要忘记停用第一个方面,例如通过将if(false) && 添加到其切入点。否则这两个方面会相互冲突。
package de.scrum_master.aspect;
import java.lang.reflect.Field;
import java.util.Random;
import org.aspectj.lang.SoftException;
import de.scrum_master.app.InjectServiceClientAdapter;
public aspect StaticInjectionAspect {
private static final Random RANDOM = new Random();
before(InjectServiceClientAdapter adapterAnn, Object targetObj) :
get(* *) && @annotation(adapterAnn) && target(targetObj)
{
try {
Field field = targetObj.getClass().getDeclaredField(thisJoinPoint.getSignature().getName());
field.setAccessible(true);
if (field.get(targetObj) != null)
return;
Class<?> implClass = RANDOM.nextBoolean() ? adapterAnn.legacyImpl() : adapterAnn.newImpl();
field.set(targetObj,implClass.newInstance());
} catch (Exception e) {
throw new SoftException(e);
}
}
}
这有点难看,因为它涉及使用反射来查找成员字段。因为它可能是(在我们的示例中确实是)私有的,我们需要在对其进行任何操作之前使其可访问。
这会产生以下输出:
I am de.scrum_master.app.NewAccountSummary@20d1fa4
Account summary is de.scrum_master.app.NewAccountSummary@20d1fa4
I am de.scrum_master.app.NewAccountSummary@2b984909
Account summary is de.scrum_master.app.NewAccountSummary@2b984909
I am de.scrum_master.app.LegacyAccountSummary@1ae3043b
Account summary is de.scrum_master.app.LegacyAccountSummary@1ae3043b
I am de.scrum_master.app.LegacyAccountSummary@2e2acb47
Account summary is de.scrum_master.app.LegacyAccountSummary@2e2acb47
I am de.scrum_master.app.LegacyAccountSummary@7b87b9fe
Account summary is de.scrum_master.app.LegacyAccountSummary@7b87b9fe
现在输出看起来不同了:在五个输出组中的每一个中(即对于每个PoolableBusinessLogic 实例),两个输出行都显示完全相同的对象 ID。