AOP的理解以及实现
AOP
一、AOP概念
? AOP即面向切面編程。我們先來理解下為什么會需要AOP?
? 如果在編程時多個類中有重復出現的代碼,那么我們就應該考慮將這些重復代碼抽取出來定義成一個抽象類,這種情況我們稱為縱向抽取。但是如果這些重復的代碼是分散在各個業務邏輯中的,比如事務控制中有大量的try-catch-finally代碼,這些重復代碼嵌套在主要的業務邏輯代碼中,我們用上面的方法就抽取不了,這時我們就可以通過橫向切割的方式,把這些重復代碼抽取到一個獨立的模塊中,在以后調用對應的業務邏輯方法時,又將這些重復代碼橫向切入進去。從而達到讓業務邏輯類保持最初的單純。
? 我們用一個例子來說明。如下圖:是一個對數據庫進行操作的步驟:
? 1、連接數據庫
? 2、執行SQL語句
? 3、是否有異常,有就回滾事務,沒有就提交事務
? 4、關閉資源
? 我們可以看到每次對數據庫進行一次操作后,都會有如下的步驟,其中的1-3-4步驟都是重復的,而作為開發人員我們每次真正需要關心的只是步驟2的SQL語句執行(因為這在每個操作中是不一樣的),而對于其他的我們則可以交由AOP去實現這些步驟,我們只需通過注解或者XML的配置來告訴AOP我們需要在那些類下的哪些方法中切入這些重復的代碼,這樣在編寫代碼時我們就只需關注核心邏輯代碼,而在運行時AOP會對我們需要加入重復代碼的方法進行攔截,并將這些重復代碼切入進去。
? 值得一提的是AOP并不是Spring框架特有的,Spring只是支持AOP編程的框架之一,且SpringAOP是一種基于方法攔截的AOP,也就是說Spring只能支持方法攔截的AOP。
二、AOP術語
1、切面(Aspect):切面由切點和增加(需要切入的代碼、方法也叫通知)組成,它既包括了橫切邏輯的定義,也包括了連接點的定義,SpringAOP就是將切面所定義的橫切邏輯織入到切面所制定的連接點中。
2、增強、通知(Advice):是切面的方法,也就是一段需要切入到目標對象的代碼。根據他在代理對象真實方法調用前、后和邏輯分為以下幾種:
? 前置通知(before):在真實對象方法調用前執行
? 后置通知(after):在真實對象方法調用后執行
? 返回通知(afterReturning):在執行業務代碼后無異常執行
? 異常通知(afterThrowing):在執行業務代碼發送異常后執行
? 環繞通知(around):最強的通知,可以取代原對象方法。但使用也較復雜
3、切點(Pointcut):告訴SpringAOP在什么時候啟動攔截并織入對應的流程中。
4、連接點(join point):連接點對應的是一個具體的方法,比如通過切點的正則表達式去判斷那些方法是連接點。
5、織入(Weaving):織入就是將增強添加到目標具體連接點上的過程。
三、基于純注解的AOP實現:
主要步驟:
? 1、創建業務邏輯接口,實現接口
? 2、創建切面,切面中包含切點和需要切入的方法
? 3、創建AOP配置類,啟動Aspectj自動代理、掃描bean、生成切面類
? 4、測試AOP
1、創建一個接口 里面的方法就是我們的連接點,也就是我們需要攔截這個方法并將通知織入
package com.test.aop;public interface Student {void getName(); }2、創建這個接口的實現
package com.test.aop;import org.springframework.stereotype.Component;@Component public class StudentImpl implements Student {@Overridepublic void getName() {System.out.println("我叫唐鵬,我自豪");} }3、創建切面,并定義切點和邏輯方法
package com.test.aop;import org.aspectj.lang.annotation.*;@Aspect public class TestAspect {@Pointcut("execution(* com.test.aop.*.getName(..))")public void pointCut(){}@Before("pointCut()")public void before(){System.out.println("=====前置:小么小么小二郎喲,背著書包上學堂咯");}@After("pointCut()")public void after(){System.out.println("=====后置:終于放學了!");}@AfterReturning("pointCut()")public void afterReturning(){System.out.println("=====返回:今天真呀真高興");}@AfterThrowing("pointCut()")public void afterThrowing(){System.out.println("=====異常:oh 我考試考了0分,可不高興");} }4、創建AOP配置類
package com.test.aop;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.EnableAspectJAutoProxy;//啟用Aspectj自動代理 @EnableAspectJAutoProxy //配置掃描的包 這是掃描bean的配置 @ComponentScan("com.test") public class AopConfig {//生成切面類,自定義的類里面設置了切點@Beanpublic TestAspect getTestAspect(){return new TestAspect();} }5、測試AOP
package com.test.aop;import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class TestMain {public static void main(String[] args) {//因為是采用注解所以使用AnnotationConfigAopApplicationContext來實現ApplicationContext ac = new AnnotationConfigApplicationContext(AopConfig.class);Student tp = (Student) ac.getBean("studentImpl");tp.getName();} }6、結果打印
=====前置:小么小么小二郎喲,背著書包上學堂咯 我叫唐鵬,我自豪 =====后置:終于放學了! =====返回:今天真呀真高興四、基于純XML開發AOP的方式:
基本步驟:
? 1、同樣先創建接口和接口實現類
? 2、創建切面類和切入方法,因為是采用XML的方式,所以這里不需要指明他是個切面類,也不需要指定切入方法對應的切入點。,只需要生成對應的方法和方法代碼即可。
? 3、創建spirng配置文件
? 4、測試
1、接口和實現同上,這里就不在給出。(注意如果是在不同包下使用相同類名,注意包的引用)
2、編寫切面類
package com.test.aopXml;public class TestAspect {public void before(){System.out.println("=====XML前置:小么小么小二郎喲,背著書包上學堂咯");}public void after(){System.out.println("=====XML后置:終于放學了!");}public void afterReturning(){System.out.println("=====XML返回:今天真呀真高興");}public void afterThrowing(){System.out.println("=====XML異常:oh 我考試考了0分,可不高興");}}3、spring的配置文件applicationContext.xml 注意放在resources源碼文件下面
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><bean id ="student" class="com.test.aopXml.StudentImpl"/><bean id ="testAspect" class="com.test.aopXml.TestAspect"/><!--aop配置--><aop:config ><!--定義切面,和切點配置--><aop:aspect ref="testAspect"><!--定義需要重復使用的切點--><aop:pointcut id="pointCut" expression="execution(* com.test.aopXml.StudentImpl.*(..))"/><!--定義切點,method是指切面類中對應的方法名--><aop:before method="before" pointcut-ref="pointCut"/><aop:after method="after" pointcut-ref="pointCut"/><aop:after-returning method="afterReturning" pointcut-ref="pointCut"/><aop:after-throwing method="afterThrowing" pointcut-ref="pointCut"/></aop:aspect></aop:config></beans>4、測試
package com.test.aopXml;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestMain {public static void main(String[] args) {ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");Student student = (Student) ac.getBean("student");student.getName();} }5、測試結果
=====XML前置:小么小么小二郎喲,背著書包上學堂咯 我叫唐鵬,我自豪 =====XML后置:終于放學了! =====XML返回:今天真呀真高興五、注解和XML混合開發的方式
注解和XML混合使用:切點信息定義在切面類,xml中只需要開啟對aspectj自動代理和配置掃描就好
步驟如下:
? 1、同樣給出接口和實現類
? 2、編寫切面類,切面類需要加入容器,讓ioc管理
? 3、配置applicationContext1.xml文件
? 4、測試
1、接口和實現同上
2、編寫切面類,這里切面類加上了@Component注解 而在使用純注解時是沒有加上的
package com.test.aop;import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component;@Component @Aspect public class TestAspect {@Pointcut("execution(* com.test.aop.*.getName(..))")public void pointCut(){}@Before("pointCut()")public void before(){System.out.println("=====混合前置:小么小么小二郎喲,背著書包上學堂咯");}@After("pointCut()")public void after(){System.out.println("=====混合后置:終于放學了!");}@AfterReturning("pointCut()")public void afterReturning(){System.out.println("=====混合返回:今天真呀真高興");}@AfterThrowing("pointCut()")public void afterThrowing(){System.out.println("=====混合異常:oh 我考試考了0分,可不高興");} }3、applicationContext1.xml文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!--此配置是為了讓spring知道我們配置了切面,讓他掃描bean的時候注意到切面類--><aop:aspectj-autoproxy/><!--掃描bean--><context:component-scan base-package="com.test.aop"/></beans>4、測試
package com.test.aop;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestMain {public static void main(String[] args) {ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext1.xml");Student student = (Student) ac.getBean("studentImpl");student.getName();} }5、測試結果
=====混合前置:小么小么小二郎喲,背著書包上學堂咯 我叫唐鵬,我自豪 =====混合后置:終于放學了! =====混合返回:今天真呀真高興總結
以上是生活随笔為你收集整理的AOP的理解以及实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 读书笔记软件调试之道 :问题的核心-如何
- 下一篇: SQL_Injection_Base_b