一.AOP
AOP 和 Filter 能夠實現(xiàn)的 功能相似 。
AOP 和 Filter 的區(qū)別:
AOP攔截的是類中方法 (切點),只要方法能夠被Spring管理,那么這個方法就能夠被攔截。 Filter攔截的是請求 。
1.AOP:中文名稱面向切面編程
2.英文名稱:(Aspect Oriented Programming)
3.正常程序執(zhí)行流程都是縱向執(zhí)行流程 3.1 又叫面向切面編程,在原有縱向執(zhí)行流程中添加橫切面 3.2 不需要修改原有程序代碼 3.2.1 高擴展性 3.2.2 原有功能相當于釋放了部分邏輯.讓職責更加明確. 4.面向切面編程是什么? 4.1 在程序原有縱向執(zhí)行流程中,針對某一個或某一些方法添加通知,形成橫切面過程就叫做面向切面編程.
5.常用概念 5.1 原有功能: 切點, pointcut 5.2 前置通知: 在切點之前執(zhí)行的功能. before advice 5.3 后置通知: 在切點之后執(zhí)行的功能,after advice 5.4 如果切點執(zhí)行過程中出現(xiàn)異常,會觸發(fā)異常通知.throws advice 5.5 所有功能總稱叫做切面. 5.6 織入: 把切面嵌入到原有功能的過程叫做織入
6.spring 提供了2 種AOP 實現(xiàn)方式 6.1 Schema-based 6.1.1 每個通知都需要實現(xiàn)接口或類 6.1.2 配置spring 配置文件時在<aop:config>配置 6.2 AspectJ 6.2.1 每個通知不需要實現(xiàn)接口或類 6.2.2 配置spring 配置文件是在<aop:config>的子標簽<aop:aspect>中配置
二. Schema-based 實現(xiàn)步驟(需要在類中實現(xiàn)接口)
1. 導入jar 2. 新建通知類 2.1 新建前置通知類 2.1.1 arg0: 切點方法對象Method 對象 2.1.2 arg1: 切點方法參數(shù) 2.1.3 arg2:切點在哪個對象中
public class MyBeforeAdvice implements MethodBeforeAdvice { @Override public void before ( Method arg0
, Object
[ ] arg1
, Object arg2
) throws Throwable
{ System
. out
. println ( "執(zhí)行前置通知" ) ; }
}
2.2 新建后置通知類 2.2.1 arg0: 切點方法返回值 2.2.2 arg1:切點方法對象 2.2.3 arg2:切點方法參數(shù) 2.2.4 arg3:切點方法所在類的對象
public class MyAfterAdvice implements AfterReturningAdvice { @Override public void afterReturning ( Object arg0
, Method arg1
, Object
[ ] arg2
, Object arg3
) throws Throwable
{ System
. out
. println ( "執(zhí)行后置通知" ) ; }
}
3. 配置 spring 配置文件 3.1 引入 aop 命名空間 3.2 配置通知類的<bean> 3.3 配置切面 3.4 * 通配符,匹配任意方法名,任意類名,任意一級包名 (下面圖中第一個*表示返回值類型,也就是我們不關心方法返回值類型。圖上的解釋‘聲明通配符’是錯誤的解釋。) 3.5 如果希望匹配任意方法參數(shù)(..)
<?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.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd" > < bean id = " mybefore" class = " com.bjsxt.advice.MyBeforeAdvice" > </ bean> < bean id = " myafter" class = " com.bjsxt.advice.MyAfterAdvice" > </ bean> < aop: config> < aop: pointcut expression = " execution(*com.bjsxt.test.Demo.demo2())" id = " mypoint" /> < aop: advisor advice-ref = " mybefore" pointcut-ref = " mypoint" /> < aop: advisor advice-ref = " myafter" pointcut-ref = " mypoint" /> </ aop: config> < bean id = " demo" class = " com.bjsxt.test.Demo" > </ bean>
</ beans>
4. 編寫測試代碼
public class Test { public static void main ( String
[ ] args
) { ApplicationContext ac
= new ClassPathXmlApplicationContext ( "applicationContext.xml" ) ; Demo demo
= ac
. getBean ( "demo" , Demo
. class ) ; demo
. demo1 ( ) ; demo
. demo2 ( ) ; demo
. demo3 ( ) ; }
}
運行結果:
三. 配置異常通知的步驟(AspectJ 方式)
1. 只有當切點報異常, 才能觸發(fā)異常通知
2. 在spring 中有AspectJ 方式提供了異常通知的辦法. 2.1 如果希望通過schema-base 實現(xiàn)需要按照特定的要求自己編寫方法.
3. 實現(xiàn)步驟: 3.1 新建類,在類寫任意名稱的方法
public class MyThrowAdvice { public void myexception ( Exception e1
) { System
. out
. println ( "執(zhí)行異常通知" + e1
. getMessage ( ) ) ; }
}
3.2 在spring 配置文件中配置 3.2.1 <aop:aspect>的 ref 屬性表示:方法在哪個類中 . 3.2.2 <aop: xxxx/> 表示什么通知 3.2.3 method: 當觸發(fā)這個通知時,調(diào)用哪個方法 3.2.4 throwing: 異常對象名,必須和通知中方法參數(shù)名相同(可以不在通知中聲明異常對象)
< bean id = " mythrow" class = " com.bjsxt.advice.MyThrowAdvice" > </ bean> < aop: config> < aop: aspect ref = " mythrow" > < aop: pointcut expression = " execution(*com.bjsxt.test.Demo.demo1())" id = " mypoint" /> < aop: after-throwing method = " myexception" pointcut-ref = " mypoint" throwing = " e1" /> </ aop: aspect> </ aop: config> < bean id = " demo" class = " com.bjsxt.test.Demo" > </ bean>
四. 異常通知(Schema-based 方式)
1. 新建一個類實現(xiàn)throwsAdvice 接口 1.1 必須自己寫方法,且必須叫afterThrowing 1.2 有兩種參數(shù)方式 1.2.1 必須是 1個 或 4個 1.3 異常類型要與切點報的異常類型一致
public class MyThrow implements ThrowsAdvice {
public void afterThrowing ( Exception ex
) throws Throwable
{ System
. out
. println ( "執(zhí)行異常通過-schema-base 方式 " ) ; }
}
2. 在ApplicationContext.xml 配置
<bean id="mythrow"class="com.bjsxt.advice.MyThrow">
</ bean> < aop: config> < aop: pointcut expression = " execution(*com.bjsxt.test.Demo.demo1())" id = " mypoint" /> < aop: advisor advice-ref = " mythrow" pointcut-ref = " mypoint" /> </ aop: config> < bean id = " demo" class = " com.bjsxt.test.Demo" > </ bean>
五.環(huán)繞通知(Schema-based 方式)
1. 把前置通知和后置通知都寫到一個通知中,組成了環(huán)繞通知
2. 實現(xiàn)步驟 2.1 新建一個類實現(xiàn)MethodInterceptor
public class MyArround implements MethodInterceptor { @Override public Object
invoke ( MethodInvocation arg0
) throws Throwable
{ System
. out
. println ( "環(huán)繞-前置" ) ; Object result
= arg0
. proceed ( ) ; System
. out
. println ( "環(huán)繞-后置" ) ; return result
; }
}
2.2 配置 applicationContext.xml
< bean id = " myarround" class = " com.bjsxt.advice.MyArround" > </ bean> < aop: config> < aop: pointcut expression = " execution(* com.bjsxt.test.Demo.demo1())" id = " mypoint" /> < aop: advisor advice-ref = " myarround" pointcut-ref = " mypoint" /> </ aop: config> < bean id = " demo" class = " com.bjsxt.test.Demo" > </ bean>
六.使用AspectJ 方式實現(xiàn)
1. 新建類,不用實現(xiàn) 1.1 類中方法名任意
package com
. bjsxt
. advice
; import org
. aspectj
. lang
. ProceedingJoinPoint
; public class MyAdvice { public void aopBefFunc2arg ( String name
, int age
) { System
. out
. println ( "MyAdvice.aopBefFunc2arg()" ) ; System
. out
. println ( "前置" + name
) ; } public void aopBefFunc1arg ( String name
) { System
. out
. println ( "MyAdvice.aopBefFunc1arg()" ) ; System
. out
. println ( "前置:" + name
) ; } public void aopAfteringFunc0arg ( ) { System
. out
. println ( "MyAdvice.aopAfteringFunc0arg()" ) ; System
. out
. println ( "后置2" ) ; } public void aopAfterFunc0arg ( ) { System
. out
. println ( "MyAdvice.aopAfterFunc0arg()" ) ; System
. out
. println ( "后置1" ) ; } public void aopThrowFunc ( ) { System
. out
. println ( "MyAdvice.aopThrowFunc()" ) ; System
. out
. println ( "異常" ) ; } public Object
myarround ( ProceedingJoinPoint p
) throws Throwable
{ System
. out
. println ( "MyAdvice.myarround()" ) ; System
. out
. println ( "before Object result = p.proceed()" ) ; Object result
= p
. proceed ( ) ; System
. out
. println ( "after Object result = p.proceed()" ) ; return result
; }
}
1.2 配置 spring 配置文件 1.2.1 <aop:after/> 后置通知,是否出現(xiàn)異常都執(zhí)行 1.2.2 <aop:after-returing/> 后置通知,只有當切點正確執(zhí)行時執(zhí)行 1.2.3 <aop:after/> 和<aop:after-returing/> 和<aop:after-throwing/>執(zhí)行順序和配置順序有關 1.2.4 execution() 括號不能擴上args 1.2.5 中間使用 and 不能使用 && ,由 spring 把 and 解析成 && 1.2.6 args(名稱) 名稱自定義的.順序和demo1(參數(shù),參數(shù))對應 1.2.7 <aop:before/>, arg-names=” 名稱” 名稱來源于expression=”” 中args(),名稱必須一樣 1.2.7.1 args() 有幾個參數(shù),arg-names 里面必須有幾個參數(shù) 1.2.7.2 arg-names=”” 里面名稱必須和通知方法參數(shù)名對應
// 本示例非sxt原示例,稍微修改了下
<?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.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd" > < bean id = " demo" class = " com.bjsxt.test.Demo" > </ bean> < bean id = " myadvice" class = " com.bjsxt.advice.MyAdvice" > </ bean> < aop: config> < aop: aspect ref = " myadvice" > < aop: pointcutexpression = " execution(* com.bjsxt.test.Demo.demoMethod(String,int)) and args(name,age)" id = " pointcut_2_arg" /> < aop: pointcutexpression = " execution(* com.bjsxt.test.Demo.demoMethod(String)) and args(name)" id = " pointcut_1_arg" /> < aop: pointcutexpression = " execution(* com.bjsxt.test.Demo.demoMethod())" id = " pointcut_0_arg" /> < aop: pointcutexpression = " execution(* com.bjsxt.test.Demo.*(..))" id = " pointcut_all" /> < aop: before method = " aopBefFunc2arg" pointcut-ref = " pointcut_2_arg" arg-names = " name,age" /> < aop: before method = " aopBefFunc1arg" pointcut-ref = " pointcut_1_arg" arg-names = " name" /> < aop: after method = " aopAfterFunc0arg" pointcut-ref = " pointcut_0_arg" /> < aop: after method = " aopAfterFunc0arg" pointcut-ref = " pointcut_all" /> </ aop: aspect> </ aop: config>
</ beans>
七. 使用注解(基于Aspect)
1. spring 不會自動去尋找注解,必須告訴spring 哪些包下的類中可能有注解 1.1 引入xmlns:context
<context:component-scanbase-package="com.bjsxt.advice">
</ context: component-scan>
2. @Component 2.1 相當于<bean/> 2.2 如果沒有參數(shù),把類名首字母變小寫,相當于<bean id=””/> 2.3 @Component(“自定義名稱”)
2. 實現(xiàn)步驟: 3.1 在 spring 配置文件中設置注解在哪些包中
< context: component-scan base-package = " com.bjsxt.advice,com.bjsxt.test" > </ context: component-scan>
3.2 在 Demo 類中添加@Componet 3.2.1 在方法上添加@Pointcut(“”) 定義切點
@Component
public class Demo { @Pointcut ( "execution(* com.bjsxt.test.Demo.demo1())" ) public void demo1 ( ) throws Exception
{ System
. out
. println ( "demo1" ) ; }
}
3.3 在通知類中配置 3.3.1 @Component 類被spring 管理 3.3.2 @Aspect 相當于<aop:aspect/>表示通知方法在當前類中
@Component
@Aspect
public class MyAdvice { @Before ( "com.bjsxt.test.Demo.demo1()" ) public void mybefore ( ) { System
. out
. println ( "前置" ) ; } @After ( "com.bjsxt.test.Demo.demo1()" ) public void myafter ( ) { System
. out
. println ( "后置通知" ) ; } @AfterThrowing ( "com.bjsxt.test.Demo.demo1()" ) public void mythrow ( ) { System
. out
. println ( "異常通知" ) ; } @Around ( "com.bjsxt.test.Demo.demo1()" ) public Object
myarround ( ProceedingJoinPoint p
) throws Throwable
{ System
. out
. println ( "環(huán)繞-前置" ) ; Object result
= p
. proceed ( ) ; System
. out
. println ( "環(huán)繞-后置" ) ; return result
; }
}
八.代理設計模式
1. 設計模式:前人總結的一套解決特定問題的代碼.
2. 代理設計模式優(yōu)點: 2.1 保護真實對象 2.2 讓真實對象職責更明確. 2.3 擴展
3. 代理設計模式 3.1 真實對象.(老總) 3.2 代理對象(秘書) 3.3 抽象對象(抽象功能),談小目標
九. 靜態(tài)代理設計模式
1. 由代理對象代理所有真實對象的功能. 1.1 自己編寫代理類 1.2 每個代理的功能需要單獨編寫
2. 靜態(tài)代理設計模式的缺點: 2.1 當代理功能比較多時,代理類中方法需要寫很多.
十. 動態(tài)代理
1. 為了解決靜態(tài)代理頻繁編寫代理功能缺點.
2. 分類: 2.1 JDK 提供的 2.2 cglib 動態(tài)代理
十一. JDK 動態(tài)代理
1. 和cglib 動態(tài)代理對比 1.1 優(yōu)點:jdk 自帶,不需要額外導入jar 1.2 缺點: 1.2.1 真實對象必須實現(xiàn)接口 1.2.2 利用反射機制.效率不高.
2. 使用JDK 動態(tài)代理時可能出現(xiàn)下面異常 2.1 出現(xiàn)原因:希望把接口對象轉換為具體真實對象
十二: cglib 動態(tài)代理
1. cglib 優(yōu)點: 1.1 基于字節(jié)碼,生成真實對象的子類. 1.1.1 運行效率高于JDK 動態(tài)代理. 1.2 不需要實現(xiàn)接口
2. cglib 缺點: 2.1 非JDK 功能,需要額外導入jar
3. 使用 spring aop 時,只要出現(xiàn) Proxy 和真實對象轉換異常 3.1 設置為true 使用cglib 3.2 設置為false 使用jdk(默認值)
< aop: aspectj-autoproxy proxy-target-class = " true" > </ aop: aspectj-autoproxy>
總結
以上是生活随笔 為你收集整理的【Spring】Spring第二天 - AOP 详解、动态代理设计模式(JDK和cglib) 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。