Spring Scope代理模式AspectJ?

时间:2011-07-13 11:56:25

标签: 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的实体,它就失败了(并没有真正有用的例外)。 - (这个失败很明显。

原因是spring在currentUser中注入一个CGI代理。只要只使用此代理的属性,这样就可以正常工作,但如果开始使用引用本身就会失败。

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

至少我想要的只是当前用户非常容易使用:

@Resouce
@CurrenctUser
User currentUser;

就是这样。

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


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

当我尝试按currentUser(Select b From Bookmark b Where user=?

加载时出现异常
  

java.lang.IllegalStateExceptionorg.hibernate.TransientObjectException:对象引用未保存的瞬态实例 - 在刷新之前保存瞬态实例:domain.User

我尝试保存书签时出现例外情况(书签有字段用户)

  

无法插入:[domain.Bookmark]; SQL [insert into bookmark (businessId, reference_Folder_fk, title, user_fk) values (?, ?, ?, ?)];约束[null];嵌套异常为org.hibernate.exception.ConstraintViolationException:无法插入:[domain.Bookmark]

1 个答案:

答案 0 :(得分:1)

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