除springMvc外需要引入@Aspect注解依赖:
<!-- AOP -->
<!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_3</version>
</dependency>
自定义注解标签:
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface logAnnotation {
/**
* @param 模块名字
*/
String modelName() default "";
/**
* @param 操作类型
*/
String option();
}
定义切面类:
@Aspect
// 该注解标示该类为切面类
@Component
// 注入依赖
public class OperationLogAspect {
// 标注该方法体为后置通知,当目标方法执行成功后执行该方法体
@AfterReturning("within(com.ustcinfo.fccos.terminal.web..*) && @annotation(rl)")
public void addLogSuccess(JoinPoint jp, logAnnotation rl) {
System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&");
Object[] parames = jp.getArgs();// 获取目标方法体参数
String className = jp.getTarget().getClass().toString();// 获取目标类名
className = className.substring(className.indexOf("com"));
String signature = jp.getSignature().toString();// 获取目标方法签名
String methodName = signature.substring(signature.lastIndexOf(".") + 1, signature.indexOf("("));
System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&");
}
}
切面类可根据业务要求自行添加逻辑
在spring的容器xml中添加配置:
<aop:aspectj-autoproxy/>
此处有个注意点:网上说利用AOP无法拦截controller层,经测试,需要在web mvc中同时添加注解
<aop:aspectj-autoproxy/>
因为为了启用事务,在spring的容器扫描中排除了controller层:
<context:annotation-config />
<!-- 对应的是系统级别的配置,作用范围是系统上下文 -->
<context:component-scan base-package="com.ustcinfo.fccos.terminal.web">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
在Mvc、中只启用了controller层的扫描:
<mvc:annotation-driven />
<!-- 对应的是 controller 级别的配置,作用范围是控制层上下文。初始话转发内容 -->
<context:component-scan base-package="com.ustcinfo.fccos.terminal.web.controller">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
因此,只需要在 spring的父容器,mvc子容器中均添加
<aop:aspectj-autoproxy/>
即可实现controller的拦截;
网上还有另外一种说法,就是配置文件改成
<aop:aspectj-autoproxy proxy-target-class="true"/>让spring使用cglib的代理方式
但是cglib的时候需要有默认的构造方法,class不能为final的,因此在项目中引入了mybatis或者其他的无默认构造的方法时候就会报错:
java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy33
,经测试,只需要在 spring的父容器,mvc子容器中均添加
<aop:aspectj-autoproxy/>
即可实现controller以及其他业务的切面,网上说spring会自动在JDK动态代理和CGLIB之间转换,但是没做验证
查看aop是否生效
切面注解controller
@RequestMapping(value = "getInstallerInfos")
@ResponseBody
@logAnnotation(option = "查询装维_controller")
public Json getInstallerInfos(String installer) {
@Override
@logAnnotation(option = "查询装维_service")
public Json getInstallerInfos(String installer) {
切面注解service
日志均打印表明测试成功