java - Spring Scope代理模式AspectJ?

标签 java spring scope aop

我想实现一些功能来获取当前登录的用户(代表当前登录的人的 JPA 实体)。但不是用经典的方式来做

CurrentUserService.getCurrentUser(){load the user from db by login}) 

我想以更 CDI 的方式做到这一点。

我想要一个 CurrentUserFactory,它将当前用户提供为具有自定义限定符(当前 bean)的请求范围 bean。

预选赛:

@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface CurrentUser {
}

工厂:

@Component
public class CurrentUserFactory {

  @CurrentUser
  @Bean
  @Scope(value = WebApplicationContext.SCOPE_REQUEST,
         proxyMode = ScopedProxyMode.TARGET_CLASS)
  public User currentUser() throws IllegalStateException {
      return
          <DoWhatIMean>
             User load form DB by:
             SecurityContextHolder.getContext().getAuthentication().getName()
          </dwim>
}

用法:

@Controller
@RequestMapping(…)
public AccountController() {

  @Resource
  @CurrentUser
  private User currentUser;

  @RequestMapping(params=”my”)
  public String myAccount () {
     return “redirect:/account/”+currentUser.id;
  }
 }

效果很好。

但是,如果我使用当前用户进行直接 JPA (Hibernate) 操作(例如通过引用 currentUser 搜索实体或引用 currentUser 存储实体),它会失败(没有真正有用的异常(exception))。 --(这个失败是显而易见的。)

原因是spring在currentUser中注入(inject)了一个CGI代理。只要仅使用该代理的属性,这种方法就可以正常工作,但如果开始使用引用本身,这种方法就会失败。

我知道我正在规范的边缘工作,如果我的想法行不通,我会接受。但我想问你我有一个让它发挥作用的想法。这样开发人员就可以像普通 JPA 加载的实体一样使用这个 currentUser 对象。

我至少想要的是仅当前用户可以非常轻松地使用:

@Resouce
@CurrenctUser
User currentUser;

就是这样。

可能有人有一个想法让它工作,例如 AspectJ 技巧(我正在使用编译时 AspectJ)?

<小时/>

无论如何:正如我之前所说,异常不是我的问题,我理解它们,因为它们只是所描述问题的指标。

当我尝试通过 currentUser 加载时出现异常(从书签 b 中选择 b 其中 user=?)

java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: domain.User

尝试保存书签时出现异常(书签有字段用户)

could not insert: [domain.Bookmark]; SQL [insert into bookmark (businessId, reference_Folder_fk, title, user_fk) values (?, ?, ?, ?)]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not insert: [domain.Bookmark]

最佳答案

Spring代理是由ScopedProxyFactoryBean创建的。它的文档说代理实现了“ScopedObject”,它允许您访问原始 bean。

@Resource
@CurrentUser
private User currentUser;

public static <T> T unwrapScopedProxy(T maybeProxy) {
    if (maybeProxy instanceof ScopedObject) {
        return (T) ((ScopedObject) maybeProxy).getTargetObject();
    } else {
        return maybeProxy;
    }
}

...
query.setParameter("user", unwrapScopedProxy(currentUser));

关于java - Spring Scope代理模式AspectJ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6678458/

相关文章:

Java:局部变量可能尚未初始化?

java - chalice 。 Hibernate 延迟加载多个对象

java - 没有为依赖项 : expected at least 1 bean which qualifies as autowire candidate for this dependency 找到 UserRepository 类型的合格 bean

class - 我无法从 Kotlin 的嵌套类中联系到任何类成员

C++:如果抛出异常,超出范围的对象是否被销毁?

java - 使用 BlueJ 将 24 时钟更改为 12 时钟

java - 如何使用 Junit 创建可共享的测试包?

java - 在运行时添加 JDBC 驱动程序 - 由 : java. lang.ClassNotFoundException : com. mysql.jdbc.Driver 引起

java - 带有 AclPermissionEvaluator 的 Spring Boot 导致 IllegalStateException : No ServletContext set

javascript - 从内部函数中的父作用域访问数组元素