Aop的三个关键概念简介
Aop思想有三个重要概念:Pointcut,Advice,Advisor。
Pointcut(切入点):
在pointcut之前先说明一个概念:joinPoint(连接点)。Join-Point指程序运行中的某一个阶段点,比如某个方法的调用,异常的抛出。比如上例中的register方法就是一个jion-point。
Pointcut是jion-point的集合,他是程序中需要注入Advice的位置的集合。他指明Advice什么情况下被触发。Spring中用org.springframework.aop.Pointcut接口表示pointcut概念。
Advice(通知)
Advice是某个连接点采用的处理逻辑,也就是向连接点注入的代码。上例中日志输出的代码就是一个advice。
Advisor(通知者)
Advisor是advice和pointcut的配置器,它包括二者。
Spring的三种切入点实现
静态切入点
静态切入点使用类名和方法描述切入点。org.sprinframework.aop.support.RegexpMethodPoint是一个静态切入点的实现。这是一个通用的正则表达式切入点。
(这个切入点的实现使用Jakarta ORO,依赖jakarta-oro-2.0.8.jar)
(Jakarta-ORO是最全面以及优化得最好的正则表达式API之一,Jakarta-ORO库以前叫做OROMatcher,是由Daniel F. Savarese
编写,后来他将其赠与Jakarta Project。是面向JAVA的正则表达式库。)
使用这个切入点的一个案例是:
<bean id="registerPointCut" class="org.springframework.aop.support.RegexpMethodPointcut">
<property name="pattern">
<list>
<value>.*save*.</value>
<value>.*save*.</value>
</list>
</bean>
此配置含义是:所有以sava和do开头的方法为切入点
动态切入点
动态切入点和静态切入点的唯一不同为,动态切入点可以依赖方法参数确定。
Spring有个内建的动态切入点:控制流切入点。
大多数情况下使用静态切入点,极少使用动态切入点。
自定义切入点
Spring中切入点是java类,而不是语言特性,因此可以自定义切入点。
Spring的Advice(通知)
Spring提供了5种Advice的实现类型。Interceptor Around, Before, After Running, Throw, Introduction。他们分别pointcut的前后,前,后,抛出异常,条用之后执行。
Interceptor Around
会在jionpiont前执行,上例中的日志代理类就是一个Interceptor Arouond。
实现Interceptor Around需要实现MehodInterceptor接口:
Public class logInterceptor implements MehodInterceptor{
Public Object invoke(MethodInvocation invocation)throws Throwable{
System.out.println("正在审核...");
Object result = invocation.proceed();
System.out.println("注册完毕");
Return result;
}
}
Before
实现MethodBeforeAdvice接口:
Public class logAdvice implements MethodBeforeAdvice{
Public void before(Method m , Object[] args ,Object target)throws Trowable{
System.out.println("开始审核数据...");
}
}
After Running
实现AfterRunningAdvice接口:
Public class logAdvice implements AfterRuningAdvice {
Public void afterRunning(Method m,Object[] args,Object target)throw Throwable{
System.out.println("注册完毕");
}
}
Throw
实现ThrowAdvice接口:
Public class logThrowAdvice implements ThrowsAdvice{
Public void afterThowing(RemoteException ex)throws Throwable{
System.out.println("审核数据出现异常请检查"+ex);
}
}
Introduction
实现IntroductionAdvice接口和IntroductinoInterceptor接口
Spring的Advisor
org.springframework.aop.support.DefaultPointcutAdvisor是最通用的Advisor类。
使用PorxyFactoryBean创建Aop代理
org.springframework.aop.framework.ProxyFactoryBean是创建代理的最基本的方式。
代理目标类的所有方法
<beans>
<!--Advice-->
<bean id="logAdvice" class="com.test.LogAround" />
<!--被代理的目标类-->
<bean id="register" class="com.test.RegisterImpl"/>
<bean id="logProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--要代理的接口-->
<property name="proxyInterface">
<value>com.test.Register<value>
</property>
<!--要代理的目标类-->
<property name="target">
<ref="register"/>
</property>
<!--advice-->
<property name="interceptorNames">
<list>
<value>logAdvice</value>
</list>
</property>
</bean>
</beans>
代理目标类的指定方法
<beans>
<!--Advice-->
<bean id="logAdvice" class="com.test.LogAround" />
<!--被代理的目标类-->
<bean id="register" class="com.test.RegisterImpl"/>
<!--advisor-->
<bean id="logAdvisor" class="org.springframework.aop.support.RegexpMethodPointAdvisor">
<!--指定advice-->
<property name="advice">
<ref bean="lgoAdivce"/>
</property>
<!--指定代理方法-->
<property name="pattern">
<value>.*log.*</value>
</property>
</bean>
<bean id="logProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--要代理的接口-->
<property name="proxyInterface">
<value="com.test.Register"><value>
</property>
<!--要代理的目标类-->
<property name="target">
<ref="register"/>
</property>
<!--Advisor-->
<property name="interceptorNames">
<list>
<value>logAdvisor</value>
</list>
</property>
</bean>
</beans>
把输出日志的实例改成由spring的Aop特性实现
使用InterceptotionAround 通知实现
/** * * @file:LogAdvice.java * @discript: 输出日志切面的通知类实现MehodInterceptor接口,在jionpoint的前后执行 * @author: yanwushu * @date:2012-6-29 * */ public class LogAdvice implements MethodInterceptor{ private Logger logger = Logger.getLogger(this.getClass().getName());
@Override public Object invoke(MethodInvocation mi) throws Throwable { logger.log(Level.INFO,"开始审核数据..."); try{
Object result = mi.proceed(); return result; }finally { logger.log(Level.INFO,"审核结束"); } } } |
先实现advice。注:MethodInvocation可以获取方法的参数,名称等。
日志接口、实现类不用改。
配置文件applicationContext.xml
<bean id="register" class="util.RegisterImpl"></bean> <bean id="logAdvice" class="advice.LogAdvice"></bean> <bean id="logerProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>util.Register</value> </property> <property name="target"> <ref bean="register"/> </property> <property name="interceptorNames"> <list> <value >logAdvice</value> </list> </property> </bean> |
测试类:
public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); Register register = (Register) ac.getBean("logerProxy"); register.register("张三"); } |
本例完整代码下载