『壹』 如何理解spring中的切面和過濾
1, 什麼是AOP ?
面向方面/切面的編程:將程序中的交叉業務邏輯(公用代碼)提取出來,稱為切面,
將這些切面動態的織入到目標對胡搏象,生成一個新的代理對象的過程;
把程序劃分為兩部分:
1) 通用的交叉業務,公用的代碼(日誌,事務,安全);
2) 具體的業務邏輯處理代碼;
將切面動態的織入到業務代碼中;
面向方面/切面編程:將業務分解成切面與具體的業務邏輯模塊,將切面透明的接入到業務邏輯模塊中,形成一個完整的程序。比如:字元編碼;日誌;事務等等
2, AOP中的基本概念:
1)切面(Aspect): 指交叉業務邏輯的統稱, 比如日誌,事務,安全;
2)通知(Advice): 指切面的具體實現;
3)連接點(Joinpoint):指切面可以薯汪織入到(應用到)目標對象的位置(級別), 兩個: 方法/屬性
代理模式, 調用的是代理對象, 代理維護一個目標對象的屬性;
調用方法之前, 先寫日誌; 再調用具體的實現方法;
調用屬性之前, 攔截一下做處理,很少用;Spring目前不支持這個;
4)切入點(Pointcut):指通知(切面的具體實現)應用到哪些目標對象的哪些方法或者哪些屬性上;
org.springframework.aop.Pointcut
Spring根據類名稱及方法名稱定義Pointcut,表示Advice織入至應用程序的時機;
5)引入(introction):指動態的給一個對象增加方法或者屬性的過程;是一種特殊的通知;
6)織入(weaving):將切面(通知)應用到目標對象生成代理的過程;
7)代理對象(Proxy): 目標對象應用切面以後生成的代理(切面織入之後生成的新的代理對象);
8)目標對象(Target): 具體業務邏輯的實現(需要織入切面的對象);
3, Spring的AOP, 使用的是動態代理;
1) 代理的褲手祥兩種方式:
靜態代理:
針對每個具體類分別編寫代理類;
針對一個介面編寫一個代理類;
IRegister
RegisterService <--- RegisterProxy
目標對象 代理對象
IRegister ir; 調用代理的方法, 代理再去調用目標對象的方法;
IReport
ReportService <--- ReportProxy
目標對象 代理對象
每一個代理對象只為一個目標對象服務;
動態代理:
針對一個方面編寫一個InvocationHandler,
然後借用JDK反射包中的Proxy類為各種介面動態生成相應的代理類
告訴一個類,我的介面是什麼, 目標類是什麼, 自動生成代理;
2) 動態代理例子:
public class MyProxyCreater implements java.lang.reflect.InvocationHandler {
private Object target;
public MyProxyCreater(Object target) {
super();
this.target = target;
}
public static Object createProxy(Object o){
//類載入器,實現的介面,代理生成的類
//根據三個參數創建一個代理對象;
//通過類載入器,借口,和實現類得到一個代理對象
//目標對象最少要實現一個介面
return
Proxy.newProxyInstance(o.getClass().getClassLoader(),
o.getClass().getInterfaces(),new MyProxyCreater(o));
}
//代理對象,目標方法,目標對象的參數
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object rst=null;
//加切面
System.out.println("loging...");
rst=method.invoke(target, args);
return rst;
}
}
spring思想:
1,將切面使用動態代理的方式動態地織入到目標對象(被代理對象)生成新的代理對象;
2,目標對象如果沒有實現代理介面,spring採用CGLIB來生成代理對象,
該代理對象是目標對象的子類;
3,目標對象如果是final類,並且沒有實現代理介面,就不能運用AOP了;
目標對象如果沒有實現介面, spring採用CGLIB庫來動態生成一個代理,
代理是目標對象的子類; 目標對象不能是final的;
Spring採用動態代理來實現AOP, 在運行時,spring將切面應用到目標對象生成動態代理,
客戶端使用動態代理來調用;
AspectJ: 需要學習一些別的語言,
支持屬性連接點; 可以在編譯期生成代理; 需要把編譯器重新寫一遍;
難度比較大;
3) Advice :
切面的實現:
類型:
(1)org.springframework.aop.MethodBeforeAdvice
在方法調用之前,做處理。
不能夠改變返回值
不能夠改變目標方法的流程,也不能中斷流程的處理過程(除非拋出異常)
before(目標方法,目標方法的參數,目標對象);
public void before(Method method, Object[] objectArray, Object object) throws Throwable
(2)org.springframework.aop.AfterReturningAdvice
在方法調用之後,做處理。
不能夠改變返回值
不能夠改變目標方法的流程,也不能中斷流程的處理過程(除非拋出異常)
void afterReturning(Object returnValue, Method method, Object[] args, Object target)
(3)org.aopalliance.intercept.MethodInterceptor
aop聯盟框架; 保證代碼兼容別的aop框架;
攔截器, 通知,跟filter差不多;
在方法調用之前以及之後,做處理。
可以改變返回值,也可以改變流程。
public Object invoke(MethodInvocation methodInvocation) throws Throwable
(4)org.springframework.aop.ThrowsAdvice
在目標方法拋出異常後,會根據異常類型選擇的做處理。
當該通知處理完異常後,會簡單地將異常再次拋出給客戶端調用。
public void afterThrowing(IllNameException e);
public void afterThrowing(IllAgeException e);
內置的創建代理類:
org.springframework.aop.framework.ProxyFactoryBean
proxyInterfaces,interceptorNames,target
作用:依照配置信息,將切面應用到目標對象,生成動態代理對象;
配置過程:
(1)配置目標對象,
(2)注入切面: 通知, Advisor, 攔截器
(3)利用ProxyFactoryBean將切面織入到目標對象,生成動態代理對象;
客戶端調用的是代理的對象;
如果目標對象沒有實現指定介面,不用配置ProxyInterfaces, (cglib會生成一個);
實現了介面,也可以不寫的;
(4)客戶端使用動態代理來訪問目標對象的方法。
注: 在默認情況下,通知會應用到目標對象的所有方法之上。
編碼過程: 目標對象--通知--代理--客戶端調用;
例子: (aop3)四種通知 ;
<bean id="registerServiceTarget" class="aop3.RegisterServiceImpl"/>
<bean id="logingAdvice" class="aop3.LogingAdvice"/>
<bean id="welcomeAdvice" class="aop3.WelcomeAdvice"/>
<bean id="registerInterceptor" class="aop3.RegisterInterceptor"/>
<bean id="registerThrowingAdvice" class="aop3.RegisterThrowingAdvice"/>
<bean id="registerService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><!-- 目標對象實現的介面 -->
<value>aop3.IRegisterService</value>
</property>
<property name="target"><!-- 配置(指定)目標對象 -->
<ref bean="registerServiceTarget"/>
</property>
<property name="interceptorNames"><!-- 需要織入到目標對象的切面(通知,advisor,攔截器) -->
<list>
<value>logingAdvice</value>
<!--
<value>welcomeAdvice</value>
<value>registerInterceptor</value>
<value>registerThrowingAdvice</value>
-->
</list>
</property>
</bean>
練習: (aop4)在攔截器設置一個屬性,記錄方法超時的時間;
4) 切入點:
通知具體應用到哪些類的哪些方法之上;
自定義切入點:用來約束Advice
步驟:
1)實現org.springframework.aop.ClassFilter--->用來過濾類(哪些類可以應用切面)
如果返回值為true時, 則應用切面; 否則不應用切面;
對類進行過濾,看要不要將切面應用到該類上;
2)實現org.springframework.aop.MethodMatcher--->用來過濾方法(類中的哪些方法應用切面)
方法1: boolean matches(Method, Class);//
方法2: boolean isRunTime(); 返回值為真,該切入點是動態切入點;
否則是靜態切入點; 方法3不會被執行;
方法3: boolean matches(Method, Class,Object[]);//這個方法可以動態的獲得方法的信息;
解釋:
靜態切入點:
在目標方法被執行以前, 確定切面是否應用到目標方法之上;
根據目標方法的靜態特徵(方法所在的類名A, 方法名f1), 來決定;
一般用這個;
動態切入點:
在目標方法每一次執行,會依照方法的動態的特徵來決定是否應用切面;
動態特徵: 當前方法的參數值, 等等;
會影響性能很大, 很少使用;
3)實現org.springframework.aop.Pointcut
4)實現org.springframework.aop.PointcutAdvisor:將Pointcut與Advice結合到一起。
是一個特殊的通知,它包含了切入點在內;
注意:
在此可定義兩個屬性,並且通過配置文件來完成裝配工作;
private Advice advice;//通知的實現;
private Pointcut pointcut;//通知的應用地點;
在配置文件中,將自定義的切入點與通知綁訂到一起,成為Advisor;
5)利用ProxyFactoryBean將advisor織入到目標對象
『貳』 使用java語言,如何對一個類中的靜態方法做切面編程
aop的事務代理機制最重要的放心是確定切入點,面,通知.具體看代碼,下面是在spring中配置的我自己寫的一個異常處理的aop作用類 ,該配置切入面在於在controller包下的所有類的所有註解為aspect的切面類,通液絕知類型為表示在目標方法之前切入,切入點為controller包下的所有類所有方法.至於樓主所說的靜態方法對於事務機制應該沒什麼區別吧,只要用within方法一樣可以的
<!-- 定義共同處理組件 -->
<bean id="loggerBean"
class="org.te.cloudnote.aspect.LoggerBean">
</bean>
<!-- 將loggerBean組件切入到Controller方法上 -->
<aop:config>
<斗螞!-- 要切入哪個共同處理組件,ref指定共同組件id值 -->
<aop:aspect ref="loggerBean">
<!-- aop:before表示在目標方法之前切入,
method指定方法名;pointcut指定目標組件 -->
<aop:before method="logController"
pointcut="within(org.te.cloudnote.controller..*)"/>
</aop:aspect>
</aop:config>
之後這個bean所定義的 自定義類的代碼如下 ,希望樓主給個採納,如果問友喜歡,也可以給我個贊哦,摸摸大
package org.te.cloudnote.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/空埋埋/封裝共同處理的組件
@Component//掃描,等價於<bean>定義
@Aspect//等價於<aop:aspect ref="">
public class LoggerBean {
//要在Controller.execute開始位置切入
//方法規則:public void 方法名(){...} (前置通知)
@Before("within(org.te.cloudnote.controller..*)")
//等價於<aop:before method="logController" pointcut="">
public void logController(){
System.out.println("進入Controller組件處理");
}
}
『叄』 spring切面反射,JoinPoint怎麼分辨基本數據類型和封裝類型
可磨臘以通過getClass()獲取神搭對象的類對象,然後通過isPrimitive()函數做判斷。瞎瞎滑即
arg.getClass().isPrimitive()
『肆』 簡述識別木材三個切面的方法 木材的橫切、縱切、*切怎麼識別
(一)橫睜猛歲切面
良材1.與樹干主軸(或木材紋理)垂直方向的切面.
良材2.在肉眼或放大鏡下識別木材特別重要.
(二)縱切面
弦切1.弦切面,與木材紋理悉睜或生長輪正切與木射線垂直的切面.
弦切2.徑切面,與木材紋理平行,與木材射線平行的切面;實際上徑切面是弦切面通知洞過髓心的一個特殊的切面.
『伍』 spring aop切面表達式詳解及例子
切面類型
execution格式
通配符
例子
一、 execution :使用「 execution (方法表達式)」匹配方法執行;
二、 within :使用「 within (類型表達式)」匹配指定類型內的方法執行;
三、 this :使用「 this (類型全限定名)」匹配當前AOP代理對象類型的執行方法;注意是AOP代理對象的類型匹配,這樣就可能包括引入介面方法也可以匹配;注意this中使用的表達式必須是類型全限定名,不支持通配符;
四、 target :使用「 target (類型全限定名)」匹配當前目標對象類型的執行方法;注意是目標對象的類型匹配,這樣就不包括引入介面也類型匹配;注意target中使用的表達式必須是類型全限定名,不消檔支持通配符;
五、 args :使用「 args (參數類型列表)」匹配當前執行的方法傳入的參數為指定類型的執行方法;注意是匹配傳入的參數類型,不是匹配方法簽名的參數類型;參數類型列表中的參數必須是類型全限定名,通配符不支持;args屬於動態切入點,這祥橋空種切入點開銷非常大,非特殊情況最好不要使用;
六、 @within :使用「 @within (註解類型)」匹配所以持有謹瞎指定註解類型內的方法;註解類型也必須是全限定類型名;
七、 @target :使用「 @target (註解類型)」匹配當前目標對象類型的執行方法,其中目標對象持有指定的註解;註解類型也必須是全限定類型名;
八、 @args :使用「 @args (註解列表)」匹配當前執行的方法傳入的參數持有指定註解的執行;註解類型也必須是全限定類型名;
九、 @annotation :使用「 @annotation (註解類型)」匹配當前執行方法持有指定註解的方法;註解類型也必須是全限定類型名;
十、 bean :使用「 bean (Bean id或名字通配符)」匹配特定名稱的Bean對象的執行方法;Spring AOP擴展的,在AspectJ中無相應概念;
『陸』 如何獲得被前置切面切入類的類名和方法名
在方法中添加一個參數就行了,然後掉用那個參數的方法,純肆禪具體的看看這個:
@Around("execution(* cn.e.pdsu..*.*(..))")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
Class clazz = pjp.getTarget().getClass();
Logger logger = Logger.getLogger(clazz);
StringBuffer log = new StringBuffer();// 日誌信息
log.append("執行 ").append(clazz).append("類的 ")
.append(pjp.getSignature().getName()).append("方法!");
logger.info(log);
Object retVal = null;
try {
retVal = pjp.proceed();
} catch (Exception e) {
logger.error(log);
logger.error(e.getMessage(), e.fillInStackTrace());// 記錄異常信息
}
return retVal;
}
這個是環繞通知,雹逗要是按Lz的方法只需要改改參數就行了;
@Before("execution(* com.dlmu.aml..*Service.update*(..))")
public void logBeforeChange(JoinPoint pjp)//添加參數的地方,剩下的就和上邊一樣了
{
Class clazz = pjp.getTarget().getClass();//得到當前執行的類
pjp.getSignature().getName();//得到執行的方法
System.out.println("調用類名:"做塵+className+";調用方法名:"+methodName);
}
『柒』 被調用方法如何加切面
1、首先定義一個被調族液用方法的切面實現類做穗扮。
2、其次在Spring配置文件中配置切面。
3、最後通過SpringIoC容器獲純灶取要攔截的類的實例就可以加切面了。
『捌』 spring切面Aspects
導入aop模塊:spring-aspects
xml實現: 開啟基於註解版的切面功能<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
1.通知方法
1.1 前置通知@Before
1.2 後置通知@After(目標睜渣方法運行結束後執行,【正常結束或異常結束都調用】)
1.3 返回通知@AfterReturning (目標方法正常返回後執行)
1.4 異常通知@AfterThrowing
1.5 環繞通知@Around (動態代理 ,手動推進悉稿悄目標方法運行[joinPoint.proceed])
2.定義業務邏輯類,在運行時執行通知方法
3.定義日誌切面類,裡面方法要動態感知邏輯類方法(給切面類方法標注敬廳何時何地運行通知方法)
4.將切面類和邏輯類都加入到容器,切面類加@Aspect註解
5.在配置類加@EnableAspectJAutoProxy開啟基於註解版的切面功能
使用切面總結:
1.將業務邏輯組件和切面類都加在容器中,告訴spring哪個是切面類@Aspect
2.在切面類上每一個通知方法上標注通知註解,告訴Spring什麼時候運行
3.開啟aop模式@EnableAspectJAutoProxy
『玖』 SpringBoot在切面中怎麼查詢修改前的數據
以下的問題就可以完美的解決了
自定姿隱義註解,切入點是controller的增、刪、改方法,切面中獲取到了參數、類名、方法名,在修改前要通過id查詢資料庫內容,怎麼獲取對應的service對象
非常簡單:
1. 加一個Interceptor,
2.在onPreHandle中看看能不能處理
註:只是這樣一來的話,就相當於又把請求攔跡者廳截了一嫌培遍