1、什么是AOP
AOP,面向切面编程,是对OOP编程的补充。下面介绍下AOP中涉及的术语:
(1)Aspect切面
一个关注点的模块化,这个关注点可能横切多个对象。
(2)Jointpoint连接点
在程序执行过程中某个特定的点,比如添加一个日志处理方法,此方法的执行就是一个连接点。
(3)Pointcut切入点
与连接点是相互匹配的。
(4)Target目标
被一个或者多个切面所通知的对象,是被代理对象
(5)AOP Proxy AOP代理
AOP创建的对象。
(6)Weaving织入
把切面连接到其他应用逻辑的行为。
2、AOP作用
用来处理一些具有横切性质的系统性服务,比如日志管理、安全检查、事务管理等。
3、Spring对AOP的支持
Spring中的AOP代理由IoC容器负责生成和管理,因此AOP代理可以直接使用IoC容器中的其它Bean作为代理对象,即target。Spring使用Java动态代理创建AOP代理,需要注意的是,如果需要代理的类不是接口的时候,Spring会自动使用CGLIB来动态修改二进制码生成代理对象。
4、Spring中AOP的实现
(1)基于Annotation
(a)启用Spring对@AspectJ支持
<?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:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <!-- 启动@Aspectj支持 --> <aop:aspectj-autoproxy /> </beans>(b)定义一个切面Aspect
package cn.com.yy.aop; import org.aspectj.lang.annotation.Aspect; @Aspect public class LogHandlerAspect { }即使用注解@Aspect来声明该类是一个切面。
(c)前置通知---定义Before增强处理
package cn.com.yy.aop; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class LogHandlerAspect { // 匹配 cn.com.yy.service 包及其子包下所有类的login方法作为切入点 @Before("execution(public * cn.com.yy.service..*.login(**))") public void logPrint(){ System.out.println("--print log info---"); } }当匹配成功时,会首先指向logPrint方法,然后再执行所匹配的方法。
(d)最终通知---After增强处理
@After("execution(public * cn.com.yy.service..*.login(**))") public void close(){ System.out.println("--close---"); }@After,不论一个方法是如何结束的,最终通知都会执行。
(e)后置通知--@AfterReturning
@AfterReturning("execution(public * cn.com.yy.service..*.login(**))") public void afterReturning(){ System.out.println("---afterReturning---"); }该增强处理只有在匹配的方法成功完成后才会执行,这点不同于@After。
(f)异常通知--@AfterThrowing
@AfterThrowing("execution(public * cn.com.yy.service..*.login(**))") public void afterThrowing(){ System.out.println("--afterThrowing method--"); }匹配方法发生异常时,才会织入。
当然,还有其他的增强通知。
注意:如果多个通知对应于同一个匹配表达式,此时可以抽取成公共切入点。
package cn.com.yy.aop; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @Aspect public class LogHandlerAspect { //公共切入点 @Pointcut("execution(public * cn.com.yy.service..*.login(**))") public void pubPointCut(){ } //引用公共切入点 @Before("pubPointCut") public void logPrint(){ System.out.println("--print log info---"); } //引用公共切入点 @After("pubPointCut") public void close(){ System.out.println("--close---"); } //引用公共切入点 @AfterReturning("pubPointCut") public void afterReturning(){ System.out.println("---afterReturning---"); } //引用公共切入点 @AfterThrowing("pubPointCut") public void afterThrowing(){ System.out.println("--afterThrowing method--"); } }
(2)使用XML配置
<?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:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <bean id="logAspect" class="cn.com.yy.aop.LogHandlerAspect"></bean> <aop:config> <!-- 定义一个切面 --> <aop:aspect id="myAspect" ref="logAspect"> <!-- 前置通知 --> <aop:before method="logPrint" pointcut="execution(public * cn.com.yy.service..*.login(**))"/> <!-- 最终通知 --> <aop:after method="close" pointcut="execution(public * cn.com.yy.service..*.login(**))"/> <!-- 后置通知 --> <aop:after-returning method="afterReturning" pointcut="execution(public * cn.com.yy.service..*.login(**))"/> <!-- 异常通知 --> <aop:after-throwing method="afterThrowing" pointcut="execution(public * cn.com.yy.service..*.login(**))"/> </aop:aspect> </aop:config> </beans>如果一个切面中多个方法使用同一个匹配表达式,则可以提取公共,如下:
<aop:config> <aop:aspect id="myAspect2" ref="logAspect"> <aop:pointcut expression="execution(public * cn.com.yy.service..*.login(**))" id="pubPointcut"/> <aop:before method="logPrint" pointcut-ref="myPointcut"/> <aop:after method="close" pointcut-ref="myPointcut"/> <aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/> <aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut"/> </aop:aspect> </aop:config>当然,如果多个切面对应于同一个匹配表达式,可以提取公共到切面外。