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>
当然,如果多个切面对应于同一个匹配表达式,可以提取公共到切面外。