欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

spring基礎(chǔ)概念A(yù)OP與動(dòng)態(tài)代理理解

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

一、代理模式

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

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

1.1 靜態(tài)代理

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

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)代理類---實(shí)現(xiàn)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();
 }
}

總結(jié):

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

2、假設(shè)dao有100個(gè)類,100個(gè)proxy,接口中有多少方法,在proxy層就得實(shí)現(xiàn)多少方法,有多少方法就要開啟和提交多少事務(wù)

3、如果一個(gè)proxy實(shí)現(xiàn)了多個(gè)接口,如果其中的一個(gè)接口發(fā)生變化(添加了一個(gè)方法),那么proxy也要做相應(yīng)改變

1.2 JDK動(dòng)態(tài)代理

動(dòng)態(tài)代理類:在程序運(yùn)行時(shí),運(yùn)用反射機(jī)制動(dòng)態(tài)創(chuàng)建而成。

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

使用上個(gè)例子的PersonDao接口、PersonDaoImpl類及Transaction類

編寫攔截器

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

/**
 * 攔截器 
 *   1、目標(biāo)類導(dǎo)入進(jìn)來 
 *   2、事物導(dǎo)入進(jìn)來 
 *   3、invoke完成:開啟事務(wù)、調(diào)用目標(biāo)對(duì)象的方法、事務(wù)提交
 * 
 * @author qjc
 */
public class Interceptor implements InvocationHandler {

 private Object target; // 目標(biāo)類
 private Transaction transaction;

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

 /**
  * @param proxy 目標(biāo)對(duì)象的代理類實(shí)例
  * @param method 對(duì)應(yīng)于在代理實(shí)例上調(diào)用接口方法的Method實(shí)例
  * @param args 傳入到代理實(shí)例上方法參數(shù)值的對(duì)象數(shù)組
  * @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(); // 開啟事務(wù)
   method.invoke(target); // 調(diào)用目標(biāo)方法
   this.transaction.commit(); // 提交事務(wù)

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

測試

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

總結(jié)

1、因?yàn)槔肑DKProxy生成的代理類實(shí)現(xiàn)了接口,所以目標(biāo)類中所有的方法在代理類中都有。

2、生成的代理類的所有的方法都攔截了目標(biāo)類的所有的方法。而攔截器中invoke方法的內(nèi)容正好就是代理類的各個(gè)方法的組成體。

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

4、invoke方法中的三個(gè)參數(shù)可以訪問目標(biāo)類的被調(diào)用方法的API、被調(diào)用方法的參數(shù)、被調(diào)用方法的返回類型。

缺點(diǎn):

1、在攔截器中除了能調(diào)用目標(biāo)對(duì)象的目標(biāo)方法以外,功能是比較單一的,在這個(gè)例子中只能處理事務(wù)

2、攔截器中的invoke方法的if判斷語句在真實(shí)的開發(fā)環(huán)境下是不靠譜的,因?yàn)橐坏┓椒ê芏鄆f語句需要寫很多。 

1.3 CGLIB動(dòng)態(tài)代理

使用上個(gè)例子的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; // 代理的目標(biāo)類
 private Transaction transaction;

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

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

 /**
  * @param obj 目標(biāo)對(duì)象代理類的實(shí)例
  * @param method 代理實(shí)例上 調(diào)用父類方法的Method實(shí)例
  * @param args 傳入到代理實(shí)例上方法參數(shù)值的對(duì)象數(shù)組
  * @param methodProxy 使用它調(diào)用父類的方法
  * @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動(dòng)態(tài)代理
 * 通過cglib產(chǎn)生的代理對(duì)象,代理類是目標(biāo)類的子類
 * @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();
 }
}

總結(jié):

1、CGlib是一個(gè)強(qiáng)大的,高性能,高質(zhì)量的Code生成類庫。它可以在運(yùn)行期擴(kuò)展Java類與實(shí)現(xiàn)Java接口。

2、用CGlib生成代理類是目標(biāo)類的子類。

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

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

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

JDK:

目標(biāo)類和代理類實(shí)現(xiàn)了共同的接口

攔截器必須實(shí)現(xiàn)InvocationHandler接口,而這個(gè)接口中invoke方法體的內(nèi)容就是代理對(duì)象方法體的內(nèi)容

CGLIB:

目標(biāo)類 是代理類的父類

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

二、面向切面編程

OOP(面向?qū)ο缶幊?:封裝、繼承、多態(tài)、抽象

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

AOP(面向切面編程):

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

OOP與AOP區(qū)別:

  OOP:針對(duì)業(yè)務(wù)處理過程的實(shí)體及其屬性和行為進(jìn)行抽象封裝,以獲得更加清楚的邏輯單元?jiǎng)澐帧?/p>

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

spring AOP代理機(jī)制:

  1、若目標(biāo)對(duì)象實(shí)現(xiàn)了若干接口,spring使用JDK的java.lang.reflect.Proxy類代理。

          優(yōu)點(diǎn):因?yàn)橛薪涌?,所以使系統(tǒng)更加松耦合

          缺點(diǎn):為每一個(gè)目標(biāo)類創(chuàng)建接口

  2、若目標(biāo)對(duì)象沒有實(shí)現(xiàn)任何接口,spring使用CGLIB庫生成目標(biāo)對(duì)象的子類。

          優(yōu)點(diǎn):因?yàn)榇眍惻c目標(biāo)類是繼承關(guān)系,所以不需要有接口的存在。

          缺點(diǎn):因?yàn)闆]有使用接口,所以系統(tǒng)的耦合性沒有使用JDK的動(dòng)態(tài)代理好。

使用第一個(gè)例子的 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>
  <!-- 切入點(diǎn)表達(dá)式 確定目標(biāo)類 -->
  <aop:pointcut expression="execution(* cn.qjc.aop.xml.PersonDaoImpl.*(..))" id="perform"/>
 
  <!-- ref指向?qū)ο缶褪乔忻?-->
  <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動(dòng)態(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、當(dāng)spring容器啟動(dòng)的時(shí)候,加載兩個(gè)bean,對(duì)像個(gè)bean進(jìn)行實(shí)例化
2、當(dāng)spring容器對(duì)配置文件解析到<aop:config>的時(shí)候,把切入點(diǎn)表達(dá)式解析出來,按照切入點(diǎn)表達(dá)式匹配spring容器內(nèi)容的bean
3、如果匹配成功,則為該bean創(chuàng)建代理對(duì)象
4、當(dāng)客戶端利用context.getBean獲取一個(gè)對(duì)象時(shí),如果該對(duì)象有代理對(duì)象,則返回代理對(duì)象,如果沒有代理對(duì)象,則返回對(duì)象本身

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • java內(nèi)存優(yōu)化的方法總結(jié)

    java內(nèi)存優(yōu)化的方法總結(jié)

    在本篇文章里小編給大家分享的是一篇關(guān)于java內(nèi)存優(yōu)化的方法總結(jié)內(nèi)容,有需要的朋友們可以學(xué)習(xí)下。
    2021-06-06
  • Java網(wǎng)絡(luò)編程之TCP通信完整代碼示例

    Java網(wǎng)絡(luò)編程之TCP通信完整代碼示例

    這篇文章主要介紹了Java網(wǎng)絡(luò)編程之TCP通信完整代碼示例,具有一定借鑒價(jià)值,需要的朋友可以了解下。
    2017-12-12
  • 通過IEAD+Maven快速搭建SSM項(xiàng)目的過程(Spring + Spring MVC + Mybatis)

    通過IEAD+Maven快速搭建SSM項(xiàng)目的過程(Spring + Spring MVC + Mybatis)

    這篇文章主要介紹了通過IEAD+Maven快速搭建SSM項(xiàng)目的過程(Spring + Spring MVC + Mybatis),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • Spring Boot整合JPA使用多個(gè)數(shù)據(jù)源的方法步驟

    Spring Boot整合JPA使用多個(gè)數(shù)據(jù)源的方法步驟

    這篇文章主要給大家介紹了關(guān)于Spring Boot整合JPA使用多個(gè)數(shù)據(jù)源的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring Boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • spring的TransactionSynchronizationAdapter事務(wù)源碼解析

    spring的TransactionSynchronizationAdapter事務(wù)源碼解析

    這篇文章主要介紹了spring的TransactionSynchronizationAdapter事務(wù)源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • Spring Security基本架構(gòu)與初始化操作流程詳解

    Spring Security基本架構(gòu)與初始化操作流程詳解

    這篇文章主要介紹了Spring Security基本架構(gòu)與初始化操作流程,Spring Security是一個(gè)能夠?yàn)榛赟pring的企業(yè)應(yīng)用系統(tǒng)提供聲明式的安全訪問控制解決方案的安全框架
    2023-03-03
  • 詳解Java匿名內(nèi)部類

    詳解Java匿名內(nèi)部類

    這篇文章介紹了Java匿名內(nèi)部類的實(shí)現(xiàn),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • 詳細(xì)介紹Java關(guān)鍵字throw?throws?Throwable的用法與區(qū)別

    詳細(xì)介紹Java關(guān)鍵字throw?throws?Throwable的用法與區(qū)別

    這篇文章主要介紹了java中throws與throw及Throwable的用法和區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • Java的MyBatis+Spring框架中使用數(shù)據(jù)訪問對(duì)象DAO模式的方法

    Java的MyBatis+Spring框架中使用數(shù)據(jù)訪問對(duì)象DAO模式的方法

    Data Access Object數(shù)據(jù)訪問對(duì)象模式在Java操作數(shù)據(jù)庫部分的程序設(shè)計(jì)中經(jīng)常被使用到,這里我們就來看一下Java的MyBatis+Spring框架中使用數(shù)據(jù)訪問對(duì)象DAO模式的方法:
    2016-06-06
  • 淺析JAVA Lock鎖原理

    淺析JAVA Lock鎖原理

    這篇文章主要介紹了JAVA Lock鎖原理的相關(guān)資料,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07

最新評(píng)論