- spring aop
面向切面編程(AOP),是軟件編程思想發展到一定階段的產物,是對面向對象編程(OOP)的有益補充。AOP一般適用於具有橫切邏輯的場合,如訪問控制、事務管理、性能監測等。
面向切面編程,簡單的說,就是在不改變源程序的基礎上爲代碼段增加新的功能,對代碼進行增強處理,它的設計思想來源於代理設計模式。
瞭解之後需要知道以下概念:
1.增強類型:
前置增強(通知),在在原方法執行之前進行處理,同理還有後置增強、環繞增強、異常拋出增強、最終增強等。
2.連接點(Joinpoint):
程序執行的某個特定位置:如類某個方法調用前、調用後、方法拋出異常後等。
3.切點(Pointcut):
每個類都擁有多個連接點:類的所有方法實際上都是連接點,即連接點是程序類中客觀存在的事務。AOP 通過切點定位到特定的連接點。類比:連接點相當於數據庫中的記錄,切點相當於查詢條件。切點和連接點不是一對一的關係,一個切點匹配多個連接點,切點通過 org.springframework.aop.Pointcut 接口進行描述,它使用類和方法作爲連接點的查詢條件。
需求:UserDao 接口(根據id 獲取用戶信息)
/**
* @note 用戶Dao
* @author liuh
* */
public interface UserDao {
/**
* @note 根據用戶id 獲取用戶
* @author liuh
* */
public User getUser(int id);
}
UserDaoImpl 實現
/**
* @note 用戶UserDao 接口實現
* @author liuh
* */
public class UserDaoImpl implements UserDao{
/**
* @note 根據id 獲取用戶
* @author liuh
* */
@Override
public User getUser(int id){
System.out.println("模擬根據【id】獲取用戶信息實現");
User u=new User();
u.setId(id);
u.setName("hello");
return u;
}
}
- 基於xml配置實現spring aop增強
1.前置增強
(1)創建UserLogger類,新增before_log方法:
/**
* @note 用戶增強類
* @author liuh
* */
public class UserLogger {
/**
* @note 前置
* */
public void before_log(JoinPoint jp){
System.out.println("調用"+jp.getTarget()+"的方法:"+jp.getSignature().getName()+"參數:"+jp.getArgs());
}
}
(2)配置增強實現
<!-- 用戶Dao 實現Bean -->
<bean id="aop_userImpl" class="com.liuh.aop.UserDaoImpl"></bean>
<!-- 用戶增強 實現 Bean -->
<bean id="use_log" class="com.liuh.aop.UserLogger"></bean>
<!-- aop stat -->
<aop:config>
<!-- 切點 -->
<aop:pointcut expression="execution(public * getUser(..))" id="useDao_point"/>
<!-- 增強 -->
<aop:aspect ref="use_log">
<!-- 前置增強 -->
<aop:before method="before_log" pointcut-ref="useDao_point"/>
</aop:aspect>
</aop:config>
<!-- aop end -->
2.後置增強
(1)在新增UserLogger類 afterReturn_log方法
/**
* @note 後置返回值
* */
public void afterReturn_log(JoinPoint jp,Object obj){
System.out.println("調用"+jp.getTarget()+"的方法:"+jp.getSignature().getName()+"參數:"+jp.getArgs()+"返回值:"+((User)obj).getName());
}
(2)後置增強配置
<!-- 用戶Dao 實現Bean -->
<bean id="aop_userImpl" class="com.liuh.aop.UserDaoImpl"></bean>
<!-- 用戶增強 實現 Bean -->
<bean id="use_log" class="com.liuh.aop.UserLogger"></bean>
<!-- aop stat -->
<aop:config>
<!-- 切點 -->
<aop:pointcut expression="execution(public * getUser(..))" id="useDao_point"/>
<!-- 增強 -->
<aop:aspect ref="use_log">
<!-- 後置增強 返回值 -->
<aop:after-returning method="afterReturn_log" pointcut-ref="useDao_point" returning="obj"/>
</aop:aspect>
</aop:config>
<!-- aop end -->
3.環繞增強
(1)在新增UserLogger類 round_log方法
/**
* @note 環繞
* */
public void round_log(ProceedingJoinPoint jp){
System.out.println("前置調用"+jp.getTarget()+"的方法:"+jp.getSignature().getName()+"參數:"+jp.getArgs());
Object obj=null;
try {
obj =jp.proceed();
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("後置調用"+jp.getTarget()+"的方法:"+jp.getSignature().getName()+"參數:"+jp.getArgs()+"返回值:"+((User)obj).getId());
}
(2)環繞配置
<!-- 用戶Dao 實現Bean -->
<bean id="aop_userImpl" class="com.liuh.aop.UserDaoImpl"></bean>
<!-- 用戶增強 實現 Bean -->
<bean id="use_log" class="com.liuh.aop.UserLogger"></bean>
<!-- aop stat -->
<aop:config>
<!-- 切點 -->
<aop:pointcut expression="execution(public * getUser(..))" id="useDao_point"/>
<!-- 增強 -->
<aop:aspect ref="use_log">
<!-- 環繞 -->
<aop:around method="round_log" pointcut-ref="useDao_point"/>
</aop:aspect>
</aop:config>
<!-- aop end -->
4.異常增強(異常拋出增強方法)
(1)在新增UserLogger類 catch_log方法
/**
* @note 異常增強
* */
public void catch_log(JoinPoint jp,RuntimeException e){
try {
throw e;
} catch (Exception e2) {
System.out.println("處理該異常");
// TODO: handle exception
}
System.out.println("異常調用"+jp.getTarget()+"的方法:"+jp.getSignature().getName()+"參數:"+jp.getArgs()+"異常:"+e.getMessage());
}
(2)異常增強配置
<!-- 用戶Dao 實現Bean -->
<bean id="aop_userImpl" class="com.liuh.aop.UserDaoImpl"></bean>
<!-- 用戶增強 實現 Bean -->
<bean id="use_log" class="com.liuh.aop.UserLogger"></bean>
<!-- aop stat -->
<aop:config>
<!-- 切點 -->
<aop:pointcut expression="execution(public * getUser(..))" id="useDao_point"/>
<!-- 增強 -->
<aop:aspect ref="use_log">
<!-- 異常增強 -->
<aop:after-throwing method="catch_log" pointcut-ref="useDao_point" throwing="e"/>
</aop:aspect>
</aop:config>
<!-- aop end -->
5.最終增強
我們知道,如果在目標方法中拋出了異常,就不會執行後續的後置增強。在AspectJ中爲我們提供了一種最終增強,無論是否出了異常都會執行,類似於try-catch中的finally塊,一般用於釋放資源
(1)在新增UserLogger類 after_log方法
/**
* @note 最終
* */
public void after_log(JoinPoint jp){
System.out.println("最終增強調用"+jp.getTarget()+"的方法:"+jp.getSignature().getName()+"參數:"+jp.getArgs());
}
(2)最終增強配置
<!-- 用戶Dao 實現Bean -->
<bean id="aop_userImpl" class="com.liuh.aop.UserDaoImpl"></bean>
<!-- 用戶增強 實現 Bean -->
<bean id="use_log" class="com.liuh.aop.UserLogger"></bean>
<!-- aop stat -->
<aop:config>
<!-- 切點 -->
<aop:pointcut expression="execution(public * getUser(..))" id="useDao_point"/>
<!-- 增強 -->
<aop:aspect ref="use_log">
<!-- 最終增強 -->
<aop:after method="after_log" pointcut-ref="useDao_point"/>
</aop:aspect>
</aop:config>
<!-- aop end -->
- 測試
public class AopTest {
public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userD=(UserDao)ctx.getBean("aop_userImpl");
userD.getUser(1123);
}
}