Spring-AOP
概述
1、AOP即Aspect-Oriented Programming,他是面向切面编程的核心思想。
2、AOP与OOP即面向对象的编程语言,不相冲突,他们是两个相辅相成的设计模式。
3、Spring的容器并不依赖于AOP。
AOP简介
1。AOP专业术语:
Cross-cutting concern:系统层面上的服务穿插到业务逻辑的处理流程之中
Aspect:当需要时,将其放到应用程序之上,不需要时,将其从应用程序中解脱出来。
Advice:Aspect的具体实现。
Joinpoint:连接点,Aspect在应用程序执行时,加入业务流程的时机。
pointcut:切入点,通过定义pointcut,可以指定某个Aspect在哪些Joinpoint时,被穿插至应用程序之上。
target:是一个目标对象,一个advice被应用的对象和目标对象。
instruction:为已编写、编译完成的类,在执行时期动态的加入一些方法,而不用修改和增加任何代码。
weave:即织入,被应用到对象之上的过程,AOP织入有3个状态:编译,类加载,执行时期
2、Spring对AOP的支持
1、纯jiava语言编写。
2、定义pointcuts可以使用配置文件。
3、不支持属性成员的joinpoints。
3、Spring创建Advice
一:Before Advice:会在目标对象traget的方法执行之前被调用
通过实现MethodBeforeAdvice接口来实现:
实现步骤:
1:创建代理对象接口类
public interface Ihello { public void saychina(String str); public void meiguosay(String str); }
2:创建目标对象类,并实现代理对象接口类。
public class hello implements Ihello { public void saychina(String str){ System.out.println("你好中国人"+str); } public void meiguosay(String str) { System.out.println("你好美国人"+str); } }
3:创建一个Advice类,并实现MethodBeforeAdvice接口,重写方法
import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class SaybeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { System.out.println("在方法调用之前做的事情!"); } }
4:创建applicationContext.xml,并配置
<!-- 建立目标对象实例 --> <bean id="hello" class="hello"></bean> <!-- 建立Advice实例 --> <bean id="sab" class="SaybeforeAdvice"></bean> <!-- 建立代理实例 --> <bean id="hellopoxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 设定代理的接口 --> <property name="proxyInterfaces"> <value>Ihello</value> </property> <!-- 设定目标对象 实例--> <property name="target"> <ref bean="hello"/> </property> <!-- 建立Advice实例 --> <property name="interceptorNames"> <list> <value>sab</value> </list> </property> </bean>
二:afterAdvice:afterReturning
1、会在目标方法被执行之后调用。
2、通过实现afterReturningAdvice接口来实现。并重写public void afterReturning(Object arg0, Method arg1, Object[] arg2,
Object arg3) throws Throwable {}方法
import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; public class afterAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { System.out.println("在目标对象执行完之后调用"); } }
<!-- 建立目标对象实例 --> <bean id="hello" class="hello"></bean> <!-- 建立Advice实例 --> <bean id="sab" class="SaybeforeAdvice"></bean> <bean id="aab" class="afterAdvice"></bean> <!-- 建立代理实例 --> <bean id="hellopoxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 设定代理的接口 --> <property name="proxyInterfaces"> <value>Ihello</value> </property> <!-- 设定目标对象 实例--> <property name="target"> <ref bean="hello"/> </property> <!-- 建立Advice实例 --> <property name="interceptorNames"> <list> <value>sab</value> <value>aab</value> </list> </property> </bean>
三:Around Advice:在目标对象方法执行前后都执行
要实现MethodInterceptor接口并重写public Object invoke(MethodInvocation arg0) throws Throwable {
//目标对象执行之前执行的代码
?????
arg0.proceed();
//目标对象执行之后执行的代码块
????
//该方法有返回值
return Object;
}
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class SayAroundAdive implements MethodInterceptor { @Override public Object invoke(MethodInvocation arg0) throws Throwable { System.out.println("开始之前奏"); arg0.proceed(); System.out.println("完事之后的服务"); return null; } }
四:throw Advice:异常发生的时候,通知某个服务对象做处理,只是提示异常信息,不会处理异常
实现ThrowsAdvice接口,该接口没有方法,可自定义方法。
可在测试目标对象方法中抛出自定义异常:Throw new exception("发生异常");
public class SayThrowAdvice implements ThrowsAdvice { public void afterThrowing(Method method,Object[]objs,Object target,Throwable ta){ //输出 异常的 内容 和 抛出 异常的 方法 System.out.println("exception happened"+ta+"and was thrown in"+method); } }
配置Spring配置文件
<!-- 建立目标对象实例 --> <bean id="hello" class="hello"></bean> <!-- 建立Advice实例 --> <!-- befoer Advice --> <bean id="sab" class="SaybeforeAdvice"></bean> <!-- after Advice --> <bean id="aab" class="afterAdvice"></bean> <!-- Around Advice --> <bean id="srb" class="SayAroundAdive"></bean> <!-- throwAdice --> <bean id="tad" class="SayThrowAdvice"></bean> <!-- 建立代理实例 --> <bean id="hellopoxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 设定代理的接口 --> <property name="proxyInterfaces"> <value>Ihello</value> </property> <!-- 设定目标对象 实例--> <property name="target"> <ref bean="hello"/> </property> <!-- 建立Advice实例 --> <property name="interceptorNames"> <list> <!-- <value>sab</value> <value>aab</value> <value>srb</value> --> <value>tad</value> </list> </property> </bean>
五:基于xml Schema创建Advice
目标对象类,代理类,Adivce类(可自定义,无需实现接口)
优点:简化代码实现,容易对应用程序进行维护,所有元素都定义在<aop:config>标签元素中
import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class BeforeAdive { public void before(){ System.out.println("之前的事情!"); } }
<aop:config>标签
可包含多个切面(aspect),切入点(pointcut),advice等标签元素
<aop:aspect>标签元素
定义一个切面
<aop:pointcut>:定义切入点的信息。
experssion是执行的表达式:常用形式1、*符号:表示匹配任意的返回类型
2、():表示匹配一个不带参数的方法
3、(..):表示匹配了一个带任意参数的方法
<aop:after>定义一个after Advice
<aop:before>定义一个before Advice
<aop:around>定义一个Around Advice
<?xml version="1.0" encoding="UTF-8"?> <!-- 需先在beans声明xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd" --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" 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.1.xsd "> <!-- adivice类实例 --> <bean id="beforeAdvice" class="BeforeAdive" ></bean> <!-- 目标对象实例 --> <bean id="hello" class="hello" ></bean> <aop:config > <!-- 定义切入点 --> <aop:pointcut expression="execution(public void *(..))" id="helloPointcut" /> <!-- 定义切面 --> <aop:aspect ref="beforeAdvice" > <!-- 定义advice类型,方法,和关联类 --> <aop:before method="before" pointcut-ref="helloPointcut" /> </aop:aspect> </aop:config> </beans>
六、基于annotation创建Advice
七、定义pointcut、advice
Spring中的pointcutAdvisor将pointcut和advice结合成一个对象
1、NameMatchMethodPointcutAdvisor():匹配方法名
2、RegexpMethodPointcutAdvisor():用正则表达式的方式定义(静态pointcut实例)
实例应用xml代码
<!-- 建立目标对象实例 --> <bean id="hello" class="hello"></bean> <!-- 建立Advice实例 --> <!-- befoer Advice --> <bean id="sab" class="SaybeforeAdvice"></bean> <!-- after Advice --> <bean id="aab" class="afterAdvice"></bean> <!-- Around Advice --> <bean id="srb" class="SayAroundAdive"></bean> <!-- throwAdice --> <bean id="tad" class="SayThrowAdvice"></bean> <!-- 建立Spring内置pointcutAdvisor:NameMatchMethodPointcutAdvisor --> <bean id="helloPerson" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <!-- 制定匹配的方法名 :以say开头的方法--> <property name="mappedName"> <value>say*</value> </property> <!-- 制定与之关联的advice --> <property name="advice"> <ref bean="sab"/> </property> </bean> <!-- 建立Spring内置pointcutAdvisor:RegexpMethodPointcutAdvisor --> <bean id="helloPerson2" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <!-- 制定匹配的正则表达式 --> <property name="pattern"> <value>.*say.*</value> </property> <!-- 制定与之关联的advice --> <property name="advice"> <ref bean="aab"/> </property> </bean> <!-- 建立代理实例 --> <bean id="hellopoxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 设定代理的接口 --> <property name="proxyInterfaces"> <value>Ihello</value> </property> <!-- 设定目标对象 实例--> <property name="target"> <ref bean="hello"/> </property> <!-- 建立Advice实例 --> <property name="interceptorNames"> <list> <value>helloPerson</value> <value>helloPerson2</value> <!--<value>srb</value> <value>tad</value> --> </list> </property> </bean> </beans>
八、动态代理
1、通过动态的代理模式,在目标对象的方法调用前后,插入相应的处理代码
2、Spring所实现的动态代理,其内置的aop默认使用动态代理模式来实现。
3、不必为特定的对象或者方法编写实现特定功能的代理对象。
3、一个处理者类必须实现invocationHandler接口