我有一个使用Spring框架在Java 1.5中开发的Web应用程序。应用程序包含“仪表板”,这是一个简单的页面,其中一组信息被重新分组,用户可以在其中修改某些状态。管理人员希望我在数据库中为三个仪表板添加日志记录系统。每个仪表板都有不同的信息,但日志应该按日期和用户登录进行跟踪。
我想要做的是实现类似这样的策略模式:
interface DashboardLog {
void createLog(String login, Date now);
}
// Implementation for one dashboard
class PrintDashboardLog implements DashboardLog {
Integer docId;
String status;
void createLog(String login, Date now){
// Some code
}
}
class DashboardsManager {
DashboardLog logger;
String login;
Date now;
void createLog(){
logger.log(login,now);
}
}
class UpdateDocAction{
DashboardsManager dbManager;
void updateSomeField(){
// Some action
// Now it's time to log
dbManagers.setLogger = new PrintDashboardLog(docId, status);
dbManagers.createLog();
}
}
Appcontext.xml:
<bean id="dashboardManagers" class="...DashboardManagers" />
在这个解决方案中,我因此不使用依赖注入。以这种方式做到这一点是“正确的”(良好做法,表现......)有没有更好的方法可以使用DI?
注意:我没有编写构造函数和getter / setter等基本内容。
答案 0 :(得分:2)
您的解决方案将为每次调用updateSomeField()创建一个新的PrintDashboardLog实例。这可能会占用不必要的时间/内存/ GC工作量。此外,从设计的角度来看,如果每个仪表板都有一个DashboardLog,而不是每个呼叫的新仪表板,那么它是有意义的。
我认为使用Logging是示例性用例之一的方面可能是个好主意。类似的东西:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean id="loggingAspect" class="com.yourcompany.yourapplication.aspects.DashboardLogAspect" />
<aop:aspectj-autoproxy>
<aop:include name="loggingAspect" />
</aop:aspectj-autoproxy>
</beans>
package com.yourcompany.yourapplication.aspects;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class DashboardLogAspect {
@Around("execution(* com.yourcompany.yourapplication..*Action+.*(..)) && target(target)")
public Object logActionCall(ProceedingJoinPoint pjp, Object target) throws Throwable {
long before = System.nanoTime();
Object returnValue = pjp.proceed();
long after = System.nanoTime();
long durationNs = after - before;
String logMsg = target.getClass() + "." + pjp.getSignature().toShortString() + " (" + durationNs + " ns)";
// TODO: store the log message in your database
System.out.println(logMsg);
return returnValue;
}
}
这会记录对名称以“Action”结尾的应用程序类的所有调用。它还会增加每个呼叫完成所需的时间。您可能还想调整特定方法名称模式的Around建议。见the AspectJ programming guide
答案 1 :(得分:1)
尽管采用战略模式完全“正确”,但考虑到你使用Spring这一事实 - 采用Dependency Injection机制会更好 由Spring框架提供 - 不妨将您的框架提供的内容作为其核心优势之一。
答案 2 :(得分:1)
如果每个“仪表板”都有一个控制器,为什么不从控制器调用日志记录。
public interface DashboardLog
{
void createLog(...);
}
public class DashboardUno
implements DashboardLog
{
...
public void createLog(...)
{ ... }
}
@Controller
@RequestMapping("/blah/schmarr")
public class BlahController
{
...
@RequestMapping(value = "/xxx")
public String someMeaningfulName(...)
{
DashboardUno elEsUno;
... get the dashboard object ...
elEsUno.createLog(...);
...
}
}