Spring --12.Spring中AOP程式設計(XML方式)
1、AOP入門案例
1.1、建立工程並引入依賴
工程為com.day03
依賴如下:
<!--依賴--> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> </dependency> <!--log4j--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> </dependency> </dependencies>
1.2、引入applicationContext.xml和log4j.properties
applicationContext.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"> <!--配置相關類到applicationContext.xml--> <bean id="customerDao" class="com.day03.dao.Impl.CustomerDaoImpl"></bean> <!--配置切面類到applicationContext.xml--> <bean id="aspectXml" class="com.day03.aspect.AspectXml"></bean> <!--AOP配置--> <aop:config> <!--配置切入點--> <aop:pointcut id="pointCut1" expression="execution(* com.day03.dao.Impl.CustomerDaoImpl.save(..))" /> <!--配置切面 告訴spring框架呼叫切面類中哪個方法來增強--> <aop:aspect ref="aspectXml"> <aop:before method="writeLog" pointcut-ref="pointCut1" /> </aop:aspect> </aop:config> </beans>
log4j.properties
### direct log messages to stdout ### log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n ### direct messages to file mylog.log ### log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file.File=D:/mylog.log log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n ### set log levels - for more verbose logging change 'info' to 'debug' ### log4j.rootLogger=debug, stdout, file
1.3、編寫CustomerDao.java介面和CustomerDaoImpl.java實現類
CustomerDao.java介面
package com.day03.dao;
public interface CustomerDao {
public abstract void save();
public abstract void delete();
public abstract void update();
public abstract void select();
}
CustomerDaoImpl.java
package com.day03.dao.Impl;
import com.day03.dao.CustomerDao;
public class CustomerDaoImpl implements CustomerDao {
@Override
public void save() {
System.out.println("持久層:客戶儲存。。。。。。。");
}
@Override
public void delete() {
System.out.println("持久層、刪除使用者。。。。。");
}
@Override
public void update() {
System.out.println("持久層、更新使用者。。。。。。。。。");
}
@Override
public void select() {
System.out.println("持久層、查詢使用者..................");
}
}
1.4、配置相關類到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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置相關類到applicationContext.xml-->
<bean id="customerDao" class="com.day03.dao.Impl.CustomerDaoImpl"></bean>
</beans>
1.5、編寫切面類AsptectXml.java並配置切面類到Spring中
AsptectXml.java切面類
package com.day03.aspect;
import org.aspectj.lang.JoinPoint;
/**
* @ Author :ShaoWei Sun.
* @ Date :Created in 20:26 2018/11/12
*/
public class AspectXml {
public void writeLog() {
System.out.println("記錄日誌。。。。。。");
}
}
applicationContext.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">
<!--配置相關類到applicationContext.xml-->
<bean id="customerDao" class="com.day03.dao.Impl.CustomerDaoImpl"></bean>
<!--配置切面類到applicationContext.xml-->
<bean id="aspectXml" class="com.day03.aspect.AspectXml"></bean>
</beans>
1.6、配置AOP
applicationContext.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">
<!--配置相關類到applicationContext.xml-->
<bean id="customerDao" class="com.day03.dao.Impl.CustomerDaoImpl"></bean>
<!--配置切面類到applicationContext.xml-->
<bean id="aspectXml" class="com.day03.aspect.AspectXml"></bean>
<!--AOP配置-->
<aop:config>
<!--配置切入點-->
<aop:pointcut id="pointCut1" expression="execution(* com.day03.dao.Impl.CustomerDaoImpl.save(..))" />
<!--配置切面 告訴spring框架呼叫切面類中哪個方法來增強-->
<aop:aspect ref="aspectXml">
<aop:before method="writeLog" pointcut-ref="pointCut1" />
</aop:aspect>
</aop:config>
</beans>
1.7、測試類
TestAOP.java
package com.day03.test;
import com.day03.dao.CustomerDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @ Author :ShaoWei Sun.
* @ Date :Created in 20:54 2018/11/12
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestAOP {
@Autowired
private CustomerDao customerDao;
@Test
public void test1(){
customerDao.save();
}
}
2、Spring中AOP通知型別
前置通知、後置通知、環繞通知、異常通知、最終通知
2.1、前置通知
應用: 許可權控制 (許可權不足,丟擲異常)、 記錄方法呼叫資訊日誌
2.2、後置通知
特點:在目標方法執行後,返回值後執行增強程式碼邏輯。
應用場景:與業務相關的,如ATM取款機取款後,自動下發簡訊。
2.3、環繞通知
特點:目標執行前後,都進行增強(控制目標方法執行)
應用場景:日誌、快取、許可權、效能監控、事務管理
增強程式碼的方法要求:
接受的引數:ProceedingJoinPoint(可執行的連線點)
返回值:Object返回值
丟擲Throwable異常。
說明:
ProceedingJoinPoint:表示正在執行的連線點,也就是目標方法
joinpoint.proceed表示呼叫目標方法
2.4、異常通知
作用:目的碼出現異常,通知執行。記錄異常日誌、通知管理員(簡訊、郵件)
應用場景:處理異常(一般不可預知),記錄日誌
2.5、最終通知
作用:不管目標方法是否發生異常,最終通知都會執行(類似於finally程式碼功能)
應用場景:釋放資源 (關閉檔案、 關閉資料庫連線、 網路連線、 釋放記憶體物件 )
案例:
CustomerDao.java介面
package com.day03.dao;
public interface CustomerDao {
public abstract void save();
public abstract Integer delete();
public abstract Integer update(int a , int b);
public abstract void list();
public abstract void select();
}
CustomerDaoImpl.java實現類
package com.day03.dao.Impl;
import com.day03.dao.CustomerDao;
public class CustomerDaoImpl implements CustomerDao {
@Override
public void save() {
System.out.println("持久層:客戶儲存。。。。。。。");
}
@Override
public Integer delete() {
System.out.println("持久層、刪除使用者。。。。。");
return 100;
}
@Override
public Integer update(int a, int b) {
System.out.println("持久層、更新使用者。。。。。。。。。");
Integer c = a + b;
return c;
}
@Override
public void list() {
System.out.println("這是一個異常。。。。。");
//int i = 10/0;
}
@Override
public void select() {
int i =10/0;
System.out.println("持久層、查詢使用者..................");
}
}
切面類:AspectXml.java
package com.day03.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* @ Author :ShaoWei Sun.
* @ Date :Created in 20:26 2018/11/12
*/
public class AspectXml {
//入門案例
public void writeLog() {
System.out.println("記錄日誌。。。。。。");
}
//前置通知 許可權控制 、許可權不足、丟擲異常、
public void before(JoinPoint jp) {
String username = "rose";
if (!"admin".equals(username)) {
throw new RuntimeException("你沒有對"+jp.getTarget().getClass().getName()+"類中的"+jp.getSignature().getName()+"沒有訪問許可權");
}
}
//後置通知方法 應用:ATM取款取款後、自動下發簡訊、引數result:被增強那個方法返回值
public void afterReturning(JoinPoint jp, Object result){
System.out.println("你取款"+result+"元");
}
//環繞通知方法 、應用、事務處理 proceedingJoinPoint 正在執行的連線點
//joinPonint表示呼叫目標方法
public Object around(ProceedingJoinPoint pjp){
Object proceed = null;
System.out.println("開啟事務");
//獲取目標方法的引數
Object[] args = pjp.getArgs();
try {
proceed = pjp.proceed(args);
System.out.println("事務提交");
// 列印目標方法裡引數的結果值
System.out.println(proceed);
} catch (Throwable throwable) {
System.out.println("事務回滾");
}
return proceed;
}
//異常丟擲通知
//作用:目的碼出現異常、通知執行、記錄日誌、通知管理員
public void afterThrowing(JoinPoint jp,Throwable ex){
System.out.println("注意、在"+jp.getTarget().getClass().getName()+"類中"+jp.getSignature().getName()+"方法中發生異常"+ex.getMessage());
}
//最終通知:不管目標方法是否發生異常、最終通知都會執行、類似於finally程式碼功能、
//應用:釋放資源、關閉檔案、關閉資料庫連線、網路連線、釋放記憶體物件
public void after(JoinPoint jp){
System.out.println("開始釋放資源、連線類方法為:"+jp.getTarget().getClass().getName()+"方法:"+jp.getSignature().getName() );
}
}
applicationContext.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">
<!--配置相關類到applicationContext.xml-->
<bean id="customerDao" class="com.day03.dao.Impl.CustomerDaoImpl"></bean>
<!--配置切面類到applicationContext.xml-->
<bean id="aspectXml" class="com.day03.aspect.AspectXml"></bean>
<!--AOP配置-->
<aop:config>
<!--配置切入點-->
<aop:pointcut id="pointCut1" expression="execution(* com.day03.dao.Impl.CustomerDaoImpl.save(..))" />
<aop:pointcut id="pointCut2" expression="execution(* com.day03.dao.Impl.CustomerDaoImpl.delete(..))"/>
<aop:pointcut id="pointCut3" expression="execution(* com.day03.dao.Impl.CustomerDaoImpl.update(..))"/>
<aop:pointcut id="pointCut4" expression="execution(* com.day03.dao.Impl.CustomerDaoImpl.list(..))"/>
<aop:pointcut id="pointCut5" expression="execution(* com.day03.dao.Impl.CustomerDaoImpl.select(..))"/>
<!--配置切面 告訴spring框架呼叫切面類中哪個方法來增強-->
<aop:aspect ref="aspectXml">
<aop:before method="before" pointcut-ref="pointCut1" />
<aop:after-returning method="afterReturning" pointcut-ref="pointCut2" returning="result" />
<aop:around method="around" pointcut-ref="pointCut3"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="pointCut4" throwing="ex"/>
<aop:after method="after" pointcut-ref="pointCut5"/>
</aop:aspect>
</aop:config>
</beans>
TestAOP.java測試類
package com.day03.test;
import com.day03.dao.CustomerDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @ Author :ShaoWei Sun.
* @ Date :Created in 20:54 2018/11/12
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestAOP {
@Autowired
private CustomerDao customerDao;
//前置
@Test
public void test1(){
customerDao.save();
}
//後置
@Test
public void test2(){
customerDao.delete();
}
//環繞
@Test
public void test3(){
customerDao.update(5,8);
}
//異常
@Test
public void test4(){
customerDao.list();
}
//最終、不管目標方法是否發生異常、最終通知都執行
@Test
public void test5(){
customerDao.select();
}
}