spring的AOP组件是基于这样一种思想:让程序员把分散在代码中的重复功能提取出来,单独编写成一个类(spring叫通知advice),通过动态代理的手段再加入到需要它的地方。
1>.spring要求advice要按照它的要求进行编写。它给提供了四个接口可供使用,以便在目标方法执行的不同时期不同情况下,能够触发执行advice里的方法:
MethodBeforeAdvice:在目标方法调用之前触发执行它的方法before(...);
AfterReturningAdvice:在目标方法返回值之前触发执行它的方法afterReturning(...);
MethodInterceptor: 可以在它的方法invoke(...)执行过程中调用目标方法;
ThrowsAdvice: 在目标方法发生异常时触发执行它实现类里面的方法afterThrowing(...)。
2>.spring通过类org.springframework.aop.framework.ProxyFactoryBean来实现把advice和目标类结合起来完成动态代理功能,向用户提供所需要的代理类。
目标类实现的接口:
public
interface StudentDao {
public void test1();
public void test2() throws Exception;
}
public void test1();
public void test2() throws Exception;
}
目标类:
public
class StudentDaoImpl
implements StudentDao {
public void test1() {
try {
Thread.sleep(2000); //用来使测试时间更加明显
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println( "@@@@执行目标方法:test1()@@@@");
}
public void test2() throws Exception {
System.out.println( "####执行目标方法:test2()####");
throw new SQLException( "test2 has SQLException");
}
}
public void test1() {
try {
Thread.sleep(2000); //用来使测试时间更加明显
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println( "@@@@执行目标方法:test1()@@@@");
}
public void test2() throws Exception {
System.out.println( "####执行目标方法:test2()####");
throw new SQLException( "test2 has SQLException");
}
}
Advice:
public
class SecurityAdvice
implements MethodBeforeAdvice {
/*
* method: 目标方法
* args: 目标方法的参数列表
* target: 目标对象
*/
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println( "====security check for: "+method.getName()+ " ====");
}
}
/*
* method: 目标方法
* args: 目标方法的参数列表
* target: 目标对象
*/
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println( "====security check for: "+method.getName()+ " ====");
}
}
public
class LoggingAdvice
implements AfterReturningAdvice {
/*
* returnValue: 目标方法的返回值
* method: 目标方法
* args: 目标方法的参数列表
* target: 目标对象
*/
@Override
public void afterReturning(Object returnValue, Method method, Object[] args,
Object target) throws Throwable {
System.out.println( "****"+method.getName()+ " run at "+ new Date()+ " ****");
}
}
/*
* returnValue: 目标方法的返回值
* method: 目标方法
* args: 目标方法的参数列表
* target: 目标对象
*/
@Override
public void afterReturning(Object returnValue, Method method, Object[] args,
Object target) throws Throwable {
System.out.println( "****"+method.getName()+ " run at "+ new Date()+ " ****");
}
}
public
class PerformanceAdvice
implements MethodInterceptor {
/**
* invocation: 是对目标方法的一个封装,不但包含了目标方法本身以及它的参数列表,还包括目标对象.
*/
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Long beginTime=System.currentTimeMillis();
Object ret=invocation.proceed(); //对外提供了此方法,用来执行目标方法.
Long endTime=System.currentTimeMillis();
System.out.println( "####"+invocation.getMethod().getName()+ " used "+(endTime-beginTime)+ " ms####");
return ret;
}
}
/**
* invocation: 是对目标方法的一个封装,不但包含了目标方法本身以及它的参数列表,还包括目标对象.
*/
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Long beginTime=System.currentTimeMillis();
Object ret=invocation.proceed(); //对外提供了此方法,用来执行目标方法.
Long endTime=System.currentTimeMillis();
System.out.println( "####"+invocation.getMethod().getName()+ " used "+(endTime-beginTime)+ " ms####");
return ret;
}
}
public
class MyThrowsAdvice
implements ThrowsAdvice {
/**
* ThrowsAdvice接口本身并不包含任何方法,但spring要求它里面要触发的方法必须叫afterThrowing,并且允许程序员无限重载之。其实这也是不得已的做法,因为spring不可能事先定义好目标方法要发生的所有异常情况,交给程序员自行处理也许是个最好的选择。
/**
* ThrowsAdvice接口本身并不包含任何方法,但spring要求它里面要触发的方法必须叫afterThrowing,并且允许程序员无限重载之。其实这也是不得已的做法,因为spring不可能事先定义好目标方法要发生的所有异常情况,交给程序员自行处理也许是个最好的选择。
*需要特别指出的是:当异常发生重叠时,它采用的是最精确匹配执行。
* @param e: 目标方法抛出的异常对象
*/
public void afterThrowing(Exception e) { // 目标方法发生Exception时执行本方法
System.out.println( "@@@@catch Exception " + e.getMessage() + "@@@@");
}
public void afterThrowing(RuntimeException e) { // 目标方法发生RuntimeException时执行本方法
System.out.println( "@@@@catch RuntimeException " + e.getMessage()+ "@@@@");
}
public void afterThrowing(SQLException e) { // 目标方法发生SQLException时执行本方法
System.out.println( "@@@@catch SQLException " + e.getMessage() + "@@@@");
}
public void afterThrowing(IOException e) { // 目标方法发生IOException时执行本方法
System.out.println( "@@@@catch IOException " + e.getMessage() + "@@@@");
}
}
* @param e: 目标方法抛出的异常对象
*/
public void afterThrowing(Exception e) { // 目标方法发生Exception时执行本方法
System.out.println( "@@@@catch Exception " + e.getMessage() + "@@@@");
}
public void afterThrowing(RuntimeException e) { // 目标方法发生RuntimeException时执行本方法
System.out.println( "@@@@catch RuntimeException " + e.getMessage()+ "@@@@");
}
public void afterThrowing(SQLException e) { // 目标方法发生SQLException时执行本方法
System.out.println( "@@@@catch SQLException " + e.getMessage() + "@@@@");
}
public void afterThrowing(IOException e) { // 目标方法发生IOException时执行本方法
System.out.println( "@@@@catch IOException " + e.getMessage() + "@@@@");
}
}
配置文件:
<
beans
>
< bean id ="target" class ="com.yangfei.spring.advice.StudentDaoImpl" >
</ bean >
< bean id ="before" class ="com.yangfei.spring.advice.SecurityAdvice" > </ bean >
< bean id ="after" class ="com.yangfei.spring.advice.LoggingAdvice" > </ bean >
< bean id ="interceptor" class ="com.yangfei.spring.advice.PerformanceAdvice" > </ bean >
< bean id ="throws" class ="com.yangfei.spring.advice.MyThrowsAdvice" > </ bean >
< bean id ="dao" class ="org.springframework.aop.framework.ProxyFactoryBean" >
< property name ="target" ><!-- 目标类 -->
< ref bean ="target" />
</ property >
< property name ="interceptorNames" ><!-- Adivice -->
< list >
< value >before </ value >
< value >after </ value >
< value >interceptor </ value >
< value >throws </ value >
</ list >
</ property >
< property name ="interfaces" ><!-- 目标类实现的接口 -->
< list >
< value >com.yangfei.spring.advice.StudentDao </ value >
</ list >
</ property >
</ bean >
</ beans >
< bean id ="target" class ="com.yangfei.spring.advice.StudentDaoImpl" >
</ bean >
< bean id ="before" class ="com.yangfei.spring.advice.SecurityAdvice" > </ bean >
< bean id ="after" class ="com.yangfei.spring.advice.LoggingAdvice" > </ bean >
< bean id ="interceptor" class ="com.yangfei.spring.advice.PerformanceAdvice" > </ bean >
< bean id ="throws" class ="com.yangfei.spring.advice.MyThrowsAdvice" > </ bean >
< bean id ="dao" class ="org.springframework.aop.framework.ProxyFactoryBean" >
< property name ="target" ><!-- 目标类 -->
< ref bean ="target" />
</ property >
< property name ="interceptorNames" ><!-- Adivice -->
< list >
< value >before </ value >
< value >after </ value >
< value >interceptor </ value >
< value >throws </ value >
</ list >
</ property >
< property name ="interfaces" ><!-- 目标类实现的接口 -->
< list >
< value >com.yangfei.spring.advice.StudentDao </ value >
</ list >
</ property >
</ bean >
</ beans >
测试类:
public
static
void main(String[] args)
throws Exception{
ApplicationContext ctx= new ClassPathXmlApplicationContext( "test.xml");
StudentDao dao=(StudentDao)ctx.getBean( "dao");
dao.test1();
System.out.println();
dao.test2();
}
ApplicationContext ctx= new ClassPathXmlApplicationContext( "test.xml");
StudentDao dao=(StudentDao)ctx.getBean( "dao");
dao.test1();
System.out.println();
dao.test2();
}
运行结果:
====security check for: test1 ====
@@@@执行目标方法:test1()@@@@
####test1 used 2000 ms####
****test1 run at Sat Dec 19 10:04:28 CST 2009 ****
@@@@执行目标方法:test1()@@@@
####test1 used 2000 ms####
****test1 run at Sat Dec 19 10:04:28 CST 2009 ****
====security check for: test2 ====
####执行目标方法:test2()####
@@@@catch SQLException test2 has SQLException@@@@
Exception in thread "main" java.sql.SQLException: test2 has SQLException
at com.cernet.spring.advice.StudentDaoImpl.test2(StudentDaoImpl.java:30)
####执行目标方法:test2()####
@@@@catch SQLException test2 has SQLException@@@@
Exception in thread "main" java.sql.SQLException: test2 has SQLException
at com.cernet.spring.advice.StudentDaoImpl.test2(StudentDaoImpl.java:30)
.......
本文转自NightWolves 51CTO博客,原文链接:http://blog.51cto.com/yangfei520/245613
,如需转载请自行联系原作者