javascript
spring的aop的动态代理机制都有哪些_Spring学习(4):Spring AOP
Spring AOP說明
AOP(Aspect Oriented Pragraming)面向切面編程,AOP采用橫向抽取機制,取代了傳統縱向繼承體系的重復性代碼(性能監視、事務管理、安全檢查、緩存)。
所謂的傳統縱向繼承體系是指當你需要實現某個功能的時候需要去繼承某個類,而橫向抽取機制則是通過使用動態代理機制產生一個與之同級的對象,然后在代理對象中進行功能增強。
Spring AOP使用純Java實現,不需要專門的編譯過程和類加載器,在運行期通過代理方式向目標類織入增強代碼。
Spring的AOP代理
JDK動態代理:對實現了接口的類生成代理CGLib代理機制:對類生成代理
AOP相關術語
Joinpoint(連接點):所謂連接點是指那些被攔截到的點。在spring中,這些點指的是方法,因為spring只支持方法類型的連接點;Pointcut(切入點):所謂切入點是指我們要對哪些Joinpoint進行攔截的定義;Advice(通知/增強):所謂通知是指攔截到Joinpoint之后所要做的事情就是通知。通知分為前置通知,后置通知,異常通知,最終通知,環繞通知(切面要完成的功能);Introduction(引介):引介是一種特殊的通知在不修改類代碼的前提下, Introduction可以在運行期為類動態地添加一些方法或Field;Target(目標對象):代理的目標對象;Weaving(織入):是指把增強應用到目標對象來創建新的代理對象的過程。spring采用動態代理織入,而AspectJ采用編譯期織入和類裝載期織入;Proxy(代理):一個類被AOP織入增強后,就產生一個結果代理類;Aspect(切面) :是切入點和通知(引介)的結合。
AOP的底層實現
前面說過AOP代理有兩種,一種是JDK動態代理,用于對實現了接口的類生成代理;另一種是CGLib代理機制,用于對類生成代理。
JDK動態代理
新建一個Maven項目,名稱為SpringAOP,導入Junit依賴。新建com/envy/aop/demo文件夾,新建接口文件UserDao.java,里面的代碼為:
public interface UserDao { public void add(); public void update();}以及實現類UserDaoImpl.java文件:
public class UserDaoImpl implements UserDao { public void add() { System.out.println("this is add method"); } public void update() { System.out.println("this is update method"); }}接著新建com/envy/aop/test文件夾,新建測試文件AopTest.java,里面的代碼為:
public class AopTest { @Test public void testOne(){ UserDao userDao = new UserDaoImpl(); userDao.add(); userDao.update(); }}運行結果:
this is add methodthis is update method上述是傳統的編程方式,接下來是使用JDK動態代理模式的相關步驟,JDK動態代理模式用于對實現了接口的類生成代理,而此處的UserDao本身就是一個接口。
新建MyJDKProxy.java文件,里面代碼為:
public class MyJDKProxy implements InvocationHandler { private UserDao userDao; public MyJDKProxy(UserDao userDao){ this.userDao=userDao; } public Object createProxy(){ Object proxy= Proxy.newProxyInstance(userDao.getClass().getClassLoader(),userDao.getClass().getInterfaces(),this); return proxy; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if("add".equals(method.getName())){ //一些增強功能,如權限校驗 System.out.println("開始權限校驗操作"); return method.invoke(proxy,args); } return method.invoke(userDao,args); }}接著新建testTwo方法,里面代碼為:
@Test public void testTwo(){ UserDao userDao = new UserDaoImpl(); UserDao proxy = (UserDao) new MyJDKProxy(userDao).createProxy(); proxy.add(); proxy.update(); }運行結果:
Start permission verificationthis is add methodthis is update methodCGLIB動態代理
CGLIB(Code Generation Library)是一個開源項目!是一個強大的,高性能,高質量的Code生成類庫,它可以在運行期擴展Java類與實現Java接口。 Hibernate支持它來實現PO(Persistent Object 持久化對象)字節碼的動態生成(Hibernate實際使用Javassist生成代理,該代理對象就是持久化類的子類的實例),現在做cglib的開發,可以不用直接引入cglib的包,因為spring核心中已經集成了cglib。
CGLIB生成代理機制:其實生成了一個真實對象的子類。
新建ProductDao.java文件,里面的代碼為:
public class ProductDao { public void add(){ System.out.println("add product"); } public void update(){ System.out.println("update product"); }}接著新建測試方法testThree,里面的代碼為:
@Test public void testThree(){ ProductDao productDao = new ProductDao(); productDao.add(); productDao.update(); }運行結果:
add productupdate product上述是傳統的編程方式,接下來是使用CGLIB動態代理模式的相關步驟,CGLIB動態代理模式用于對類生成代理,而此處的ProductDao本身就是一個類。
新建MyCGLibProxy.java文件,里面代碼為:
public class MyCGLibProxy implements MethodInterceptor { private ProductDao productDao; public MyCGLibProxy(ProductDao productDao){ this.productDao=productDao; } public Object createProxy(){ //1、設置核心類 Enhancer enhancer = new Enhancer(); //2、設置父類 enhancer.setSuperclass(productDao.getClass()); //3、設置回調 enhancer.setCallback(this); //4、生成代理 Object proxy = enhancer.create(); return proxy; } public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { if("add".equals(method.getName())){ //一些增強功能,如權限校驗 System.out.println("Start permission verification"); return methodProxy.invokeSuper(proxy,args); } return methodProxy.invokeSuper(proxy,args); }}接著新建testFour方法,里面代碼為:
@Test public void testFour(){ ProductDao productDao = new ProductDao(); ProductDao proxy = (ProductDao) new MyCGLibProxy(productDao).createProxy(); proxy.add(); proxy.update(); }運行結果:
Start permission verificationadd productupdate product代理知識總結:1、Spring在運行期生成動態代理對象,不需要使用特殊的編譯器;2、SpringAOP的底層就是通過JDK動態代理或CGLib動態代理技術為目標Bean執行橫向織入。
若目標對象實現了若干接口,Spring使用JDK的java.lang.reflect.Proxy類代理;若目標對象沒有實現任何接口,Spring使用CGLIB庫生成目標對象的子類。在程序中應優先對接口創建代理,便于程序解耦維護。標記為final的方法不能被代理,因為該方法不能被重寫。因此JDK動態代理是針對接口生成子類,接口中的方法不能使用final來修飾;CGLIb是針對目標類生成子類,類或者方法不能使用final來修飾。
Spring只支持方法連接點,不支持屬性連接點。
Spring中的AOP
SpringAOP增強類型
AOP不是由Spring定義,而是AOP聯盟組織來定義的。Spring按照通知Advice在目標類方法的連接點位置,可以分為5個位置:前置通知:org.springframework.aop.MethodBeforeAdvice:在目標方法執行前實施增強;后置通知:org.springframework.aop.AfterReturningAdvice:在目標方法執行后實施增強;環繞通知:org.aopalliance.intercept.MethodInterceptor:在目標方法執行前后實施增強;異常拋出通知:org.springframework.aop.ThrowsAdvice:在方法拋出異常后實施增強;引介通知:org.springframework.aop.IntroductionInterceptor(不研究):在目標類中添加一些新的方法和屬性。
SpringAOP切面類型
Advisor(Spring中傳統切面)就是對PointCut應用Advice。(通常所說的Advisor是指只有一個Point和一個Advice,而Aspect是具有多個切點和多個通知的組合);Advisor :代表一般切面,Advice本身就是一個切面,對目標類所有方法進行攔截 (沒有切點);PointcutAdvisor :代表具有切點的切面,可以指定攔截目標類哪些方法;IntroductionAdvisor : 代表引介切面,針對引介通知而使用切面(不要求掌握)。
SpringAOP的開發
針對所有方法的增強(不帶切點的切面)
此處演示針對所有方法的增強也就是不帶切點的切面,相應的操作步驟如下:
第一步:導入相應的包。首先在pom.xml文件中引入spring-aop,spring-test和com.springsource.org.aopalliance:
org.springframework spring-aop 4.2.4.RELEASEaopalliance aopalliance 1.0org.springframework spring-test 4.2.4.RELEASE第二步:編寫被代理對象。新建com.envy.aop.student包,接著在里面新建接口StudentDao.java文件,里面代碼為:
public interface StudentDao { public void add(); public void update();}以及它的實現類StudentDaoImpl.java:
public class StudentDaoImpl implements StudentDao { public void add() { System.out.println("this is add method"); } public void update() { System.out.println("this is update method"); }}第三步,編寫增強的代碼。此處僅僅以前置通知為例演示如何編寫增強代碼(前置通知:org.springframework.aop.MethodBeforeAdvice:在目標方法執行前實施增強)。新建MyBeforeAdvice.java文件:
public class MyBeforeAdvice implements MethodBeforeAdvice { public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println("前置增強的方法"); }}第四步,生成代理(配置生成代理)。新建applicationContext.xml文件,里面的代碼如下:
第五步,注入測試。新建SpringAOPAdvisor.java測試文件,里面的代碼為:
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class SpringAOPAdvisor {// @Resource(name="studentDao") //這是不使用AOP代理對象 @Resource(name="studentDaoProxy") private StudentDao studentDao; @Test public void testOne(){ studentDao.add(); studentDao.update(); }}運行結果:
前置增強的方法this is add method前置增強的方法this is update method在第四步,生成代理對象時我們在applicationContext.xml文件中配置了一些屬性。其實就是生成代理Spring基于ProxyFactoryBean類,底層自動選擇使用JDK的動態代理還是CGLIB的代理。下面是其中的幾個屬性介紹:target :代理的目標對象;proxyInterfaces :代理要實現的接口,如果多個接口可以使用以下格式賦值:
....proxyTargetClass :是否對類代理而不是接口,設置為true時,使用CGLib代理;interceptorNames :需要織入目標的Advice;singleton :返回代理是否為單實例,默認為單例。optimize :當設置為true時,強制使用CGLib。
總結
以上是生活随笔為你收集整理的spring的aop的动态代理机制都有哪些_Spring学习(4):Spring AOP的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot启动不了_七款高St
- 下一篇: python画切片图_python切片操