AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的一个重要特征
Spring推荐使用接口编程
Spring提供三种拦截器:方法前拦截器、返回后拦截器、异常抛出拦截器
拦截器定义
- //Service接口
- public interface IAopService{
- public void withAop() throws Exception; //将会被拦截
- public void withoutAop() throws Exception; //不会被拦截
- }
- public class AopServiceImpl implements IAopService{
- private String name;
- public void withAop() throws Exception{
- System.out.println("有AOP的函数运行。name:"+name);
- if(name.trim().length() == 0){
- throw new AccountException("name属性不能为空");
- }
- }
- public void withoutAop() throws Exception{
- System.out.println("没有AOP的函数运行。");
- }
- public void setName(String name){
- this.name = name;
- }
- public String getName(){
- return this.name;
- }
- }
//Service接口
public interface IAopService{
public void withAop() throws Exception; //将会被拦截
public void withoutAop() throws Exception; //不会被拦截
}
public class AopServiceImpl implements IAopService{
private String name;
public void withAop() throws Exception{
System.out.println("有AOP的函数运行。name:"+name);
if(name.trim().length() == 0){
throw new AccountException("name属性不能为空");
}
}
public void withoutAop() throws Exception{
System.out.println("没有AOP的函数运行。");
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
}
- //方法前拦截器,检查name是否为空
- import org.springframework.aop.MethodBeforeAdvice;
- public class MethodBeforeInterceptor implements MethodBeforeAdvice{
- //调用对象的方法前执行该方法
- //参数分别为被调用的方法、被调用方法的参数、对象
- public void before(Method method,Object [] args,Object instance) throws Throwable{
- System.out.println("即将执行方法:"+method.getName());
- //
- if(instance instanceof AopServiceImpl){
- String name = ((AopServiceImpl)instance).getName();
- if(name == null){
- throw new NullPointerException("name不能为空");
- }
- }
- }
- }
//方法前拦截器,检查name是否为空
import org.springframework.aop.MethodBeforeAdvice;
public class MethodBeforeInterceptor implements MethodBeforeAdvice{
//调用对象的方法前执行该方法
//参数分别为被调用的方法、被调用方法的参数、对象
public void before(Method method,Object [] args,Object instance) throws Throwable{
System.out.println("即将执行方法:"+method.getName());
//
if(instance instanceof AopServiceImpl){
String name = ((AopServiceImpl)instance).getName();
if(name == null){
throw new NullPointerException("name不能为空");
}
}
}
}
- //返回后拦截器
- import org.springframework.aop.AfterReturningAdvice;
- public class MethodAfterInteceptor implements AfterReturningAdvice{
- //参数分别为方法返回值、被调用方法、方法参数、被拦截的对象
- public void afterReturning(Object value,Method method,Object [] args,Object instance) throws Throwable{
- System.out.println("方法:"+method.getName()+"执行完毕,返回值为:"+value);
- }
- }
//返回后拦截器
import org.springframework.aop.AfterReturningAdvice;
public class MethodAfterInteceptor implements AfterReturningAdvice{
//参数分别为方法返回值、被调用方法、方法参数、被拦截的对象
public void afterReturning(Object value,Method method,Object [] args,Object instance) throws Throwable{
System.out.println("方法:"+method.getName()+"执行完毕,返回值为:"+value);
}
}
- //异常拦截器捕获异常
- import org.springframework.aop.ThrowAdvice;
- public class ThrowsInterceptor implements ThrowAdvice{
- //参数分别为被调用的方法、方法参数、对象实例、抛出的异常
- //前三个参数可以省略,第四个参数是必须的,这样设计是为了使开发者灵活地定义多个方法捕获各种不同的异常
- public void afterThrowing(Method method,Object [] args,Object instance,AccountException ex) throws Throwable {
- System.out.println("方法:"+method.getName()+"抛出了异常:"+ex);
- }
- public void afterThrowing(NullPointerException ex) throws Throwable {
- System.out.println("抛出了异常:"+ex);
- }
- }
//异常拦截器捕获异常
import org.springframework.aop.ThrowAdvice;
public class ThrowsInterceptor implements ThrowAdvice{
//参数分别为被调用的方法、方法参数、对象实例、抛出的异常
//前三个参数可以省略,第四个参数是必须的,这样设计是为了使开发者灵活地定义多个方法捕获各种不同的异常
public void afterThrowing(Method method,Object [] args,Object instance,AccountException ex) throws Throwable {
System.out.println("方法:"+method.getName()+"抛出了异常:"+ex);
}
public void afterThrowing(NullPointerException ex) throws Throwable {
System.out.println("抛出了异常:"+ex);
}
}
拦截器配置
Spring无法将Service的实现类与拦截器直接组装,因为没有对应的setter、getter方法。安装时借助的是Spring的代理类,把拦截器安装到NameMatchMethodPointcutAdvisor中,把自动以的Service安装到ProxyFactoryBean中,然后组装到一块- <!-- 方法前拦截器MethodBeforeInterceptor安装到NameMatchMethodPointcutAdvisor中 -->
- <bean id="aopMethodBeforeInterceptor" class="org.springframework.aop.support. NameMatchMethodPointcutAdvisor">
- <!-- 拦截器的实现类-->
- <property name="advice">
- <bean class="com.clf.spring. MethodBeforeInterceptor">
- </property>
- <!-- 欲拦截的方法名-->
- <property name="mappedName" value="withAop"> </property>
- </bean>
- <!-- 类似的方式配置返回后前拦截器MethodAfterInteceptor -->
- <bean id="aopMethodAfterInterceptor" class="org.springframework.aop.support. NameMatchMethodPointcutAdvisor">
- <property name="advice">
- <bean class="com.clf.spring. MethodAfterInteceptor">
- </property>
- <property name="mappedName" value="withAop"> </property>
- </bean>
- <!-- 类似的方式配置异常前拦截器MethodAfterInteceptor -->
- <bean id="aopThrowsInterceptor" class="org.springframework.aop.support. NameMatchMethodPointcutAdvisor">
- <property name="advice">
- <bean class="com.clf.spring. ThrowsInterceptor">
- </property>
- <property name="mappedName" value="withoutAop"> </property>
- </bean>
- <!-- Service实现类,安装到ProxyFactoryBean -->
- <bean id="aopService" class="org.springframework.aop.ProxyFactoryBean">
- <!-- 安装拦截器-->
- <property name="interceptorNames">
- <list>
- <value>aopMethodBeforeInterceptor</value>
- <value>aopMethodAfterInterceptor</value>
- <value>aopThrowsInterceptor</value>
- </list>
- </property>
- <!—被拦截的对象-->
- <property name="target">
- <bean class="com.clf.spring.AopServiceImpl">
- <property name="name" value="HelloSpring"></property>
- </bean>
- </property>
- </bean>
<!-- 方法前拦截器MethodBeforeInterceptor安装到NameMatchMethodPointcutAdvisor中 -->
<bean id="aopMethodBeforeInterceptor" class="org.springframework.aop.support. NameMatchMethodPointcutAdvisor">
<!-- 拦截器的实现类-->
<property name="advice">
<bean class="com.clf.spring. MethodBeforeInterceptor">
</property>
<!-- 欲拦截的方法名-->
<property name="mappedName" value="withAop"> </property>
</bean>
<!-- 类似的方式配置返回后前拦截器MethodAfterInteceptor -->
<bean id="aopMethodAfterInterceptor" class="org.springframework.aop.support. NameMatchMethodPointcutAdvisor">
<property name="advice">
<bean class="com.clf.spring. MethodAfterInteceptor">
</property>
<property name="mappedName" value="withAop"> </property>
</bean>
<!-- 类似的方式配置异常前拦截器MethodAfterInteceptor -->
<bean id="aopThrowsInterceptor" class="org.springframework.aop.support. NameMatchMethodPointcutAdvisor">
<property name="advice">
<bean class="com.clf.spring. ThrowsInterceptor">
</property>
<property name="mappedName" value="withoutAop"> </property>
</bean>
<!-- Service实现类,安装到ProxyFactoryBean -->
<bean id="aopService" class="org.springframework.aop.ProxyFactoryBean">
<!-- 安装拦截器-->
<property name="interceptorNames">
<list>
<value>aopMethodBeforeInterceptor</value>
<value>aopMethodAfterInterceptor</value>
<value>aopThrowsInterceptor</value>
</list>
</property>
<!—被拦截的对象-->
<property name="target">
<bean class="com.clf.spring.AopServiceImpl">
<property name="name" value="HelloSpring"></property>
</bean>
</property>
</bean>
AOP相关概念
切面Aspect在本例中,方法withAop()、withoutAop()中都有一些代码,这些代码可以看做是AOP中的切面,可以将切面理解为模块
通知Advisor
本例的三个拦截器都是实现自某个接口,从类名上看就知道三个拦截器都是AOP中的通知。一旦Spring符合条件,就会派发出通知,即一些需要执行的代码,能实现某种功能
切入点Pointcut
在配置拦截器时,XML中只配置了withAop()方法使用拦截器,而withoutAop()方法没有配置拦截器,这种配置是借助于org.springframework.aop.support. NameMatchMethodPointcutAdvisor完成的。这就是一个切入点,配置时可以使用通配符。该类明上也带有Advisor是因为它也是用通知实现的
简单地说,切入点负责往什么地方插入代码,而通知负责插入什么代码
Spring提供灵活的切入点配置,例如使用正则表达式
- <bean id="advisorTest" class="org.springframework.aop.support.RegexMethodPointcutAdvisor">
- <property name="interceptor">
- <ref local="someInterceptor">
- </property>
- <property name="pattern">
- <list>
- <value>.*get*</value>
- <value>.*set*</value>
- </list>
- </property>
- </bean>