这节来学习下AOP,常说的面向切面编程,面向切面编程能提取公用的业务组件做为切面,从而减少实际业务代码的工作量,AOP经常分离的几个切面有:日志管理模块,安全管理模块,事务管理模块。
下面来看下简单的一个日志记录切面(方法前置和后置通知):
先来定义下两个通知:
前置通知:
package aop;
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.MethodBeforeAdvice;
/**
* @ClassName: LogBeforeAdvice
* @Description: 日志通知
* @author sunrain
* @date 2011-1-3
*/
public class LogBeforeAdvice implements MethodBeforeAdvice {
private static final Log log = LogFactory.getLog(LogBeforeAdvice.class);
/* (非 Javadoc)
* <p>Title: before</p>
* <p>Description:定义调用方法前的通知 </p>
* @param method
* @param arg1
* @param target
* @throws Throwable
* @see org.springframework.aop.MethodBeforeAdvice#before(java.lang.reflect.Method, java.lang.Object[], java.lang.Object)
*/
public void before(Method method, Object[] arg1, Object target)
throws Throwable {
log.info(target.getClass().getName()+"’s "+method.getName()+" invoked");
}
}
后置通知:
package aop;
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.AfterReturningAdvice;;
/**
* @ClassName: LogAfterAdvice
* @Description: 日志通知
* @author sunrain
* @date 2011-1-3
*/
public class LogAfterAdvice implements AfterReturningAdvice {
private static final Log log = LogFactory.getLog(LogAfterAdvice.class);
public void afterReturning(Object arg0, Method method, Object[] arg2,
Object target) throws Throwable {
log.info(target.getClass().getName()+"’s "+method.getName()+" invoked");
}
}
来看看通知是怎么实现通知拦截的:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="helloWorld" class="HelloWorldServiceImpl"> <property name="name"> <value>sunrain</value> </property> </bean> <bean id="personTask" class="ioc.TaskImpl"> <constructor-arg> <value>sunrain</value> </constructor-arg> <property name="living" ref="person"></property> </bean> <bean id="dogTask" class="ioc.TaskImpl"> <constructor-arg> <value>tt</value> </constructor-arg> <property name="living" ref="dog"></property> </bean> <bean id="person" class="ioc.Person"> </bean> <bean id="dog" class="ioc.Dog"> </bean> <bean id="logBeforeAdvice" class="aop.LogBeforeAdvice"></bean> <bean id="logAfterAdvice" class="aop.LogAfterAdvice"></bean> <bean id="dogAdviceTask" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <list> <value>ioc.Task</value> </list> </property> <property name="interceptorNames"> <list> <value>logBeforeAdvice</value> <value>logAfterAdvice</value> </list> </property> <property name="target"> <ref bean="dogTask"/> </property> </bean> </beans>
这里借助了代理bean ,来代理Task接口,下面写个测试类:
package aop;
import ioc.Task;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
public class AdviceTest {
/**
* @Title: main
* @Description: AOP 方法前置通知测试类
* @param @param args 设定文件
* @return void 返回类型
* @throws
*/
public static void main(String[] args) {
Resource res = new FileSystemResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(res);
Task t = (Task)factory.getBean("dogAdviceTask");
t.say();
}
}
对AOP理解的还不够,会慢慢更新的,看下日志:
0103/16:44:17 <INFO > [org.springframework.core.CollectionFactory 66] JDK 1.4+ collections available
0103/16:44:17 <INFO > [org.springframework.core.CollectionFactory 71] Commons Collections 3.x available
0103/16:44:17 <INFO > [org.springframework.beans.factory.xml.XmlBeanDefinitionReader 163] Loading XML bean definitions from file [G:\workspace\SpringStudy\beans.xml]
0103/16:44:18 <INFO > [org.springframework.aop.framework.DefaultAopProxyFactory 64] CGLIB2 available: proxyTargetClass feature enabled
0103/16:44:18 <INFO > [aop.LogBeforeAdvice 30] ioc.TaskImpl’s say invoked
0103/16:44:18 <INFO > [ioc.TaskImpl 32] tt say :汪汪汪
0103/16:44:18 <INFO > [aop.LogAfterAdvice 22] ioc.TaskImpl’s say invoked
下面介绍下用另外一种方式来实现这个:MethodInterceptor
package aop;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @ClassName: LogAdvice
* @Description: 日志前后置通知模拟
* @author sunrain
* @date 2011-1-3
*/
public class LogAdvice implements MethodInterceptor {
private static final Log log = LogFactory.getLog(LogAdvice.class);
public Object invoke(MethodInvocation invocation) throws Throwable {
log.info(invocation.getThis().getClass().getName()+"’s before "+invocation.getMethod().getName()+" invoked");
invocation.proceed();
log.info(invocation.getThis().getClass().getName()+"’s after "+invocation.getMethod().getName()+" invoked");
return null;
}
}
改下xml配置:
<bean id="logAdvice" class="aop.LogAdvice"></bean> <bean id="dogAdviceTask1" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <list> <value>ioc.Task</value> </list> </property> <property name="interceptorNames"> <list> <value>logAdvice</value> </list> </property> <property name="target"> <ref bean="dogTask"/> </property> </bean>
在测试类AdviceTest.java中加个调试吧
package aop;
import ioc.Task;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
public class AdviceTest {
/**
* @Title: main
* @Description: AOP 方法前置通知测试类
* @param @param args 设定文件
* @return void 返回类型
* @throws
*/
public static void main(String[] args) {
Resource res = new FileSystemResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(res);
Task t = (Task)factory.getBean("dogAdviceTask");
t.say();
t = (Task)factory.getBean("dogAdviceTask1");
t.say();
}
}
看下日志:
0103/17:37:47 <INFO > [org.springframework.core.CollectionFactory 66] JDK 1.4+ collections available 0103/17:37:47 <INFO > [org.springframework.core.CollectionFactory 71] Commons Collections 3.x available 0103/17:37:47 <INFO > [org.springframework.beans.factory.xml.XmlBeanDefinitionReader 163] Loading XML bean definitions from file [G:\workspace\SpringStudy\beans.xml] 0103/17:37:47 <INFO > [org.springframework.aop.framework.DefaultAopProxyFactory 64] CGLIB2 available: proxyTargetClass feature enabled 0103/17:37:47 <INFO > [aop.LogBeforeAdvice 30] ioc.TaskImpl’s say invoked 0103/17:37:47 <INFO > [ioc.TaskImpl 32] tt say :汪汪汪 0103/17:37:47 <INFO > [aop.LogAfterAdvice 22] ioc.TaskImpl’s say invoked 0103/17:37:47 <INFO > [aop.LogAdvice 17] ioc.TaskImpl’s before say invoked 0103/17:37:47 <INFO > [ioc.TaskImpl 32] tt say :汪汪汪 0103/17:37:47 <INFO > [aop.LogAdvice 19] ioc.TaskImpl’s after say invoked
看效果差不多吧,呵呵
这样,我们就能拦截方法的调用了,做一些自己想做的限制或者业务了。比如实现每个用户只能买一个果酱(书上看的喽)