Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/jsf/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring AOP记录器方面的LazyInitializationException异常_Spring_Jsf_Jpa - Fatal编程技术网

Spring AOP记录器方面的LazyInitializationException异常

Spring AOP记录器方面的LazyInitializationException异常,spring,jsf,jpa,Spring,Jsf,Jpa,我用Spring、JSF JPA和Hibernate构建了一个应用程序。 我有一个方面可以“监视”应用程序服务层中的每个更新*、创建*、删除*方法。此特性记录方法params,将apply toString应用于每个param,并将它们记录在数据库中。问题是,我在jsf中使用域对象,当我尝试更新*某些东西时,当toString()应用于方法param时,我会得到一个LazyInitializationException异常。 一种解决方案是从toString中删除所有表示其他对象的参数,但这样操

我用Spring、JSF JPA和Hibernate构建了一个应用程序。
我有一个方面可以“监视”应用程序服务层中的每个更新*、创建*、删除*方法。此特性记录方法params,将apply toString应用于每个param,并将它们记录在数据库中。问题是,我在jsf中使用域对象,当我尝试更新*某些东西时,当toString()应用于方法param时,我会得到一个LazyInitializationException异常。
一种解决方案是从toString中删除所有表示其他对象的参数,但这样操作就没有意义了,因为我不记录我感兴趣的细节。
即,我有一个名为Price的实体,它有一个依赖项PriceList:

public class Price extends BaseEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    @Column(name = "price")
    private Double price;

    //bi-directional many-to-one association to TelCoPriceList
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "price_list_id")
    private PriceList priceList;
.....................
}
价格被用于AddPriceForm.xhtml,这是jsf表单。JSF AddPriceMB引用了执行实际更新的PriceService。
PriceService由以下方面“监控”:

@Aspect
@Named("auditLogAspectImpl")
public class AuditLogAspectImpl implements AuditLogAspect {

@Inject
private UserService userService; 

@Inject
private AuditLogService auditLogService;

@Override
@AfterReturning(pointcut = "execution(* com.videanuadrian.core.impl.services..*.save*(..)) or execution(* com.videanuadrian.core.impl.services..*.update*(..)) or execution(* com.videanuadrian.core.impl.services..*.delete*(..))", returning = "retVal")
public boolean afterLogEvent(JoinPoint joinPoint,Object retVal) {

    String className = joinPoint.getTarget().getClass().getName();
    String methondName = joinPoint.getSignature().getName();

...................................................................      
    StringBuffer logMessage = new StringBuffer();       
    Object[] args = joinPoint.getArgs();    

    //for login action we only get the username and hash the password
    if (methondName.compareTo("login") == 0){           
        logMessage.append(args[0]);         
    }else {

        int argsLen = args.length;
        //else log all the parameters
        for (int i = 0; i < argsLen; i++) {
            // this is where the exception occurs !!!!!!!!!!!!!!!!!!!!!!!!!!!
            logMessage.append(args[i]).append(",");
        }

        if (argsLen > 0) {
            logMessage.deleteCharAt(logMessage.length() - 1);
        }
    }

    //some save/update methods return Boolean
        Boolean status = false;
        if (retVal instanceof Boolean){
            status = (Boolean) retVal;
        }

        //some return the ID of the object inserted,and if these methods return an integer the status is true, if they return null, the status si false
        if (retVal instanceof Integer){
            if (retVal!=null)
                status = true;  
        }

    auditLogService.addAuditLogEvent(uid, className+"."+methondName, status,logMessage.toString());     
    return true;
}
@方面
@命名(“auditLogAspectImpl”)
公共类AuditLogAspectImpl实现AuditLogAspect{
@注入
私人用户服务;
@注入
私有AuditLogService AuditLogService;
@凌驾
@返回(pointcut=“execution(*com.videanuadrian.core.impl.services..*.save*(..)或执行(*com.videanuadrian.core.impl.services..*.update*(..)或执行(*com.videanuadrian.core.impl.services..*.delete*(..)后,返回=“retVal”)
公共布尔afterLogEvent(JoinPoint、JoinPoint、Object retVal){
字符串className=joinPoint.getTarget().getClass().getName();
字符串methondName=joinPoint.getSignature().getName();
...................................................................      
StringBuffer logMessage=新的StringBuffer();
对象[]args=joinPoint.getArgs();
//对于登录操作,我们只获取用户名和散列密码
如果(methondName.compareTo(“登录”)==0{
logMessage.append(args[0]);
}否则{
int argsLen=args.length;
//否则,记录所有参数
对于(int i=0;i0){
logMessage.deleteCharAt(logMessage.length()-1);
}
}
//某些保存/更新方法返回布尔值
布尔状态=假;
if(返回布尔值的实例){
status=(布尔)retVal;
}
//有些方法返回插入对象的ID,如果这些方法返回一个整数,则状态为true,如果返回null,则状态为false
if(retVal instanceof Integer){
如果(retVal!=null)
状态=真;
}
addAuditLogEvent(uid,className+““+methodName,status,logMessage.toString());
返回true;
}
在以前的版本中,我没有遇到这个问题,因为我使用了DTO对象,DTO和域对象之间的转换是在服务层执行的。错误很明显,因为与我执行这个toString()操作的时间相比,我的会话早就关闭了。
你知道不使用openSessionInView或扩展持久性上下文如何实现这一点吗?或者我的方法不太好……

不要使用AOP,而是为这类任务实现Hibernate事件侦听器。另请检查Hibernate Envers项目。好的,谢谢你的提示。我以前使用过Envers,但我正在寻找通用解决方案我明白。如果你真的想去AOP的方式,那么你也可以考虑不使用实体作为服务方法参数。你可以实现特殊的传输对象(例如,对于<代码>价格>代码>实体实现<代码> PrimeUpDebug < /代码>对象)。。这样您就不会有延迟初始化的问题。缺点是应用程序中的对象数量(以及这些对象之间所需的映射逻辑)增加了很多。:)一个月前,我做了这样的设置,每个DomainObject都由一个具有完全相同字段的DTO对象备份,并且在视图中我使用了该DTO。谢谢您的提示。