Spring AOP 可以使用XML 配置方式和注解方式
而AOP的类型有如下三种
1. 显示声明前置后置AOP方法
2. 环绕AOP方法
3. 使用接口扩展已知类
以下是各种类型示例
applicationContext.xml示例
<!-- 带参AOP示例 --> <aop:aspect ref="idInterceptor" > <!-- 在切入点设置方法参数类型和参数名 --> <aop:pointcut id="interceptId" expression=" execution(* com.xxx.service.UserServiceImpl.buyTicket(int)) and args(userId)" /> <!-- 接货参数的参数名 --> <aop:before method="setUserId" pointcut-ref="interceptId" arg-names="userId" /> </aop:aspect> <!-- 切面实现新接口AOP示例 --> <aop:aspect> <!-- 声明需要扩展的类和需要实现的接口,+表示衍生类 --> <!-- implement-interface是切点类需要实现的接口 --> <!-- default-impl是接口的实现方法 --> <!--types-matching如果写的是具体接口实现类,就不能转成那个类了,只能写这个接口 --> <aop:declare-parents types-matching="com.xxx.service.UserServiceIntf+" implement-interface="com.xxx.aop.ExtraAopIntf" default-impl="com.xxx.aop.ExtraAop" /> <!-- 实现类也可以使用bean id代替,此时需要将实现类注册为bean --> <aop:declare-parents types-matching="com.xxx.service.UserServiceImplImpl+" implement-interface="com.xxx.aop.ExtraAopIntff" delegate-ref="extraAop" /> </aop:aspect>
<!-- 自动注册 --> <context:component-scan base-package="com.xxx" > <!-- 排除由ServletDispatcher管理的controller包和MyBatis管理的mapper包 --> <!--<context:exclude-filter type="regex" expression=".controller.*" />--> <!--<context:exclude-filter type="regex" expression=".mapper.*" />--> <context:include-filter type="regex" expression=".bean.*" /> <context:include-filter type="regex" expression=".service.*" /> <!-- aop中切面包含的bean似乎只能通过显示的bean注册 不能自动注册,所以此处不写,直接移动到xxxBeans.xml文件 --> </context:component-scan>
dispatcher-servlet.xml示例
<!-- 开启Controller自动注册,必须写在这个文件里 --> <context:component-scan base-package="com.xxx.controller" /> <!-- Web层AOP配置 --> <aop:config> <!-- 声明一个切面 --> <aop:aspect ref="logger"> <!-- 声明一个切点 --> <!-- expression的含义: * 表示返回值为任意类型 .. 表示参数为任意类型 --> <aop:pointcut id="listAllLog" expression=" execution(* com.xxx.controller.UserController.listAll(..))" /> <!-- 声明前置通知 --> <aop:before method="beforeLog" pointcut-ref="listAllLog" /> <!-- 声明返回后置通知 --> <aop:after-returning method="successLog" pointcut-ref="listAllLog" /> <!-- 声明异常后置通知 --> <aop:after-throwing method="failLog" pointcut-ref="listAllLog" /> </aop:aspect> <!-- 环绕通知示例 --> <aop:aspect ref="security" > <aop:pointcut id="listAllSecurity" expression=" execution(* com.xxx.controller.UserController.listAll(..))" /> <aop:around method="securityCheck" pointcut-ref="listAllSecurity" /> </aop:aspect> </aop:config>
使用注解的方式AOP
受限开启自动注册注解AOPbean
<!-- 开启自动AOP代理bean功能,它可以自动生成使用了@Aspect的通知类的代理类,类似于自动注册 --> <aop:aspectj-autoproxy />
1. 显示限定调用注解类
package com.xxx.aop; /** * Created with IntelliJ IDEA. * User: zhenwei.liu * Date: 13-7-19 * Time: 下午3:42 * To change this template use File | Settings | File Templates. */ import org.aspectj.lang.annotation.*; /** * 注解AOP测试 */ @Aspect public class Logger { @Pointcut( "execution(* com.xxx.controller.UserController.listAll())") // 此处的listAll无意义,相当于<aop:pointcut>里的id public void listAll() {} @Before("listAll()") public void beforeLog() { System.out.println("Prepared to log"); } @AfterReturning("listAll()") public void successLog() { System.out.println("Log successfully"); } @AfterThrowing("listAll()") public void failLog() { System.out.println("Log fail"); } }
2. 环绕通知
package com.xxx.aop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; /** * Created with IntelliJ IDEA. * User: zhenwei.liu * Date: 13-7-19 * Time: 下午6:42 * To change this template use File | Settings | File Templates. */ /** * 注解环绕通知示例 */ @Aspect public class Security { @Pointcut( "execution(* com.xxx.controller.UserController.listAll())") // 此处的listAll无意义,相当于<aop:pointcut>里的id public void listAll() {} // 使用环绕通知 @Around("listAll()") public void securityCheck(ProceedingJoinPoint joinPoint) { try { System.out.println("Prepared to Security check"); joinPoint.proceed(); System.out.println("Security check finished"); } catch (Throwable throwable) { System.out.println("Security system error"); } } }
3.带参AOP
package com.xxx.aop; /** * Created with IntelliJ IDEA. * User: zhenwei.liu * Date: 13-7-19 * Time: 下午10:36 * To change this template use File | Settings | File Templates. */ import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; /** * 演示带参AOP方法 */ @Aspect public class IdInterceptor { @Pointcut( "execution(* com.xxx.service.UserServiceIntf." + "buyTicket(int)) && args(userId))") public void buyTicket(int userId){}; private int userId; public int getUserId() { return userId; } @Before("buyTicket(userId)") public void setUserId(int userId) { this.userId = userId; } }
4. 接口扩展AOP
package com.xxx.aop; /** * Created with IntelliJ IDEA. * User: zhenwei.liu * Date: 13-7-20 * Time: 下午1:41 * To change this template use File | Settings | File Templates. */ public interface ExtraAopIntf { void extraFunc(); } package com.xxx.aop; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.DeclareParents; /** * Created with IntelliJ IDEA. * User: zhenwei.liu * Date: 13-7-20 * Time: 下午1:42 * To change this template use File | Settings | File Templates. */ /** * 基于注解的实现新接口AOP切面 */ @Aspect public class ExtraAop implements ExtraAopIntf { @Override public void extraFunc() { System.out.println("Execute extra aop func"); } } package com.xxx.aop; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.DeclareParents; /** * Created with IntelliJ IDEA. * User: zhenwei.liu * Date: 13-7-20 * Time: 下午5:01 * To change this template use File | Settings | File Templates. */ @Aspect public class ExtraAopAspect { /** * value 表示需要被扩展的bean类型 * defaultImp 表示实现扩展的类 * static 属性成员extraAopInft代表扩展的类型 */ @DeclareParents( value = "com.xxx.service.UserServiceIntf+", defaultImpl = ExtraAop.class ) public static ExtraAopIntf extraAopIntf; }