说明
AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的另一个重要特征。AOP把一个业务流程分成几部分,例如权限检查、业务处理、日志记录,每个部分单独处理,然后将他们组装成完整的业务流程。每个部分被称为切面(Aspect)或者关注点。
AOP的相关概念
- 切面Aspect:在本例中,方法withAop()、withoutAop()中都有一些代码。虽然只是一些输出语句,但在真实的程序中这里应该是一些有意义的代码(如读写数据库、权限检查、异常情况记录等)。这些代码可以看做AOP中的切面,可以将切面理解成模块。
- 通知Advisor:本例的三个拦截器都是实现至某个Advisor接口。从类名上看就知道3个拦截器都是AOP中的通知(Advisor)。一旦Spring符合条件,就会派发出通知。与生活中的通知不同的是,Spring中的通知是带有执行代码的,能实现某种功能。
- 切入点Pointcut:在配置拦截器的时候,XML中只配置了withAop()方法使用拦截器,而withoutAop()方法没有配置拦截器。这种配置是借助org.springframework.aop.support.NameMatchMethodPointcutAdvisor完成的。从类名称上看,这是一个切入点(Pointcut)。该类对象能配置对哪些方法使用拦截器,从哪个地方切入进去。配置时可以使用通配符。
即可看成是切入点负责往什么地方插入代码,而通知负责插入什么代码。
实例:使用拦截器拦截方法
Service接口
package interf;
public interface IAopService {
public void withAop() throws Exception;
public void withOutAop() throws Exception;
}
接口实现代码
package example;
import javax.security.auth.login.AccountException;
import interf.IAopService;
public class AopService implements IAopService {
private String name;
@Override
public void withAop() throws Exception {
// TODO Auto-generated method stub
System.out.print("有AOP的函数运行");
System.out.println("name为:"+name);
if(name.trim().length()==0) //检查name是否为空
throw new AccountException(); //抛出异常
}
@Override
public void withOutAop() throws Exception {
// TODO Auto-generated method stub
System.out.print("没有AOP的函数运行");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
方法前拦截器检查name是否为null
package before;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
import example.AopService;
public class IAopMethodBefore implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object obj) throws Throwable {
// TODO Auto-generated method stub
System.out.println("运行前检查..."); //输出信息
System.out.println("即将执行的Method:"+method.getName()); //输出方法名
if(obj instanceof AopService){ //instance关键字判断是不是AOPService类
String name=((AopService) obj).getName();
if(name==null) throw new NullPointerException(); //检查是否为NULL
}
System.out.println("Object:"+obj); //输出对象
}
}
返回后拦截器输出返回值
package after;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class IAopMethodAfter implements AfterReturningAdvice {
@Override
public void afterReturning(Object value, Method method, Object[] args, Object obj) throws Throwable {
// TODO Auto-generated method stub
System.out.println("方法名:"+method.getName()+"返回值为:"+value);
}
}
异常拦截器捕获异常
package exception;
import java.lang.reflect.Method;
import javax.security.auth.login.AccountException;
import org.springframework.aop.ThrowsAdvice;
public class ThrowsInterceptor implements ThrowsAdvice{ //异常捕获器
//方法一
public void afterThrowing(Method method,Object[] args,Object obj,AccountException ex) throws Throwable{
System.out.println("方法:"+method+"抛出了异常:"+ex);
}
//方法二
public void afterThrowing(NullPointerException ex) throws Throwable{
System.out.println("空指针异常:抛出了异常:"+ex);
}
}
拦截器配置
ApplicationContext.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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- 拦截器 在withAop()方法前运行 安装到NameMatchMethodPointcutAdvice中 -->
<bean id="aopMethodBefore" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice">
<bean class="before.IAopMethodBefore"></bean>
</property>
<property name="mappedName" value="withAop"></property>
</bean>
<!-- 拦截器 在withAop()方法后运行 安装到NameMatchMethodPointcutAdvice中 -->
<bean id="aopMethodAfter" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice">
<bean class="after.IAopMethodAfter"></bean>
</property>
<property name="mappedName" value="withAop"></property>
</bean>
<!-- 拦截器 在异常抛出后运行 安装到NameMatchMethodPointcutAdvice中 -->
<bean id="aopException" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice">
<bean class="exception.ThrowsInterceptor"></bean>
</property>
<property name="mappedName" value="withAop"></property>
</bean>
<!-- Service对象 安装到ProxyFactoryBean对象中 -->
<bean id="aopService" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 多个拦截器 -->
<property name="interceptorNames">
<list>
<value>aopMethodBefore</value>
<value>aopMethodAfter</value>
<value>aopException</value>
</list>
</property>
<!-- 被拦截的对象 -->
<property name="target">
<bean class="example.AopService">
<property name="name" value="HelloMyQiu"></property>
</bean>
</property>
</bean>
</beans>
运行代码
package example;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
import interf.IAopService;
public class AopRun {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(new ClassPathResource("ApplicationContext.xml"));
IAopService service=(IAopService) beanFactory.getBean("aopService");
service.withAop();
service.withOutAop();
beanFactory.destroySingletons(); //销毁对象
}
}
结果贴图
总结
拦截器与Filter的区别
二者都是AOP编程思想的体现,都能实现权限检查、日志记录等。
Filter是Servlet规范规定的,只能用于Web程序中,而拦截器还能用于Swing、Application程序中。规范不同,Servlet容器和Spring容器支持,拦截器能使用Spring里任何资源,Filter只能在Servlet前后起作用,而拦截器能深入方法前后、异常前后等。所以在Spring下尽量能使用拦截器就不用Filter