Spring两大重要特性之一就是面向切面编程,下面的例子就是基于XML配置文件最简单的Spring AOP,AOP中的一些术语我就不说了,还是直接操作来的直观
一、maven依赖
<!--spring--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.1.2.RELEASE</version> </dependency> <!--aspectJ--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.0</version> </dependency> <!--动态代理实现--> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2.2</version> </dependency>
二、一个很普通的类以及方法
package cn.cjc.spring.aop.service; public class LogService { public void sayHi(String userName) { System.out.println("Hi, " + userName); } }
三、切面类
package cn.cjc.spring.aop.aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; public class LogAspect { /** * 前置通知 */ public void before(JoinPoint call) { String className = call.getTarget().getClass().getName(); String methodName = call.getSignature().getName(); System.out.println("前置通知:" + className + "类的" + methodName + "方法开始执行"); } /** * 后置通知 */ public void afterReturn() { System.out.println("后置通知"); } /** * 最终通知 */ public void after(String userName) { System.out.println(userName + ",最终通知"); } /** * 异常通知 */ public void afterThrow() { System.out.println("异常通知"); } /** * 环绕通知 */ public Object around(ProceedingJoinPoint call, String userName) { System.out.println("环绕通知"); this.before(call); Object result = null; try { result = call.proceed(); this.afterReturn(); } catch (Throwable e) { this.afterThrow(); } finally { this.after(userName); } return result; } }
四、spring配置文件beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <!--普通的bean声明--> <bean id="logService" class="cn.cjc.spring.aop.service.LogService"/> <bean id="logAspect" class="cn.cjc.spring.aop.aspect.LogAspect"/> <!--aop配置开始--> <aop:config> <!--将id=logAspect的类声明为切面--> <aop:aspect ref="logAspect"> <!--切点1--> <aop:pointcut id="pc1" expression="execution(* cn.cjc.spring.aop.service..*.*(String)) and args(name)"/> <!--切点2--> <aop:pointcut id="pc2" expression="execution(* cn.cjc.spring.aop.service..*.*(..))"/> <!--将切面中的before方法声明为前置通知,并指定通知的切点--> <aop:before method="before" pointcut-ref="pc2"/> <!--将切面中的afterReturn方法声明为后置通知,并指定通知的切点--> <aop:after-returning method="afterReturn" pointcut-ref="pc2"/> <!--将切面中的after方法声明为最终通知,并指定通知的切点,同时拦截切点的参数--> <aop:after method="after" pointcut-ref="pc1" arg-names="name"/> <!--将切面中的afterThrow方法声明为异常通知,并指定通知的切点--> <aop:after-throwing method="afterThrow" pointcut-ref="pc2"/> <!--将切面中的around方法声明为环绕通知,并指定通知的切点,同时拦截切点的参数--> <aop:around method="around" pointcut-ref="pc1" arg-names="name"/> </aop:aspect> </aop:config> </beans>
切点1的表达式含义是:匹配所有cn.cjc.spring.aop.service包及其子包下有且仅有一个入参为String类型的全部方法
切点2的表达式含义是:匹配所有cn.cjc.spring.aop.service包及其子包下所有方法
前置通知:在切点表达式匹配的方法执行前织入的通知
后置通知:在切点表达式匹配的方法执行成功后织入的通知
最终通知:在切点表达式匹配的方法执行成功或失败后都会织入的通知
异常通知:在切点表达式匹配的方法执行抛异常后织入的通知
环绕通知:能在切点表达式匹配的方法前、后、异常时都可以织入的通知
综上所述,<aop:before>标签的含义就是:在切点2的表达式匹配的方法执行前,先执行切面类的before方法,然后再执行切点方法。
五、测试
package cn.cjc.spring.aop.test; import cn.cjc.spring.aop.service.LogService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringAOPTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); LogService logService = context.getBean("logService", LogService.class); logService.sayHi("junKi"); } }
时间: 2024-10-27 18:35:29