简而言之:我想根据某些条件允许/禁止执行Java方法。什么是最好的解决方案/机制/技术?
长问题,通过一个(诚然愚蠢的)例子:
假设我在车辆控制器中有多种方法,例如void openWindow(Window w)
,void openRoof()
,void keepSpeed(double speedKmh)
。如果下雨,则不应调用openRoof
,我们希望建立一个机制来确保它。同样,如果速度低于60公里/小时,则禁止keepSpeed
,如果下雨很多,或openWindow
,如果速度超过100 km/h
,则为@ForbidIf('default:rain') openWindow();
@ForbidIf('default:speedBelow(60)') keepSpeed();
@ForbidIf('default:speedAbove(100)', 'custom:rainsALot') openWindow();
。
由于访问雨/速度传感器需要几行代码,并且这些条件在任何地方使用,我不想在方法体中使用使用断言或条件,但我宁愿使它们易于使用由域开发人员。此外,我希望将安全问题与打开窗口等的实际逻辑分开。更复杂的自定义条件也应该易于配置。
例如,我想要这个:
{{1}}
如果有帮助,这个应用程序是一个Spring驱动的客户端 - 服务器应用程序。
答案 0 :(得分:2)
你可以使用一个简单的Spring AOP方面,像这样(未经测试):
@Aspect
public class SecurityAspect{
@Pointcut("execution(@ForbidIf * *(*))")
public void annotatedMethodCalled(){}
@Before("annotatedMethodCalled() && @target(annotation) && target(bean)")
public void beforeRestrictedMethodCall(
final ForbidIf annotation, final Object bean){
final Expression expression =
new SpelExpressionParser().parseExpression(annotation.value());
if(!Boolean.TRUE.equals(expression.getValue(bean))){
throw new IllegalArgumentException();
}
}
}
答案 1 :(得分:1)
类似的东西在Spring Security中实现为expression based access control,但我认为它不适合你的情况。
但是,通过创建可以针对特定上下文评估SpEL expressions的方面,从头开始实现类似功能应该很容易。
答案 2 :(得分:1)
OP,评论Andreas_D的回答:“如果禁止执行,我想要引发运行时异常。在这种情况下,如果条件为false,则意味着在当前情况下应该从未调用此方法。 “
出了什么问题:
public void openWindow() {
if (itsRaining()) {
throw new IllegalStateException("Window should not open if it's raining");
}
}
?我的意思是,做一个注释实际上是相同的,只是更复杂(特别是如果你的方法的条件增加复杂性,例如,如果窗口不下雨,如果下雨,下雪,车速> 100 KPh,风速度> 6,温度低于冰点等)。
当然,我也可能只是忽略了这一点。只是想暗示,过度思考,工程化或复杂化问题不是唯一可行的途径。当然,不想说使用AOP或注释是过度思考/工程/并发症是一个问题。可能也是基于简化示例的这篇文章。
答案 3 :(得分:0)
这是一个有趣的想法,虽然我看到了一些真正的问题。您可以注释方法并参考某些环境设置。但是如果禁止执行,那应该做什么呢?
考虑这个例子:
@ForbidIf('default:durationIs(0))') double getSpeed(double distance);
并像
一样使用它 double speed = getSpeed(distance); // the duration is set globally in this example
如果持续时间值设置为0会发生什么 - 在这种情况下应该为速度分配什么?或者您是否想提出运行时异常?
在您的情况下,我们已经有两种方法来实现条件执行:
// check before calling
if (isSaveToOpenWindow())
openWindow();
和
public void openWindow() {
if (!isSaveToOpenWindow())
return;
// open window
}
答案 4 :(得分:0)
你需要AOP吗?装饰器模式可以更简单,并且需要更少的魔力。用以下内容包装实现:
class ProtectedWindowOpener implements WindowOpener {
WindowOpener delegate ...
void openWindow(Window w) {
if (!allowOpen(w)) {
throw new PermissionDeniedException...
}
delegate.openWindow(w);
}
boolean allowOpen(Window w) {
// security logic here
}
}
这使得安全逻辑保持独立,并且还具有不在代码中嵌入代码的优势,这意味着eclipse可以开展业务。