AOP:一个系统,包括很多业务对象.拿一个简单的学生系统作为例子.学生系统需要包括学生服务,课程服务,内容服务等等.而且,几乎每个服务都需要一些公共的模块.比如日志模块,安全模块,事务服务器等等.问题就出来了,我们是在每个业务对象里面都添加这些模块么?我想这样的话不管是复杂度还有测试方面考虑,你都不愿意这么干!就这样,AOP就是解决这个问题的.至于怎么解决,看下面!
1几个AOP术语(下面的术语是这章要用到的几个概念,这些概念是从<<spring in act
通知:别看这个鸟名字,一点实际含义都没的.通知的真正意思是那些公共模块的实现(比如说日志的实现:将日志写入日志文件).下面的例子当中就有三种通知.前,后,环绕.(看不懂,那就看下面!)
目标对象 这个容易理解些.就是你的通知要加入的地方.比如你要在学生服务这个业务对象里面添加一个通知(通知的含义见上面.~~).那这个学生服务就是一个目标对象..
代理 这里之所以说城代理的原因是,spring在实现这个功能的时候使用的是jdk的动态代理.通俗点说,代理就是目标对象+通知!当然,代理是通过配置文件组装的(如果不是这样,那要AOP干嘛).当然,也可以使用其他方式来组装.这样说可能不够严谨.换种说法就是.目标对象是应用AOP前的对象.代理对象就是应用AOP后的对象..而且对于客户对象来说,两个是一样的.不会因为目标对象加了代理而改变
2通知
spring支持的通知有四类.前置通知,后置通知,环绕通知和异常通知.具体懒得解释了.重点的我在下面例子上面写
例子:
目标对象接口(反正都要用接口的,别问为什么.要不就别用spring)
package com.service;
public interface Student {
void addStudent(String s);
}
目标对象实现
package com.serviceimpl;
imp
public class StudentImpl implements Student{
public void addStudent(String s){
System.out.println("欢迎你,"+s+"!");//够简单了吧
}
}
前置通知
package com.advice;
imp
imp
public class BeforeAdvice implements MethodBeforeAdvice {//前置通知就是实现这个接口
public void before (Method method,Object[] args,Object object)throws Throwable{//覆盖这个方法.对应的三个参数分别是方法,参数列表,目标对象
String color=#ff0000>//获取参数.args[0]表示第一个参数
System.out.println("这是beforeAdvice类所带的before方法"+name);
}
}
后置通知
package com.advice;
imp
imp
public class AfterAdvice implements AfterReturningAdvice{
public void afterReturning(Object returnValue,Method method,Object[] arg,Object object) throws Throwable {
System.out.println("这是AfterAdvice类的afterReturning方法.");//returnValue表示目标方法的返回值.本例子就是addStudent方法的返回值(本例子是void的)
}
}
环绕通知 环绕通知与前面两个通知有两个重要区别.一,环绕通知能控制目标方法是否调用(如果要调用,要用MethodInvocation.proceed()方法.二.环绕通知能控制返回的对象(不同于目标方法的返回对象)
前面两种通知的目标方法总是会被调用.除非抛出异常.
package com.advice;
imp
imp
public class CompareInterceptor implements MethodInterceptor{
public Object invoke(MethodInvocation invocation) throws Throwable{
Object result = null;
String stu_name = invocation.getArguments()[0].toString();
if ( stu_name.equals("dragon")){
//如果学生是dragon时,执行目标方法,
result= invocation.proceed();
} else{
System.out.println("此学生是"+stu_name+"而不是dragon,不批准其加入.");
}
return result;
}
}
配置文件applicationContext.xml
<?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="beforeAdvice" class="com.advice.BeforeAdvice"></bean>
<bean id="afterAdvice" class="com.advice.AfterAdvice"></bean>
<bean id="compareInterceptor" class="com.advice.CompareInterceptor"></bean>
<bean id="studenttarget" class="com.serviceimpl.StudentImpl"></bean>//目标对象实现类
<bean id="student">//这个就是创建代理Bean
<property name="proxyInterfaces">
<value>com.service.Student</value>//目标对象接口类
</property>
<property name="interceptorNames">
<list>
<value>beforeAdvice</value>//加入几个通知.这个是上面对应的bean id
<value>afterAdvice</value>
<value>compareInterceptor</value>
</list>
</property>
<property name="target">//实现类
<ref bean="studenttarget"/>
</property>
</bean>
</beans>
测试类,Test.java
package com.act;
imp
imp
imp
public class Test {
public static void main(String[] args) {
ApplicationContext ctx =
new FileSystemXmlApplicationContext("/src/applicationContext.xml");//配置文件我放在SRC下
Student person = (Student)ctx.getBean("student");//这里获得的是代理对象的bean
person.addStudent("dragon");
// person.addStudent("javadragon");
}
}
运行该程序时,要加上commons-logging.jar 包
<property name="proxyInterfaces">
<property name="interceptorNames">
<property name="target">
这三个属性是一定要配置的