为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

九州编程 2023-07-28 16:20:43
我试图避免来自控制器类的 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@Componentpublic 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    }}
查看完整描述

1 回答

?
汪汪一只猫

TA贡献1898条经验 获得超8个赞

我们首先要区分

  • 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 service

Doing something in DAO

Doing something in controller

Doing 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;


@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)


查看完整回答
反对 回复 2023-07-28
  • 1 回答
  • 0 关注
  • 97 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信