gpt4 book ai didi

java - 在 spring 中防止来自 Controller 的 dao 调用

转载 作者:行者123 更新时间:2023-12-02 09:31:35 25 4
gpt4 key购买 nike

我试图避免来自 Controller 类的 dao 调用。如果调用是从服务包完成的,那么 dao 调用应该成功,否则我将抛出异常。我不想在dao类的每个方法中都写这个逻辑,所以打算使用aspectj来拦截dao调用。如何防止 Controller 中的 dao 并仅允许服务类中的 dao 。我应该使用任何其他 api/approach 吗?任何建议

package com;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DaoAspect {

@Before(value = "execution(* com.dao.*.*(..))")
public void beforeAdvice( JoinPoint joinPoint) {
// here I want to know the caller package/class
// if its com.service allow ,if com.controller reject

}
}

最佳答案

免责声明:我不是 Spring 用户。也许有一种更简单的内置方法可以通过拦截器、Spring Security 或您拥有的其他方法来实现此目的。但您要求 AOP 解决方案。

我们首先要区分

  • AspectJ(快速、高效、无代理、更强大)和
  • Spring AOP(基于代理、委托(delegate)模式、“轻量级 AOP”、仅方法拦截)。<​​/li>

使用 @DeclareError 调用代码的编译时检查

当使用 AspectJ 并使用 AspectJ 编译器重新编译遗留库(具有 AOP 增强功能的 Java 编译器的直接替代品)时,您可以使用 @DeclareError 以使编译在调用时失败发现来自错误的类或包模式。这样你就不需要任何昂贵的运行时检查、反射或其他技巧。对于 Maven 构建,您可以使用 AspectJ Maven 插件。有关 @DeclareError 的更多信息,请参阅我的回答:

这就是我的建议:在构建时检测无效调用,修复代码,使其能够编译并在运行时无忧无虑。

使用 AspectJ 加载时编织 (LTW) 和 call() 切入点进行运行时检查

但是,如果您不想使用 AspectJ 编译器(即使您标记了问题 aspectj 而不是 spring-aop)或者没有编译时对调用代码的影响,仍然可以使用AspectJ load-time weaving (LTW)从 Spring 开始。如果您想避免创建异常的唯一目的是分析其调用堆栈以找到调用者,那么 Spring AOP 绝对不够。相反,在完整的 AspectJ 中,有一个名为 call() 的切入点,它在 Spring AOP 中不可用。您可以通过 LTW 编织到调用代码中,然后使用 EnendingStaticPart 来查找调用者。唯一需要注意的是,在 Spring 中您可能会使用代理而不是直接调用,这可能会间接地扰乱调用者,但您可以尝试一下。

这是一个MCVE在普通 Java + AspectJ 中(不涉及 Spring):

DAO、服务、 Controller :

package com.dao.ddd;

public class MyDao {
public void doSomething() {
System.out.println("Doing something in DAO");
}
}
package com.service.sss;

import com.dao.ddd.MyDao;

public class MyService {
public void doSomething() {
System.out.println("Doing something in service");
new MyDao().doSomething();
}
}
package com.controller.ccc;

import com.dao.ddd.MyDao;

public class MyController {
public void doSomething() {
System.out.println("Doing something in controller");
new MyDao().doSomething();
}
}
package de.scrum_master.app;

import com.controller.ccc.MyController;
import com.service.sss.MyService;

public class Application {
public static void main(String[] args) {
// Allowed
new MyService().doSomething();
// Forbidden
new MyController().doSomething();
}
}

驱动程序应用程序:

package de.scrum_master.app;

import com.controller.ccc.MyController;
import com.service.sss.MyService;

public class Application {
public static void main(String[] args) {
// Allowed
new MyService().doSomething();
// Forbidden
new MyController().doSomething();
}
}

不带方面的控制台日志:

Doing something in service
Doing something in DAO
Doing something in controller
Doing something in DAO

实际上,列表行不应该被打印,因为从 Controller 到 DAO 的调用是被禁止的。

方面:

package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.JoinPoint.EnclosingStaticPart;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class ContractEnforcerAspect {
@Before("call(* com.dao..*(..))")
public void beforeAdvice(JoinPoint joinPoint, EnclosingStaticPart enclosingStaticPart) {
System.out.println(" Callee = " + joinPoint.getSignature());
System.out.println(" Caller = " + enclosingStaticPart.getSignature());
if (enclosingStaticPart.getSignature().getDeclaringType().getPackageName().startsWith("com.controller"))
throw new RuntimeException("DAO must not be called from controller");
}
}

控制台日志与方面:

Doing something in service
Callee = void com.dao.ddd.MyDao.doSomething()
Caller = void com.service.sss.MyService.doSomething()
Doing something in DAO
Doing something in controller
Callee = void com.dao.ddd.MyDao.doSomething()
Caller = void com.controller.ccc.MyController.doSomething()
Exception in thread "main" java.lang.RuntimeException: DAO must not be called from controller
at de.scrum_master.aspect.ContractEnforcerAspect.beforeAdvice(ContractEnforcerAspect.aj:17)
at com.controller.ccc.MyController.doSomething(MyController.java:8)
at de.scrum_master.app.Application.main(Application.java:11)

关于java - 在 spring 中防止来自 Controller 的 dao 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57913903/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com