Spring三大核心思想之AOP(面向切面編程)
學習Spring三大核心思想之AOP之前建議先學習:
🔴1、Srping之IOC思想及使用
🔴2、Spring核心思想AOP的底層設計模式之代理模式
🍅 程式員小王的博客:程式員小王的博客
🍅 歡迎點贊 👍 收藏 ?留言 📝
🍅 如有編輯錯誤聯系作者,如果有比較好的文章歡迎分享給我,我會取其精華去其糟粕
🍅java自學的學習路線:java自學的學習路線
一、什么是AOP(面向切面編程)?
AOP 為 Aspect Oriented Programming 的縮寫,意思為面向切面編程,是通過預編譯方式 和運行期 動態代理 實作程式功能的統一維護的一種技術,
AOP (面向切面編程)是 OOP(面向物件) 的延續,是軟體開發中的一個熱點,也是Spring框架中的一個重要內容,是函式式編程 的一種衍生范型,利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率,
二、AOP 的作用及其優勢
作用:在程式運行期間,在不修改原始碼的情況下對方法進行功能增強
優勢:減少重復代碼,提高開發效率,并且便于維護
三、AOP 的底層實作
實際上,AOP 的底層是通過 Spring 提供的的動態代理技術實作 的,在運行期間,Spring通過動態代理技術動態的生成代理物件,代理物件方法執行時進行增強功能的介入,在去呼叫目標物件的方法,從而完成功能的增強,
- 動態代理的作用:
????1)在目標類源代碼不改變的情況下,增加功能,
????2)減少代碼的重復
????3)專注業務邏輯代碼
????4)解耦合,讓你的業務功能和日志,事務非業務功能分離,
代理設計模式詳細筆記 :代理模式詳細筆記,想學好Spring的AOP思想先理解代理模式
java設計模式之代理設計模式筆記詳細內容:
-
代理模式是結構型模式其中的一種
-
現在開發中存在的問題
-
什么是代理模式,為什么需要使用代理模式
-
靜態代理及實作
-
什么是動態代理
-
JDK 動態代理和cglib動態代理的使用及區別
-
三種動態代理的對比及優缺點
-
代理模式的使用場景
四、AOP 相關概念
Spring 的 AOP 實作底層就是對動態代理的代碼進行了封裝 ,封裝后我們只需要對需要關注的部分進行代碼撰寫,并通過配置的方式完成指定目標的方法增強,
在正式講解 AOP 的操作之前,我們必須理解 AOP 的相關術語,常用的術語如下:
1、切面(Aspect)
一個切面就是一個代理物件= 要為那些類生成代理+要添加的額外功能是那些

2、切入點(pointcut):將來要為那些類生成代理物件
3、通知/ 增強(advice):就是要添加的額外功能
- 生活案例:給面包之間涂果醬

注意:切面(Aspect)=切入點(pointcut)+通知點(advice,額外功能)

4、AOP中的(面向切面編程)通知
前置通知:目標方法之前的額外功能 MethodBeforeAdvice
環繞通知:它是spring框架為我們提供的一種可以在代碼中手動控制增強方法何時執行的方式 MethodInterceptor(Interceptor [?nt??s?pt?]攔截器)
后置通知:目標方法之后的額外功能 AfterReturningAdvice(returning[r??t??rn??])
例外通知:執行例外的額外功能 ThrowsAdvice
最終通知:一定執行的額外功能

5、Target(目標物件):代理的目標物件
6、代理(Proxy[?prɑ?ksi]):一個類被AOP注入增強后,就產生一個結果代理類
7、連接點(joinPoint):所謂連接點是指那些被攔截到的點,在spring中,這些點指的是方法(額外功能),因為spring只支持方法型別的連接點
五、切面編程步驟
1、五種通知類
AOP 切面=切入點+通知
-
前置通知:MethodBeforeAdvice
-
后置通知:AfterReturnAdvice
-
環繞通知:MethodInterceptor
-
例外通知:ThrowsAdvice(throw [θro?z])
-
最終通知
- 通知的配置語法:
<aop : 通知型別 method=“切面類中方法名” pointcut=“切點運算式"> </aop:通知型別>
- 切點運算式的抽取
當多個增強的切點運算式相同時,可以將切點運算式進行抽取,在增強中使用 pointcut-ref 屬性代替 pointcut 屬性來參考抽取后的切點運算式,
<aop:config>
<!--參考myAspect的Bean為切面物件-->
<aop:aspect ref="myAspect">
<aop:pointcut id="myPointcut" expression="execution(* com.tjcu.aop.*.*(..))"/>
<aop:before method="before" pointcut-ref="myPointcut"></aop:before>
</aop:aspect>
</aop:config>
- aop織入的配置
<aop:config>
<aop:aspect ref=“切面類”>
<aop:before method=“通知方法名稱” pointcut=“切點運算式"></aop:before>
</aop:aspect>
</aop:config>
- 切點運算式的寫法:
execution([修飾符] 回傳值型別 包名.類名.方法名(引數))
2、AOP的開發步驟
1、開發目標類
2、開發通知類,確定額外功能
3、管理通知類
4、配置切入點 確定要為那些類添加額外功能
5、將目標類和切面類的物件創建權交給 spring
6、組裝切面 切入點+通知(額外功能)
3、AOP編程所需要的依賴
引入依賴
spring-aop
spring-expression
spring-aspects
六、AOP實作前置通知案例
1、目標介面類
public interface CityService {
public void login();
public void add(String name);
}
2、目標實作類(核心功能)
/**
* @author 王恒杰
* @Description:目標物件
*/
public class CityServiceImpl implements CityService{
@Override
public void login() {
//前置通知:System.out.println("嘻嘻哈哈");
//執行核心的業務邏輯 呼叫Dao
System.out.println("登錄呼叫Dao");
}
@Override
public void add(String name) {
//前置通知:System.out.println("嘻嘻哈哈");
//執行核心的業務邏輯 呼叫Dao
System.out.println("添加呼叫Dao");
}
}
3、前置通知(額外功能)動態代理代碼
/**
* @author 王恒杰
* @Description: 通知類,額外功能
*/
public class MyBeforeAdvice implements MethodBeforeAdvice {
/**
* 額外功能書寫的方法
* 引數1:代理物件當前呼叫的方法
* 引數2:當前代理物件呼叫的方法的引數
* 引數3:目標物件(被代理的物件)
* @param method
* @param objects
* @param o
* @throws Throwable
*/
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("嘻嘻哈哈");
}
}
4、將目標類和切面類的物件創建權交給 spring
<!--管理目標物件-->
<bean class="before.CityServiceImpl" id="cityService"></bean>
<!--管理通知類 動態代理實作AOP-->
<bean id="myBeforeAdvice" class="before.MyBeforeAdvice"></bean>
5、在 spring.xml 中配置織入關系(前置功能)
<!--組裝切面-->
<aop:config>
<!--配置切入點
id:切入點的唯一標識
expression:切入點運算式,為那些類添加額外功能
execution() 切入點運算式的一種 精確到要添加到額外功能的方法
*:通配
空格:
before.CityServiceImpl.*:所有方法
(..):所有引數
-->
<aop:pointcut id="pc1" expression="execution(* before.CityServiceImpl.*(..))"/>
<!--組裝切面=切入點+通知
advice-ref:通知的id
pointcut-ref:切入點的id
-->
<aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="pc1"></aop:advisor>
</aop:config>
6、測驗代碼
@Test
public void testMethodBeforeAdvice() {
//啟動工廠
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("before/spring.xml");
//獲取組件 目標物件就是代理物件
CityService cityService = (CityService) ctx.getBean("cityService");
//目標物件就是代理物件 class com.sun.proxy.$Proxy4
System.out.println(cityService.getClass());
//呼叫方法,通過代理類呼叫目標類
cityService.add("123");
}
注意: 獲取組件時,目標物件就是代理物件
七、Spring中的環繞通知案例
1、dao層介面
public interface StudentDao {
/**
* 登錄
* @param name
*/
public void login(String name);
/**
* 分頁
* @param name
* @return
*/
public String pageShow(String name);
}
2、dao層實作類
public class StudentDaoImpl implements StudentDao{
@Override
public void login(String name) {
//回圈10000次
for (int i = 0; i < 10000; i++) {
}
System.out.println("資料庫實作登錄");
}
@Override
public String pageShow(String name) {
//回圈10000次
for (int i = 0; i < 10000; i++) {
}
System.out.println("資料庫實作分頁");
return name;
}
}
3、目標介面類
public interface StudentService {
/**
* 登錄
* @param name
*/
public void login(String name);
/**
* 分頁
* @param name
* @return
*/
public String pageShow(String name);
}
4、目標實作類
public class StudentServiceImpl implements StudentService{
private StudentDao studentDao;
public void setStudentDao(StudentDao studentDao) {
this.studentDao = studentDao;
}
@Override
public void login(String name) {
System.out.println("登錄日志");
studentDao.login(name);
}
@Override
public String pageShow(String name) {
System.out.println("分頁日志");
String s = studentDao.pageShow(name);
return s;
}
}
5、環繞通知
- 核心方法: Object proceed = methodInvocation.proceed(); 放行
public class StudentAroundAdvice implements MethodInterceptor {
/**
* 引數 內部封裝者當前的代理物件 方法的引數,執行方法等
*
* @param methodInvocation
* @return
* @throws Throwable
*/
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
//1.控制事務
System.out.println("控制事務");
//method Invocation 方法呼叫
System.out.println("當前呼叫方法的名字" + methodInvocation.getMethod().getName());
//arguments引數 methodInvocation:方法呼叫
System.out.println("當前的引數為:" + methodInvocation.getArguments()[0]);
System.out.println("--------------");
//記錄當前的時間 單位毫秒
long begin = System.currentTimeMillis();
System.out.println("呼叫查詢的資料庫");
//放行,執行目標方法 proceed:繼續做proceed
Object proceed = methodInvocation.proceed();
//記錄結束的時間 單位毫秒
long end = System.currentTimeMillis();
System.out.println("dao執行所用時間" + (end - begin));
return proceed;
}
}
6、將目標類和切面類的物件創建權交給 spring
<!--管理dao組件-->
<bean id="studentDao" class="com.tjcu.dao.StudentDaoImpl"></bean>
<!--管理Service組件/目標物件-->
<bean id="studentService" class="com.tjcu.service.StudentServiceImpl">
<!--注入值-->
<property name="studentDao" ref="studentDao"></property>
</bean>
<!--管理通知組件-->
<bean id="studentAroundAdvice" class="com.tjcu.advice.StudentAroundAdvice"></bean>
7、在 applicationContext.xml 中配置織入關系,aop相關配置
<!--aop相關配置 切面=切點+環繞通知-->
<aop:config>
<!--切入點 execution:[eks??kju??n]執行-->
<aop:pointcut id="pointcut" expression="execution(* com.tjcu.service.StudentServiceImpl.*(..))"/>
<!--組裝切面 advisor[ [?d?va?z?r]]:顧問 advice-ref:通知 pointcut-ref:切入點-->
<aop:advisor advice-ref="studentAroundAdvice" pointcut-ref="pointcut"></aop:advisor>
</aop:config>
8、測驗代碼
@Test
public void AroundAdviceTest() {
//啟動工廠
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("com/tjcu/Spring/ApplicationContext.xml");
//獲取組件 目標物件就是代理物件
StudentService studentService = (StudentService) context.getBean("studentService");
//呼叫方法,通過代理類呼叫目標類
studentService.pageShow("通過代理類呼叫呼叫目標類");
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/356796.html
標籤:java
上一篇:【榜單公布】1024征文結果出爐,快來看看你上榜了沒?
下一篇:普通大一學生的自我反思
