猿问

在 spring 中防止来自控制器的 dao 调用

我试图避免来自控制器类的 dao 调用。如果调用是从服务包完成的,那么 dao 调用应该成功,否则我将抛出异常。我不想在dao类的每个方法中都写这个逻辑,所以打算使用aspectj来拦截dao调用。如何防止控制器中的 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


    }

}


九州编程
浏览 98回答 1
1回答

汪汪一只猫

我们首先要区分AspectJ(快速、高效、无代理、更强大)和Spring AOP(基于代理、委托模式、“轻AOP”、仅方法拦截)。编译时检查调用代码@DeclareError当使用 AspectJ 并使用 AspectJ 编译器重新编译遗留库(具有 AOP 增强功能的 Java 编译器的直接替代品)时,@DeclareError如果发现来自错误的类或包模式的调用,您可以使用 AspectJ 使编译失败。这样你就不需要任何昂贵的运行时检查、反射或其他技巧。对于 Maven 构建,您可以使用 AspectJ Maven 插件。这就是我的建议:在构建时检测无效调用,修复代码以使其能够编译并在运行时无忧无虑。call()使用带有切入点的AspectJ 加载时编织 (LTW) 进行运行时检查然而,如果您不想使用 AspectJ 编译器(即使您标记了问题spectj而不是spring-aop)或者对调用代码没有编译时影响,您仍然可以使用AspectJ 加载时编织(LTW )来自春天。如果您想避免创建异常的唯一目的是分析其调用堆栈以找到调用者,那么 Spring AOP 绝对不够。相反,在完整的 AspectJ 中,有一个名为call()Spring AOP 的切入点。您可以通过 LTW 编织到调用代码中,然后使用它EnclosingStaticPart来查找调用者。唯一需要注意的是,在 Spring 中,您可能会使用代理而不是直接调用,这可能会间接地扰乱调用者,但您可以尝试一下。这是纯 Java + AspectJ 中的MCVE(不涉及 Spring):DAO、服务、控制器: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 serviceDoing something in DAODoing something in controllerDoing something in DAO实际上,列表行不应该被打印,因为从控制器到 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;@Aspectpublic 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 DAODoing 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)
随时随地看视频慕课网APP

相关分类

Java
我要回答