最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

spring基礎概念AOP與動態(tài)代理理解

 更新時間:2021年06月11日 11:49:49   作者:woonu  
這篇文章主要為大家詳細介紹了spring基礎概念AOP與動態(tài)代理,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

一、代理模式

代理模式的英文叫做Proxy或Surrogate,中文都可譯為”代理“,所謂代理,就是一個人或者一個機構代表另一個人或者另一個機構采取行動。在一些情況下,一個客戶不想或者不能夠直接引用一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。

以簡單模擬事務的執(zhí)行過程說明各種代理區(qū)別

1.1 靜態(tài)代理

由程序員創(chuàng)建或由特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。

public interface PersonDao {

 void savePerson();
}
public class PersonDaoImpl implements PersonDao {

 @Override
 public void savePerson() {
  System.out.println("save person");
 }
}

public class Transaction {
 
 void beginTransaction(){
  System.out.println("begin Transaction");
 }
 
 void commit(){
  System.out.println("commit");
 }
}

接下來編寫靜態(tài)代理類---實現PersonDao接口

/**
 * 靜態(tài)代理類
 * @author qjc
 */
public class PersonDaoProxy implements PersonDao{

 PersonDao personDao;
 Transaction transaction;
 
 public PersonDaoProxy(PersonDao personDao, Transaction transaction) {
  this.personDao = personDao;
  this.transaction = transaction;
 }

 @Override
 public void savePerson() {
  this.transaction.beginTransaction();
  this.personDao.savePerson();
  this.transaction.commit();
 }
}

測試

/**
 * 測試靜態(tài)代理
 * @author qjc
 */
public class TestPersonProxy {
 
 @Test
 public void testSave(){
  PersonDao personDao = new PersonDaoImpl();
  Transaction transaction = new Transaction();
  PersonDaoProxy proxy = new PersonDaoProxy(personDao, transaction);
  
  proxy.savePerson();
 }
}

總結:

1、靜態(tài)代理模式并沒有做到事務的重用

2、假設dao有100個類,100個proxy,接口中有多少方法,在proxy層就得實現多少方法,有多少方法就要開啟和提交多少事務

3、如果一個proxy實現了多個接口,如果其中的一個接口發(fā)生變化(添加了一個方法),那么proxy也要做相應改變

1.2 JDK動態(tài)代理

動態(tài)代理類:在程序運行時,運用反射機制動態(tài)創(chuàng)建而成。

JDK的動態(tài)代理必須具備四個條件:1、目標接口 2、目標類 3、攔截器 4、代理類

使用上個例子的PersonDao接口、PersonDaoImpl類及Transaction類

編寫攔截器

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 攔截器 
 *   1、目標類導入進來 
 *   2、事物導入進來 
 *   3、invoke完成:開啟事務、調用目標對象的方法、事務提交
 * 
 * @author qjc
 */
public class Interceptor implements InvocationHandler {

 private Object target; // 目標類
 private Transaction transaction;

 public Interceptor(Object target, Transaction transaction) {
  this.target = target;
  this.transaction = transaction;
 }

 /**
  * @param proxy 目標對象的代理類實例
  * @param method 對應于在代理實例上調用接口方法的Method實例
  * @param args 傳入到代理實例上方法參數值的對象數組
  * @return 方法的返回值,沒有返回值是null
  * @throws Throwable
  */
 public Object invoke(Object proxy, Method method, Object[] args)
   throws Throwable {
  String methodName = method.getName();
  if ("savePerson".equals(methodName)
    || "deletePerson".equals(methodName)
    || "updatePerson".equals(methodName)) {

   this.transaction.beginTransaction(); // 開啟事務
   method.invoke(target); // 調用目標方法
   this.transaction.commit(); // 提交事務

  } else {
   method.invoke(target);
  }
  return null;
 }
}

測試

/**
 * 測試jdk動態(tài)代理
 * @author qjc
 */
public class TestJDKProxy {
 
 @Test
 public void testSave(){
  /**
   * 1、創(chuàng)建一個目標對象
   * 2、創(chuàng)建一個事務
   * 3、創(chuàng)建一個攔截器
   * 4、動態(tài)產生一個代理對象
   */
  Object target = new PersonDaoImpl();
  Transaction transaction = new Transaction();
  Interceptor interceptor = new Interceptor(target, transaction);
  /**
   * 參數一:設置代碼使用的類加載器,一般采用跟目標類相同的類加載器
   * 參數二:設置代理類實現的接口,跟目標類使用相同的接口
   * 參數三:設置回調對象,當代理對象的方法被調用時,會調用該參數指定對象的invoke方法
   */
  PersonDao personDao = (PersonDao) Proxy.newProxyInstance(
    target.getClass().getClassLoader(),
    target.getClass().getInterfaces(),
    interceptor);
  personDao.savePerson();
 }
}

總結

1、因為利用JDKProxy生成的代理類實現了接口,所以目標類中所有的方法在代理類中都有。

2、生成的代理類的所有的方法都攔截了目標類的所有的方法。而攔截器中invoke方法的內容正好就是代理類的各個方法的組成體。

3、利用JDKProxy方式必須有接口的存在。

4、invoke方法中的三個參數可以訪問目標類的被調用方法的API、被調用方法的參數、被調用方法的返回類型。

缺點:

1、在攔截器中除了能調用目標對象的目標方法以外,功能是比較單一的,在這個例子中只能處理事務

2、攔截器中的invoke方法的if判斷語句在真實的開發(fā)環(huán)境下是不靠譜的,因為一旦方法很多if語句需要寫很多。 

1.3 CGLIB動態(tài)代理

使用上個例子的PersonDaoImpl類和Transaction類(不用接口)

編寫攔截器類

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * CGLIB代理 攔截器 
 * @author qjc
 */
public class Interceptor implements MethodInterceptor {

 private Object target; // 代理的目標類
 private Transaction transaction;

 public Interceptor(Object target, Transaction transaction) {
  this.target = target;
  this.transaction = transaction;
 }

 /**
  * 創(chuàng)建目標對象的代理對象
  * 
  * @return
  */
 public Object createProxy() {
  // 代碼增強
  Enhancer enhancer = new Enhancer(); // 該類用于生成代理對象
  enhancer.setCallback(this); // 參數為攔截器
  enhancer.setSuperclass(target.getClass());// 設置父類
  return enhancer.create(); // 創(chuàng)建代理對象
 }

 /**
  * @param obj 目標對象代理類的實例
  * @param method 代理實例上 調用父類方法的Method實例
  * @param args 傳入到代理實例上方法參數值的對象數組
  * @param methodProxy 使用它調用父類的方法
  * @return
  * @throws Throwable
  */
 public Object intercept(Object obj, Method method, Object[] args,
   MethodProxy methodProxy) throws Throwable {
  this.transaction.beginTransaction();
  method.invoke(target);
  this.transaction.commit();
  return null;
 }
}

測試

/**
 * 測試cglib動態(tài)代理
 * 通過cglib產生的代理對象,代理類是目標類的子類
 * @author qjc
 */
public class TestCglibProxy {
 
 @Test
 public void testSave(){
 
  Object target = new PersonDaoImpl();
  Transaction transaction = new Transaction();
  Interceptor interceptor = new Interceptor(target, transaction);
  
  PersonDaoImpl personDaoImpl = (PersonDaoImpl) interceptor.createProxy();
  personDaoImpl.savePerson();
 }
}

總結:

1、CGlib是一個強大的,高性能,高質量的Code生成類庫。它可以在運行期擴展Java類與實現Java接口。

2、用CGlib生成代理類是目標類的子類。

3、用CGlib生成 代理類不需要接口

4、用CGLib生成的代理類重寫了父類的各個方法。

5、攔截器中的intercept方法內容正好就是代理類中的方法體 CGLIB和JDK動態(tài)代理區(qū)別:

JDK:

目標類和代理類實現了共同的接口

攔截器必須實現InvocationHandler接口,而這個接口中invoke方法體的內容就是代理對象方法體的內容

CGLIB:

目標類 是代理類的父類

攔截器必須實現MethodInterceptor接口,而接口中的intercept方法就是代理類的方法體,使用字節(jié)碼增強機制創(chuàng)建代理對象的.

二、面向切面編程

OOP(面向對象編程):封裝、繼承、多態(tài)、抽象

        封裝,對代碼進行基本的管理、模塊化的管理。每個類可能都有自己的職能,出了問題就是論事找人就行了。從修改角度講,直接修改代碼可能有風險,這不是個長遠之計,最自然的是從類型封裝變化。但是新的類型和舊的體系之間怎么去融合,所以說需要在類與類之間建立一種血緣關系。那么這就是繼承的需求,通過繼承就可以發(fā)現這些類之間是有關聯的,它們之間是有父子關系的。然后在繼承基礎之上多態(tài)起決定性的特征。所以說一般認為面向對象最核心的特征,其實是多態(tài)。前面幾個都是在做鋪墊的。多態(tài)才是它最核心的特征。子類中通過重寫方法,代表了擴展這個層面的東西,而它能融入老的體系中能夠正常工作,這是重用這個層面的東西,新的方法、舊的體系、擴展和重用。 

AOP(面向切面編程):

面向切面編程,是一種通過預編譯方式運行期動態(tài)代理實現在不修改源代碼的情況下給程序動態(tài)統(tǒng)一添加功能的一種技術. 

OOP與AOP區(qū)別:

  OOP:針對業(yè)務處理過程的實體及其屬性和行為進行抽象封裝,以獲得更加清楚的邏輯單元劃分。

   AOP:針對業(yè)務處理過程中的橫切邏輯 進行提取,它所面對的是處理過程中的某個步驟或者階段,以獲得邏輯過程中各部分之間低耦合的隔離效果。這兩種設計思想在目標上有著本質的差異。AOP做到了代碼塊的重用。 

spring AOP代理機制:

  1、若目標對象實現了若干接口,spring使用JDK的java.lang.reflect.Proxy類代理。

          優(yōu)點:因為有接口,所以使系統(tǒng)更加松耦合

          缺點:為每一個目標類創(chuàng)建接口

  2、若目標對象沒有實現任何接口,spring使用CGLIB庫生成目標對象的子類。

          優(yōu)點:因為代理類與目標類是繼承關系,所以不需要有接口的存在。

          缺點:因為沒有使用接口,所以系統(tǒng)的耦合性沒有使用JDK的動態(tài)代理好。

使用第一個例子的 PersonDao接口、PersonDaoImpl類和Transaction類

編寫spring配置

 <bean id="personDao" class="cn.qjc.aop.xml.PersonDaoImpl"></bean>
 <bean id="transaction" class="cn.qjc.aop.xml.Transaction"></bean>
 
 <aop:config>
  <!-- 切入點表達式 確定目標類 -->
  <aop:pointcut expression="execution(* cn.qjc.aop.xml.PersonDaoImpl.*(..))" id="perform"/>
 
  <!-- ref指向對象就是切面 -->
  <aop:aspect ref="transaction">
   <aop:before method="beginTransaction" pointcut-ref="perform"/>
   <aop:after-returning method="commit" pointcut-ref="perform"/>
  </aop:aspect>
 </aop:config>
 
</beans>

測試

/**
 * 測試spring動態(tài)代理
 * @author qjc
 */
public class TransactionTest {

 @Test
 public void testSave(){
  ApplicationContext context = new ClassPathXmlApplicationContext("cn/qjc/aop/xml/applicationContext.xml");
  PersonDao personDao = (PersonDao) context.getBean("personDao");
  personDao.savePerson();
 }
}

spring AOP原理

1、當spring容器啟動的時候,加載兩個bean,對像個bean進行實例化
2、當spring容器對配置文件解析到<aop:config>的時候,把切入點表達式解析出來,按照切入點表達式匹配spring容器內容的bean
3、如果匹配成功,則為該bean創(chuàng)建代理對象
4、當客戶端利用context.getBean獲取一個對象時,如果該對象有代理對象,則返回代理對象,如果沒有代理對象,則返回對象本身

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • 23種設計模式(21)java享元模式

    23種設計模式(21)java享元模式

    這篇文章主要為大家詳細介紹了23種設計模式之java享元模式,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Logback的使用及如何配置

    Logback的使用及如何配置

    這篇文章主要介紹了Logback的使用及如何配置,幫助大家更好的理解和學習使用Logback,感興趣的朋友可以了解下
    2021-03-03
  • MyBatis分頁插件PageHelper的使用與原理

    MyBatis分頁插件PageHelper的使用與原理

    提到插件相信大家都知道,插件的存在主要是用來改變或者增強原有的功能,MyBatis中也一樣,下面這篇文章主要給大家介紹了關于Mybatis第三方PageHelper分頁插件的使用與原理,需要的朋友可以參考下
    2023-02-02
  • SpringBoot使用Redisson實現分布式鎖(秒殺系統(tǒng))

    SpringBoot使用Redisson實現分布式鎖(秒殺系統(tǒng))

    這篇文章主要為大家詳細介紹了SpringBoot使用Redisson實現分布式鎖,秒殺系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • spring初始化源碼之關鍵類和擴展接口詳解

    spring初始化源碼之關鍵類和擴展接口詳解

    Spring就是一個大工廠,可以將所有對象的創(chuàng)建和依賴關系的維護交給Spring管理,下面這篇文章主要給大家介紹了關于spring初始化源碼之關鍵類和擴展接口的相關資料,需要的朋友可以參考下
    2023-04-04
  • Java字符串比較方法equals的空指針異常的解決

    Java字符串比較方法equals的空指針異常的解決

    這篇文章主要介紹了Java字符串比較方法equals的空指針異常的解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-09-09
  • Java反射之Call stack introspection詳解

    Java反射之Call stack introspection詳解

    這篇文章主要介紹了Java反射之Call stack introspection詳解,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11
  • Springboot+jwt實現在線用戶功能(示例代碼)

    Springboot+jwt實現在線用戶功能(示例代碼)

    這篇文章主要介紹了Springboot+jwt實現在線用戶功能,本文通過實例代碼給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧
    2024-12-12
  • 用遞歸查找有序二維數組的方法詳解

    用遞歸查找有序二維數組的方法詳解

    本篇文章是對用遞歸查找有序二維數組的方法進行了詳細的分析介紹,需要的朋友參考下
    2013-06-06
  • Lombok中@Builder和@SuperBuilder注解的用法案例

    Lombok中@Builder和@SuperBuilder注解的用法案例

    @Builder?是?lombok?中的注解,可以使用builder()構造的Person.PersonBuilder對象進行鏈式調用,給所有屬性依次賦值,這篇文章主要介紹了Lombok中@Builder和@SuperBuilder注解的用法,需要的朋友可以參考下
    2023-01-01

最新評論

荆门市| 丽江市| 吉林省| 夏河县| 铜川市| 河间市| 武清区| 保山市| 兴业县| 尼木县| 全椒县| 门源| 古浪县| 祁阳县| 赤峰市| 临澧县| 葫芦岛市| 扎赉特旗| 保山市| 科技| 江西省| 凤庆县| 东乡| 都昌县| 宁蒗| 法库县| 伽师县| 承德县| 鄂尔多斯市| 平安县| 唐河县| 崇州市| 汝城县| 额尔古纳市| 四子王旗| 同心县| 拉萨市| 丹棱县| 东莞市| 永顺县| 会昌县|