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的相關概念,這個就比較好理解了:
簡而言之:"切入點"負責往"什麼地方"插入代碼,"通知"負責插入"什麼代碼".