Spring的另一個重要思想是AOP,面向切面的編程,它提供了一種機制,可以在執行業務前後執行另外的代碼,Servlet中的Filter就是一種AOP思想的體現,下面通過一個例子來感受一下.
假設我們現在需要在針對數據庫進行CRUD操作時添加一組日志,即在執行CRUD方法前後分別加上一句話,實現簡單的面向切面編程的功能.我用到的是spring4,在配置文件上較之之前的版本可能有些不同.
使用springAPI來實現AOP,除了spring必不可少的核心jar包,還需要兩個jar包需要導入:
並且配置文件的頭文件也需要略作修改,詳見下面實例中的beans.xml.
UserService類(省略數據庫操作代碼,只做簡單的打印來模擬):
public class UserService {
public void add(){
System.out.println("添加用戶");
}
public void delete(){
System.out.println("刪除用戶");
}
public void update(){
System.out.println("修改用戶");
}
public void search(){
System.out.println("查詢用戶");
}
}
Log類(在執行增刪改查方法前執行):
public class Log implements MethodBeforeAdvice{
/***
* method:被調用的方法對象
* arg1:被調用的方法的參數
* target:被調用方法的目標對象
*/
@Override
public void before(Method method, Object[] arg1, Object target)
throws Throwable {
System.out.println(target.getClass().getName()+"中的"+method.getName()+"方法被執行");
}
}
AfterLog類(在執行增刪改查方法後執行):
public class AfterLog implements AfterReturningAdvice{
/**
* returnValue:返回值類型
* method:被調用的方法對象
* arg1:被調用的方法的參數
* target:被調用方法的目標對象
*/
@Override
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"中的"+method.getName()+"方法被執行成功,返回值是"+returnValue);
}
spring配置文件(beans.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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.wang.service.UserService"></bean>
<bean id="log" class="com.wang.log.Log"></bean>
<bean id="afterlog" class="com.wang.log.AfterLog"></bean>
<aop:config>
<!--"*"為通配符表示所有方法
".."表示任意個數的參數 -->
<aop:pointcut expression="execution(* com.wang.service.UserService.*())" id="pointcut"/>
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
測試代碼testDemo:
@Test
public void test1(){
ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
UserService userService=(UserService)context.getBean("userService");
userService.add();
userService.search();
}
運行測試可以看到控制台的打印結果:
com.wang.service.UserService中的add方法被執行
添加用戶
com.wang.service.UserService中的add方法被執行成功,返回值是nullcom.wang.service.UserService中的search方法被執行
查詢用戶
com.wang.service.UserService中的search方法被執行成功,返回值是null
在配置文件中,我們看到了一些這樣的代碼:
<aop:config>
<!--"*"為通配符表示所有方法
".."表示任意個數的參數 -->
<aop:pointcut expression="execution(* com.wang.service.UserService.*())" id="pointcut"/>
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>
</aop:config>
我們來介紹幾個AOP的相關概念,這個就比較好理解了:
簡而言之:"切入點"負責往"什麼地方"插入代碼,"通知"負責插入"什麼代碼".