SSM框架之Spring-AOP的理解與基本使用
logger
SSM 框架學習 (Spring篇)
一、我對AOP的理解
什麼是切面程式設計:我們把一段程式執行流程比喻成一條水果大小分揀流水線,而AOP的思想就是可以在這個流水線的某個點設定一個檢查點,或者說大小過濾器,不同的過濾器能過濾不同大小的水果(過濾器表示一個單獨的功能或切入的程式碼),到這裡可能就與現實有些不同了,當有能穿過這個過濾器的水果出現時,穿過過濾器的是這個水果的一個分身,過濾器這邊會產生一個結果,而對主流水線不會產生影響(簡單的說就是這部分切入的程式碼不會影響原始碼也不用修改原始碼),而這個過濾器還能夠用於分揀其他相同或者不同的水果分揀線並統一管理。(以上就是個人對切面程式設計的理解,已經想不到更通俗的解釋了。其他參考:[
二、AOP基本用法
包結構:
匯入工具包:
下面是具體程式碼:
1.使用者實體類User.java
package cn.lsl.entity;
/**
* 使用者實體類
*
* @author LSL
*
*/
public class User{
private Integer id; // 使用者id
private String username; // 使用者名稱
private String password; // 使用者密碼
private String email; // 使用者郵箱
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this .username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
2.定義持久層介面UserDao.java
package cn.lsl.dao;
import cn.lsl.entity.User;
/**
* 增加dao介面,定義了所需的持久化方法
*
* @author LSL
*
*/
public interface UserDao {
public void save(User user);
}
3.實現持久層介面UserDaoImp.java
package cn.lsl.dao.impl;
import cn.lsl.dao.UserDao;
import cn.lsl.entity.User;
/**
* 使用者DAO,類,實現了IDAO介面,負責User類的持久化操作
*
* @author LSL
*
*/
public class UserDaoImpl implements UserDao {
public void save(User user) {
System.out.println("儲存使用者資訊到資料庫");
}
}
4.定義業務介面UserService.java
package cn.lsl.service;
import cn.lsl.entity.User;
/**
* 使用者業務介面,定義了所需的業務方法
*
* @author LSL
*
*/
public interface UserService {
public void addNewUser(User user);
}
5.實現業務介面UserServiceImp.java
package cn.lsl.service.impl;
import cn.lsl.dao.UserDao;
import cn.lsl.entity.User;
import cn.lsl.service.UserService;
/**
* 使用者業務類,實現了對User功能的業務管理
*
* @author LSL
*
*/
public class UserServiceImpl implements UserService {
/**
* 宣告介面型別的引用.和具體實現類解耦合
*/
private UserDao dao;
/**
* dao 屬性的setter訪問器,會被Spring呼叫,實現設值注入
*
* @param dao
*/
public void setDao(UserDao dao) {
this.dao = dao;
}
/**
* 呼叫使用者的dao方法儲存使用者資訊
*/
public void addNewUser(User user) {
dao.save(user);
}
}
6.定義切入方法UserServiceLogger.java
package cn.lsl.aop;
import java.util.Arrays;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
public class UserServiceLogger {
private static final Logger log = Logger.getLogger(UserServiceLogger.class);
/**
* 前置增強
* @param jp
*/
public void before(JoinPoint jp) { // JoinPoint 連線點物件
log.info("呼叫" + jp.getTarget() + " 的 " + jp.getSignature().getName()
+ " 方法,方法入參:" + Arrays.toString(jp.getArgs())); // jp.getArgs()連線點方法引數陣列
}
/**
* 後置增強
* @param jp
* @param result
*/
public void afterReturning(JoinPoint jp, Object result) {
// 連線點所在目標類
log.info("呼叫" + jp.getTarget() + " 的 " + jp.getSignature().getName() // 連線點方法資訊
+ " 方法,方法返回值: " + result);
}
}
7.配置Spring以及切入點
<?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-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<bean id="dao" class="cn.lsl.dao.impl.UserDaoImpl"/>
<bean id="service" class="cn.lsl.service.impl.UserServiceImpl">
<property name="dao" ref="dao"></property>
</bean>
<!-- 宣告增強方法所在的Bean -->
<bean id="theLogger" class="cn.lsl.aop.UserServiceLogger"></bean>
<!-- 切面配置 -->
<aop:config>
<!--
public * addNewUser(entity.User): “*”表示匹配所有型別的返回值。
public void *(entity.User): “*”表示匹配所有方法名。
public void addNewUser(..): “..”表示匹配所有引數個數和型別。
* com.service.*.*(..):匹配com.service包下所有類的所有方法。
* com.service..*.*(..):匹配com.service包及其子包下所有類的所有方法
-->
<!-- 定義切入點 -->
<aop:pointcut expression="execution(public void addNewUser(cn.lsl.entity.User))"
id="pointcut"/>
<!-- 引用包含增強方法的Bean -->
<aop:aspect ref="theLogger">
<!-- 將before()方法定義為前置增強,並引用pointcut切入點 -->
<aop:before method="before" pointcut-ref="pointcut"/>
<!-- 將afterReturning()方法定義為後置增強,並引用pointcut切入點 -->
<!-- 通過returning屬性定義名為result的引數注入返回值 -->
<aop:after-returning method="afterReturning"
pointcut-ref="pointcut" returning="result"/>
</aop:aspect>
</aop:config>
</beans>
8.編寫測試類(我用的是Junit 4測試,不一定要用相同的測試工具)
package cn.lsl.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.lsl.entity.User;
import cn.lsl.service.UserService;
public class AopTest {
@Test
public void aopTest() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService service = (UserService) context.getBean("service");
User user = new User();
user.setId(1);
user.setUsername("test2");
user.setPassword("test123");
user.setEmail("[email protected]");
service.addNewUser(user);
}
}
以上就是使用AOP列印log的完整程式碼。
執行結果:
結果可以看到,在列印“儲存使用者資訊到資料庫”先執行了切入程式碼before()的方法,在列印“儲存使用者資訊到資料庫”後又執行了切入程式碼after()方法,還獲取到了返回值。當然這裡方法沒有返回自然是null。而這切入方法執不執行,在哪切入就看你在不在配置檔案裡配置了。
@Author 瞌睡蟲
@mybatis-3.2.2
@Database: mysql 5.7.15
@Tool: MyEclipse