AOP(Aspect Oriented Programming)面向切面编程,通过预编译方式和运行期动态代理实现程序功能的横向多模块统一控制的一种技术。AOP是OOP的补充,是spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。AOP可以分为静态织入与动态织入,静态织入即在编译前将需织入内容写入目标模块中,这样成本非常高。动态织入则不需要改变目标模块。Spring框架实现了AOP,使用注解配置完成AOP比使用XML配置要更加方便与直观。
AOP基本概念:
切面(aspect):横切关注点被模块化的特殊对象。
通知(advice):切面必须要完成的工作。切面中的每个方向称之为通知。通知是在切面对象中的。 (前置通知、后置通知、返回通知、异常通知、环绕通知)
目标(target):被通知的对象。
代理(proxy):向目标对象应用通知后创建的对象。
连接点(joinpoint):目标对象的程序执行的某个特定位置。如某个方向调用前,调用后的位置。包括两个信息:1.目标程序的哪个方法?2.方法执行前还是执行后?
切点(pointcut):每个类会有多个连接点,AOP通过切点定位到特定的边接点。
需要用到的包:spring的包 和一个aspectjweaver.jar
:
在spring配置文件中加入aop命名空间:
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <!-- 自动扫描--> <context:component-scan base-package="com.itnba.entities,com.itnba.aop" ></context:component-scan> <!-- 启动第三方的aspectjweaver.jar中的功能 --> <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> </beans>
一种是通过注解的方式,在代码中加入注解,一种是基于xml配置的方式
1、使用注解的方式:
(1)做一个类,做切面类和切面方法。把这个类放在IOC容器中(自动扫描) 为这个类加上@Compoent注解
package com.itnba.entities; import org.springframework.stereotype.Component; @Component public class Chinese implements IHuman { @Override public void eat() { System.out.println("中国人正在吃饭"); } @Override public void sleep() { System.out.println("中国人正在睡觉"); } }
2、声明某个类为切面,为该类加上@Aspect注解,
在这个类中的方法上,声明方法的前置、后置通知、返回通知、异常通知、环绕通知
package com.itnba.aop; import org.aspectj.lang.JoinPoint; 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.springframework.stereotype.Component; @Aspect @Component public class HumanAOP { @Before("execution(* com.itnba.entities..*.eat(..))") public void beforeEat(){ System.out.println("吃饭前洗手吧"); } @AfterReturning("execution(* com.itnba.entities..*.eat(..))") public void afterEat(){ System.out.println("吃完饭漱口"); } @AfterThrowing(value="execution(* com.itnba.entities..*.eat(..))",throwing="ex") public void except( JoinPoint point, Exception ex ){ System.out.println(point.getSignature().getName()); System.out.println(ex.getMessage()); System.out.println("吃饭噎死了,快去抢救"); } @Before("execution(* com.itnba.entities..*.sleep(..))") public void beforeSleep(){ System.out.println("洗澡后再睡觉"); } }
通知分类:
通知分类: 前置通知(@Before) -- 在目标方法执行前执行的通知。 后置通知(@After) -- 在目标方法执行后执行的通知。无论是否发生异常。后置通知中,无法读取目标方法返回的结果。 返回通知(@AfterReturnning) --在目标方法执行成功后执行的通知。在返回通知中可以访问目标返回结果的。 @AfterReturnning(value="execution(* com.itnba..*(..))",returning="result") public void afterRun(Object result){ System.out.println(result); } 异常通知(@AfterThrowing) -- 在目标方法执行出错后执行的通知。 @AfterThrowing(value="execution(* com.itnba..*(..))",throwing="ex") public void afterThrowing(Exception ex){ System.out.println(ex.getMessage()); } 环绕通知(@Around) -- 需要切面方法携带ProceedingJoinPoion参数,类似于一个完整的动态代理,环绕通知必须要有一个返回值,是目标方法的返回值。 @Around("execution(* com.itnba..*(..))") public object aroundAdvice( ProceedingJoinPoint pjp){ object obj = null; try{ //做前置通知 obj = pjp.proceed(); //做返回通知 } catch(Exception ex){ //做异常通知 } //做后置通知 return obj; }
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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd" default-autowire="byName" > <bean id="chinese" class="com.itnba.entities.Chinese"></bean> <bean id="american" class="com.itnba.entities.American"></bean> <bean id="humanAOP" class="com.itnba.aop.HumanAOP"></bean> <aop:config> <aop:pointcut expression="execution(* com.itnba.entities.*.eat(..))" id="beforeEat"/> <aop:pointcut expression="execution(* com.itnba.entities.*.eat(..))" id="afterEat"/> <aop:aspect id="ha" ref="humanAOP"> <aop:before method="beforeEat()" pointcut-ref="beforeEat"/> <aop:after method="afterEat()" pointcut-ref="afterEat"/> </aop:aspect> </aop:config> </beans>