采用上一篇的注释虽然好,但是代码分散,也不容量看出彼此的关系,对于应用来说维护不方便。
以下采用自动组装方式
1.定义一个接口
package test.org.springframework.aop.aspectj.ycl.service;
/**
* <p>接口[引入]</p>
* @author chunlongy
*
*/
public interface AService {public void fooA(String _msg);
public void barA();
public int get(int a);
}
2.定义一个实现
package test.org.springframework.aop.aspectj.ycl.service;
/**
* 接口A的实现
* @author chunlongy
*
*/
public class AServiceImpl implements AService {public void barA() {
// TODO Auto-generated method stub
System.out.println("AServiceImpl.barA()");
}public void fooA(String _msg) {
// TODO Auto-generated method stub
System.out.println("AServiceImpl.fooA(msg:"+_msg+")");
}
public int get(int a){
return a;
}}
3.定义另一个基本类
package test.org.springframework.aop.aspectj.ycl.service;
public class BServiceImpl {
public void barB(String _msg, int _type) {
System.out.println("BServiceImpl.barB(msg:"+_msg+" type:"+_type+")");
if(_type == 1)
throw new IllegalArgumentException("测试异常个尼");
}
public void fooB() {
System.out.println("BServiceImpl.fooB()");
}}
4.定义一个切面
package test.org.springframework.aop.aspectj.ycl;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;/**
* <p>切面</p>
* @author chunlongy
*
*/
public class TestAspect {public void doAfter(JoinPoint jp) {
System.out.println("log Ending method: "
+ jp.getTarget().getClass().getName() + "."
+ jp.getSignature().getName());
}
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
long time = System.currentTimeMillis();
Object retVal = pjp.proceed(); //这是主方法的执行
//i will be rewrite the method's result;
time = System.currentTimeMillis() - time;
System.out.println("ycl:process time: " + time + " ms");
//int aa=Integer.parseInt(retVal.toString())+3;
//这里重新设置返回值.
return retVal;
}
public void doBefore(JoinPoint jp) {
System.out.println("log Begining method: "
+ jp.getTarget().getClass().getName() + "."
+ jp.getSignature().getName());
}
public void doThrowing(JoinPoint jp, Throwable ex) {
System.out.println("method " + jp.getTarget().getClass().getName()
+ "." + jp.getSignature().getName() + " throw exception");
System.out.println(ex.getMessage());
}
private void sendEx(String ex) {
//TODO 发送短信或邮件提醒
}
}
5.定义app.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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"
default-autowire="autodetect">
<aop:config>
<aop:aspect id="TestAspect" ref="aspectBean">
<aop:pointcut id="businessService"
expression="execution(* test.org.springframework.aop.aspectj.ycl.service.*.*(..))" />
<!-- 定义连接点 -->
<aop:before pointcut-ref="businessService" method="doBefore"/><!-- 定义前置通知 -->
<aop:after pointcut-ref="businessService" method="doAfter"/> <!-- 定义后置通知 -->
<aop:around pointcut-ref="businessService" method="doAround"/> <!--定义环绕通知 -->
<aop:after-throwing pointcut-ref="businessService" method="doThrowing" throwing="ex"/>
<!-- 定义异常通知 -->
</aop:aspect>
</aop:config>
<bean id="aspectBean" class="test.org.springframework.aop.aspectj.ycl.TestAspect" />
<!-- 切面 -->
<bean id="aService" class="test.org.springframework.aop.aspectj.ycl.service.AServiceImpl"></bean>
<!-- a类 -->
<bean id="bService" class="test.org.springframework.aop.aspectj.ycl.service.BServiceImpl"></bean>
<!-- b类 -->
</beans>
6. 测试用例
package test.org.springframework.aop.aspectj.ycl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import test.org.springframework.aop.aspectj.ycl.service.AService;
import test.org.springframework.aop.aspectj.ycl.service.BServiceImpl;public class AOPTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
AOPTest test=new AOPTest();
test.domy();
}
public void domy(){
ApplicationContext context = new ClassPathXmlApplicationContext(
"app.xml", this.getClass());
//AService aservice=(AService)context.getBean("aService");
//System.out.println("result"+aservice.get(1));
//采用proxy
BServiceImpl bservice=(BServiceImpl)context.getBean("bService");
bservice.barB("ycl", 1);
//采用cglib
}}
讲解:前置通知,后置通知是无论如何都是在方法前和方法后调用的,而环绕通知的执行方式是可以重写或跳过主程序的执行,或都用另一个方法代替主程序的执行,异常通知,则当发生异常时如果要记录日志等操作,则会拦截异常信息。
Spring的AOP解决了调用者和被调用者的耦合,但是却是基于方法的调用,比如我一个项目的Action调用Service的方法,那么我Action就必须调用相应的逻辑处理,当然这是必须的,然后返回相应的响应。
我指的只是一方面,我Action只调用逻辑是很简单的,在调用之前还要加一些请求参数等Validate,那么我完全可以把这些参数组装成对象,然后在调用逻辑方法之前进行拦截,如果不通过,则可以跳过逻辑的执行,正常完成跳转。在调用时可能会有一些Exception,那么我完全可以拦截Exception,并记录异常日志。在调用后可能需要关系数据的同步,那么可以执行目标同步方法。
当然AOP可以完成很多关联程序的执行,在不改变原程序代码的情况下进行相应的扩展,包括事务,日志等的控制。