1 发现问题
打算使用 Spring AOP 做切面实现记录日志的功能。因为注解方式比较简单,所以采用注解来实现。
1、在 spring 的配置文件中加入了以下配置:
<!-- 扫描包下所有的类,让标注Spring 注解的类生效 -->
<context:component-scan base-package="com"/>
<!-- 开启对 @Aspect 的支持-->
<aop:aspectj-autoproxy/>
2、新增了切面类:
@Component
@Aspect
public class SysLogAspect {
static Logger logger = LoggerFactory.getLogger(SysLogAspect.class);
@Pointcut("@annotation(com.deniro.jail.domain.sys.SysLog)")
private void sysLog() {
}
/**
* 记录日志
*
* @param pjp
*/
@Around("sysLog()")
public Object log(ProceedingJoinPoint pjp) {
logger.info("调用方法:{};输入参数:{}", pjp.getSignature()
, pjp
.getArgs());
StopWatch sw = new StopWatch();
sw.start();
Object o = null;
try {
System.out.println("开始");
o = pjp.proceed();
System.out.println("结束");
} catch (Throwable throwable) {
logger.error("记录日志", throwable);
}
sw.stop();
logger.info("输出参数:{};耗时:{}", o, sw.toString());
return o;
}
}
3、新建了注解类:
public @interface SysLog {
/**
* 描述
*
* @return
*/
public String description();
}
4、然后,在相应的方法上加入了该注解:
@RequestMapping(value = "/save")
@ResponseBody
@SysLog(description = " xxx")
public AjaxResponse save(DictItem dictItem) {
}
然而,项目在实际运行时,没有打印出切面的日志!
2 分析
打开 log4j 的 DEBUG 选项,发现系统并没有调用切面方法!
建一个单元测试试一试吧:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-context.xml"})
@TransactionConfiguration(defaultRollback = true)
@Transactional
public class BeanAspectTest {
@Autowired
private DictItemController dictItemController;
@Test
public void aspect() {
DictItem dictItem=new DictItem();
dictItem.setDictItemIsOptional("true");
dictItem.setDictItemDescription("1");
dictItem.setDictItemValue("1");
dictItem.setDictItemType("health");
dictItemController.save(dictItem);
}
}
在单元测试中,可以打印出切面日志,这说明 spring 框架配置的 AOP 运行正常!那么,为什么系统运行时就不正常了呢?
比较单元测试用到的配置文件与系统运行的配置文件,在有一点上不同,即系统运行时使用到了 spring 的 MVC 配置文件。spring 的 MVC 是独立的配置文件,所以 Controller 的配置都在这个文件中,应该把 AOP 的配置移到这里。
3 解决问题
把原有的配置移动到 spring 的 MVC 配置文件中:
<!-- 扫描包下所有的类,让标注Spring 注解的类生效 -->
<context:component-scan base-package="com"/>
<!--配置注解驱动-->
<mvc:annotation-driven/>
<!-- 开启对 @Aspect 的支持-->
<aop:aspectj-autoproxy/>
重启后,运行系统,AOP 恢复正常啦:
开始
before()
...
结束
记住,如果项目用了 spring MVC,一定要把 AOP 的相关配置移动到 MVC 配置文件哦O(∩_∩)O~
扫描包下所有的路径配置以及注解驱动配置也可以一并移过来,统一管理。