让我们用数据库驱动的方法和 Spring AOP 来解决这个问题。
您有数百条规则,不希望使用像void method1() { if (!rule1) return; .. do method } 这样的样板代码污染当前代码,或者必须创建所有基于规则的方法都必须实现的额外接口。
Spring AOP 提供了一种保持当前基础的方法,而是通过拦截方法(通过代理)来确定该方法是否应该运行。您只需编写一次代理代码,唯一持续的要求就是使用新规则使数据库保持最新。
第 1 步:构建将方法名称映射到布尔值的数据库模式
method_name VARCHAR(100), is_rule_active tinyint(1);
每条规则会有一行。该行将包含方法名称(在 java 代码中显示)和一个布尔值 true=active,false=not active。
第 2 步:构建数据库接口 (DAO)
您需要对数据库进行简单的抽象。比如:
public interface RuleSelectionInterface {
boolean isRuleActive(String methodName);
}
实现将是基本的 DAO 代码,它将查询 method_name 等于 methodName 的行。为简单起见和演示,我使用了 Map:
@Repository
public class RuleSelectionImpl implements RuleSelectionInterface {
Map<String, Boolean> rules;
public RuleSelectionImpl() {
rules = new HashMap<>();
rules.put("rule1Method", true);
rules.put("rule2Method", false);
}
@Override
public boolean isRuleActive(String methodName) {
if (!rules.containsKey(methodName))
return false;
return rules.get(methodName);
}
}
第 3 步:创建 Spring AOP 方面
创建切面来拦截方法调用,并确定何时执行调用。
要允许继续执行或中止执行,请使用@Around 通知,该通知将传递到执行点(通过ProceedingJoinPoint),您可以从中中止(代理方法简单地返回)或使用proceed 方法运行代码。
这里有一些选择应该拦截哪些方法(这是通过定义切入点来完成的)。此示例将拦截名称以rule 开头的方法:
@Around("execution(* rule*(..))")
你可以拦截所有的方法,或者基于命名模式的方法等。关于如何创建切入点来拦截方法的详细了解请参考Spring AOP
这是 AOP 代码,在方法拦截时调用,它使用您的数据库规则接口来查找该方法名称的规则是否处于活动状态:
@Aspect
@Component
public class RuleAspects {
@Autowired
private RuleSelectionInterface rulesSelectionService;
@Around("execution(* rule*(..))")
public void ruleChooser(ProceedingJoinPoint jp) throws Throwable
{
Signature sig = jp.getSignature();
System.out.println("Join point signature = "+sig);
String methodName = sig.getName();
if (rulesSelectionService.isRuleActive(methodName))
jp.proceed();
else
System.out.println("Method was aborted (rule is false)");
}
}
示例用法:
我用两种方法创建了一个简单的类(但是无论您有多少基于规则的方法的类/方法,这种方法都有效)。
@Component
public class MethodsForRules {
public void rule1Method() {
System.out.println("Rule 1 method");
}
public void rule2Method() {
System.out.println("Rule 2 method");
}
}
您会注意到在 Map 中 rule1Method 设置为 true,而 rule2Method 设置为 false。
当代码尝试运行 rule1Method 和 rule2Method 时:
MethodsForRules r; // Is a Spring managed bean.
r.rule1Method();
r.rule2Method();
产生以下输出:
Join point signature = void com.stackoverflow.aoparound.demo.MethodsForRules.rule1Method()
Rule 1 method <- Here is the method running
Join point signature = void
com.stackoverflow.aoparound.demo.MethodsForRules.rule2Method()
Method was aborted (rule is false) <- Here the method is aborted
总结:
这个演示展示了如何使用 Spring AOP 结合基于规则的接口来拦截方法(通过使用代理),检查被拦截的方法名称,查找该方法的活动状态,以及运行该方法,或中止它。