我目前在使用 JSF 2 和 Spring 3 AOP 的组合时遇到问题。
应用程序设计为经典的三层架构(Web、服务、数据库)。所以 Spring 管理的 JSF-Beans 调用代表业务逻辑的 Service Beans。
托管 Bean 如下所示:
@Named("startPage")
@Scope("view")
public class ManagedBean implements Serializable {
@Inject
private ServiceBeanA serviceBeanA;
public void someMethod() {
serviceBean.doSomeBusinessLogic();
}
由于此 Bean 是视图范围的,因此它实现了 Serializeable,并且实例变量(在本例中为 ServiceBeanA)也是如此,如下所述: JSF backing bean should be serializable?
到目前为止,一切都按预期工作。
现在我想拦截业务服务中声明的业务方法的调用。因此,我创建了一个执行一些基本日志记录的 Aspect,并在 spring 配置中将其删除:
<bean id="aspectLogging" class="my.package.AspectLogging" />
<aop:config>
<aop:aspect ref="aspectLogging">
<aop:pointcut id="serviceMethodInvocation" expression="execution(* my.services.ServiceBeanA.doSomeBusinessLogic())" />
<aop:around pointcut-ref="serviceMethodInvocation" method="performLogging" />
</aop:aspect>
</aop:config>
方面:
public class AspectLogging {
public Object performLogging(ProceedingJoinPoint pjp) throws Throwable {
Object toReturn = null;
System.out.println(">>>>"+ pjp.getSignature().toLongString());
toReturn = pjp.proceed();
return toReturn;
}
}
现在问题发生了:
SCHWERWIEGEND: Exiting serializeView - Could not serialize state: org.springframework.aop.aspectj.AspectJPointcutAdvisor
java.io.NotSerializableException: org.springframework.aop.aspectj.AspectJPointcutAdvisor
我在 Springsource 发现了两个相同的问题描述(不幸的是没有解决)
http://forum.springsource.org/showthread.php?87428-AspectJPointcutAdvisor-not-Serializable http://forum.springsource.org/archive/index.php/t-57602.html
当然,我可以简单地不使用 Aspect Orientation,但是任何其他第三方库都可能出现同样的问题。
我所做的是将持有业务服务的实例变量标记为瞬态。
public class ManagedBean implements Serializable {
@Inject
private transient ServiceBeanA serviceBeanA;
public void someMethod() {
serviceBean.doSomeBusinessLogic();
}
这工作正常,直到会话恢复(反序列化)。当然反序列化后变量(serviceBeanA)为空。我可以将 Web 容器(例如 Tomcat)配置为不序列化会话,但该应用程序在云中运行,因此我不负责配置服务器。
我唯一的想法是通过提供
private synchronized void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException
和
private synchronized void writeObject(ObjectOutputStream s) throws IOException
托管 Bean 中的方法。
private synchronized void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();
ApplicationContext context = new ClassPathXmlApplicationContext("services.spring-config.xml", "database.spring-config.xml");
this.ServiceBeanA = (ServiceBeanA) context.getBean("serviceBeanA");
}
private synchronized void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
}
这个解决方案有效,但它似乎是一个非常笨拙和不雅的解决方案。我必须在每个使用服务 Bean 的托管 Bean 中重复几乎相同的代码。此外,托管 bean 以这种方式与 Spring 紧密耦合,因为它们导入 Springs 应用程序上下文以恢复服务变量。
有人能想到更好的架构方法吗?提前致谢!