javascript
图文结合分析Spring的面向切面编程--AOP
Spring還可以這么學–AOP
上一篇文章Spring還可以這么學–IoC(控制反轉) / DI(依賴注入)理解
1. 什么是AOP?
AOP(Aspect Oriented Programming),即面向切面編程,可以說是OOP(Object Oriented Programming,面向對象編程)的補充和完善。
2. AOP的作用?
利用一種稱為"橫切"的技術,剖解開封裝的對象內部,并將那些影響了多個類的公共行為封裝到一個可重用模塊,并將其命名為"Aspect",即切面。所謂"切面",簡單說就是那些與業務無關,卻為業務模塊所共同調用的邏輯或責任封裝起來,便于減少系統的重復代碼,降低模塊之間的耦合度,并有利于未來的可操作性和可維護性。
首先我們來看沒有AOP時,如果我們要做日志處理,就得在每個方法中添加
但大多數日志處理代碼都是相同的,所以我們將日志處理抽離成一個新的方法,但是盡管這樣,我們還得手動插入這些方法。
但這樣代碼的耦合度很高,當我們要更改這個功能時,就得一個個更改
使用AOP后
為了在指定位置執行這些橫向的功能,需要知道指定的是什么地方
例如上圖,方法級別的aop實現,在一個程序執行鏈條中,把method2稱為切點,也就是說在method2執行時會執行橫切的功能,那么是在method2之前還是之后呢,又是執行什么呢?這些都由advice(通知)來指定。
Spring 方面可以使用下面提到的五種通知工作:
3. AOP的核心概念
- 橫切關注點:對哪些方法進行攔截,攔截后怎么處理,這些關注點稱之為橫切關注點
- 切面(aspect):類是對物體特征的抽象,切面就是對橫切關注點的抽象
- 連接點(joinpoint):被攔截到的點,因為Spring只支持方法類型的連接點,所以在Spring中連接點指的就是被攔截到的方法,實際上連接點還可以是字段或者構造器
- 切入點(pointcut):對連接點進行攔截的定義
- 通知(advice):所謂通知指的就是指攔截到連接點之后要執行的代碼,通知分為前置、后置、異常、最終、環繞通知五類
- 目標對象:代理的目標對象
- 織入(weave):將切面應用到目標對象并導致代理對象創建的過程
- 引入(introduction):在不修改代碼的前提下,引入可以在運行期為類動態地添加一些方法或字段
###4. 實現方式
####Spring AOP的XML實現方式
Employee.java文件
Logging.java文件
package com.wangc;public class Logging {//在一個方法執行之前,執行通知。public void beforeAdvice(){System.out.println("執行employee的方法之前執行.");}//在一個方法執行之后,不考慮其結果,執行通知。public void afterAdvice(){System.out.println("執行employee的方法之后執行.");}//在一個方法執行之后,只有在方法成功完成時,才能執行通知。public void afterReturningAdvice(Object retVal){System.out.println("返回:" + retVal.toString() );}//在一個方法執行之后,只有在方法退出拋出異常時,才能執行通知。public void AfterThrowingAdvice(IllegalArgumentException ex){System.out.println("拋出了一個異常: " + ex.toString()); } }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/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "><aop:config><!-- 聲明一個aspect,logging將被依賴注入 --><aop:aspect id="log" ref="logging"><!-- 聲明一個切入點 ,該切入點將與 com.wangc 包下的Logging類的方法相匹配,這里的“*”是通配符--><aop:pointcut id="all" expression="execution(* com.wangc.*.*(..))"/><!-- 定義一個前置通知 --><aop:before pointcut-ref="all" method="beforeAdvice"/><!-- 定義一個后置通知 --><aop:after pointcut-ref="all" method="afterAdvice"/><!-- 定義一個返回后通知 --><aop:after-returning pointcut-ref="all" returning="retVal" method="afterReturningAdvice"/><!-- 定義一個拋出異常后通知 --><aop:after-throwing pointcut-ref="all" throwing="ex" method="AfterThrowingAdvice"/></aop:aspect></aop:config><bean id="employee" class="com.wangc.Employee"><property name="name" value="zhangsan" /><property name="age" value="28" /> </bean><bean id="logging" class="com.wangc.Logging"/> </beans>MyApp.java文件
package com.wangc;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class MyApp {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");Employee employee = (Employee) context.getBean("employee");employee.getName();employee.getAge();employee.printThrowException();} }執行結果:
執行employee的方法之前執行. name = zhangsan 執行employee的方法之后執行. 返回:zhangsan 執行employee的方法之前執行. age = 28 執行employee的方法之后執行. 返回:28 執行employee的方法之前執行. 發生異常 執行employee的方法之后執行. 拋出了一個異常: java.lang.IllegalArgumentException Exception in thread "main" java.lang.IllegalArgumentException ......注意:上面的例子只有一個橫切關注點,如果有多個橫切關注點,可以使用aspect里的order屬性來控制橫切關注點的順序。
......<aop:config><aop:aspect id="log1" ref="logging1" order="1"><aop:pointcut id="addTime" expression="execution(* com.wangc.*.*(..))"/><aop:before pointcut-ref="addTime" method="beforeAdvice"/></aop:aspect><aop:aspect id="log2" ref="logging2" order="2"><aop:pointcut id="printLog" expression="execution(* com.wangc.*.*(..))"/><aop:before pointcut-ref="printLog" method="beforeAdvice"/></aop:aspect></aop:config>......Spring AOP 的 @AspectJ實現方式
這里只需要在上面的基礎上修改以下兩個文件就可實現,修改后的文件如下:
Beans.xml文件
Logging.java文件
package com.wangc;import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut;@Aspect public class Logging {@Pointcut("execution(* com.wangc.*.*(..))")private void all() {}//在一個方法執行之前,執行通知。@Before("all()")public void beforeAdvice(){System.out.println("執行employee的方法之前執行.");}//在一個方法執行之后,不考慮其結果,執行通知。@After("all()")public void afterAdvice(){System.out.println("執行employee的方法之后執行.");}//在一個方法執行之后,只有在方法成功完成時,才能執行通知。@AfterReturning(pointcut = "all()", returning="retVal")public void afterReturningAdvice(Object retVal){System.out.println("返回:" + retVal.toString() );}//在一個方法執行之后,只有在方法退出拋出異常時,才能執行通知。@AfterThrowing(pointcut = "all()", throwing="ex")public void AfterThrowingAdvice(IllegalArgumentException ex){System.out.println("拋出了一個異常: " + ex.toString()); } }這里做個簡單的說明: 用@Aspect的注解來標識切面,注意不要把它漏了,否則Spring創建代理的時候會找不到它,@Pointcut注解指定了切點,@Before、@After、@AfterReturning和@AfterThrowing指定了運行時的通知。
運行結果:
執行employee的方法之前執行. name = zhangsan 執行employee的方法之后執行. 返回:zhangsan 執行employee的方法之前執行. age = 28 執行employee的方法之后執行. 返回:28 執行employee的方法之前執行. 發生異常 執行employee的方法之后執行. 拋出了一個異常: java.lang.IllegalArgumentException Exception in thread "main" java.lang.IllegalArgumentException ......上一篇文章Spring還可以這么學–IoC(控制反轉) / DI(依賴注入)理解
總結
以上是生活随笔為你收集整理的图文结合分析Spring的面向切面编程--AOP的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java经典面试题总结(一)
- 下一篇: Java学习笔记——面向对象