1. 程式人生 > >從山丘錘王之死談Spring AOP中的引介(Introduction)

從山丘錘王之死談Spring AOP中的引介(Introduction)

  引介(Introduction)是指在不更改原始碼的情況,給一個現有類增加屬性、方法,以及讓現有類實現其它介面或指定其它父類等,從而改變類的靜態結構。Spring AOP通過採代理加攔截器的方式來實現的,可以通過攔截器機制使一個實有類實現指定的介面。   在實際應用中可以使用DefaultIntroductionAdvisor來配置引介,也可以直接繼承DefaultIntroductionAdvisor來實現引介。這裡是昨天在《深入Spring 2:輕量級J2EE開發框架原理與實踐》中作的一個示例。總體感覺代理攔截機制實現的引介,達到類似於AspectJ那樣的語言擴充套件方式實現的AOP引介的火力還差很多。   示例是一個模擬Warcraft的小遊戲,包括英雄、道具、技能、戰場(地圖)等。整個示例UML圖如下所示:      示例中的英雄、地圖及各自持有的道具等全部通過在Spring配置檔案中設定。下面是配置檔案中英雄及戰場的部分: <!--10級角色引介--> <bean id="superHeroIntroduction"
  class="springroad.demo.chap5.wow.SuperHeroIntroductionAdvisor" />   <!--代理配置模板-->
 <bean id="baseHeroProxy"
  class="org.springframework.aop.framework.ProxyFactoryBean"
  abstract="true">
  <property name="proxyInterfaces"
   value="springroad.demo.chap5.wow.Hero" />
  <property name="interceptorNames">
   <list>
    <value>gameRecordAspect</value>
    <value>armorAspect</value>    
   </list>
  </property>
 </bean>  <!--定義英雄-->
 <bean id="MK" parent="baseHeroProxy">
  <property name="target">
   <bean class="springroad.demo.chap5.wow.BaseHero">
    <constructor-arg value="60" />
    <property name="armor" value="2" />
    <property name="health" value="500" />
    <property name="name" value="Mountain King" />
    <property name="auraAndSkill">
     <list>
      <ref bean="bash" />
      <ref bean="scrollOfProtection" />
     </list>
    </property>
   </bean>
  </property>
 </bean>
 <bean id="POM" parent="baseHeroProxy">
  <property name="target">
   <bean class="springroad.demo.chap5.wow.BaseHero">
    <constructor-arg value="60" />
    <property name="armor" value="1" />
    <property name="health" value="500" />
    <property name="name" value="Priestess of the Moon" />
    <property name="auraAndSkill">
     <list>
      <ref bean="devotionAura" />
      <ref bean="scrollOftheBeast" />
      <ref bean="trueshotAura" />
     </list>
    </property>
   </bean>
  </property>
 </bean>
 <bean id="superHero" parent="baseHeroProxy">
  <property name="target">
   <bean class="springroad.demo.chap5.wow.BaseHero">
    <constructor-arg value="60" />
    <property name="armor" value="1" />
    <property name="health" value="500" />
    <property name="name" value="10級山丘之王" />
    <property name="auraAndSkill">
     <list>
      <ref bean="bash" />
      <ref bean="devotionAura" />
      <ref bean="scrollOftheBeast" />
      <ref bean="trueshotAura" />
     </list>
    </property>
   </bean>
  </property>
  <property name="interceptorNames">
   <list>
    <value>gameRecordAspect</value>
    <value>armorAspect</value>   
    <value>superHeroIntroduction</value>
   </list>
  </property>
 </bean>
 <bean id="WarField"
  class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="target">
   <bean class="springroad.demo.chap5.wow.WarField">
    <property name="heros">
     <set>
      <ref bean="MK" />
      <ref bean="POM" />
      <ref bean="superHero" />
     </set>
    </property>
   </bean>
  </property>
  <property name="interceptorNames">
   <list>
    <value>warAspect</value>
   </list>
  </property>
 </bean>    通過配置可以看出,通過使用引介讓superHero(也即10級山丘之王)實現了SuperHero介面,這樣使得概率出招成功的技能具有100%的出招成功率。   比如,下面是重擊技能的程式碼:   
import java.util.Random;
//重擊技能,具有20%的概率,可以增加英雄的攻擊力20點,如果角色變為SuperHero,則重擊100%成功
public class Bash implements AttackProp {
 private boolean haveHit;
 private Random random = new Random();
 public int getAttack(Hero hero) {
  if (bigHit() || (hero instanceof SuperHero)) {
   haveHit = true;
  } else {
   haveHit = false;
  }
  return (haveHit ? 20 : 0);
 }  public boolean bigHit() {
  int rat = random.nextInt(10);
 // System.out.println(rat);
  return (rat <= 2);
 }  public String toString() {
  return "重擊技能," + (haveHit ? "傷害提高了20點" : "未使出來");
 }
}
  通過程式碼可以看出來,如果英雄是SuperHero(即10級角色),則出招成功率100%,否則只有20%多。SuperHero只是一個標識介面,內容如下:   public interface SuperHero {
  }
  我們重點看看SuperHeroIntroductionAdvisor,這個引介就是讓某一個現有的物件實現指定介面。程式碼如下示: import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.aop.support.DelegatingIntroductionInterceptor; public class SuperHeroIntroductionAdvisor extends DefaultIntroductionAdvisor {
 public SuperHeroIntroductionAdvisor() {
  super(new DelegatingIntroductionInterceptor(new SuperHero(){}), SuperHero.class);
 }
}
  現在我們來討Spring AOP中引介的問題。假如我們的程式需要在Hero上有一個增強,然後通過Hero的實現BaseHero自身來發出技能,也即在BaseHero中包含呼叫Bash的程式碼,則該引介將會失效。這是因為當Hero自身呼叫的時候,已經不再是通過代理物件呼叫,而是通過目標物件Hero本身來呼叫,所有代理攔截都將失效,包括引介。   假如你是在Hero之外的另外一個攔截中來呼叫Bash,也就是說想讓一個引介外的攔截跟引介混合使用,則引介同樣失效。由於引介的失效,所以造成Bash認不出來SuperHero角色,這就是為什麼10級山丘之王的重擊技能不能100%發出的原因。   代理攔截引介實際上是代理類實現指定介面,並沒有改變實際的類,比如不會因為superHero引入了SuperHero介面而對其它的Hero造成影響。另外注意的是,Spring AOP中的引介不能和任何切入點一起使用,因為它是應用在類級別而不是方法級別。   確保是在代理物件上呼叫引介模組,而不是在目標物件。下面是修正後的山丘之王的作戰記錄:
log4j:WARN No appenders could be found for logger (org.springframework.core.CollectionFactory).
log4j:WARN Please initialize the log4j system properly.
[英雄名稱:Mountain King,生命值:500,基本防禦:2]
[英雄名稱:Priestess of the Moon,生命值:500,基本防禦:1]
[英雄名稱:10級山丘之王,生命值:500,基本防禦:1]
戰鬥開始......
第1回合:玩家[Mountain King]向[Priestess of the Moon]發動攻擊![命中:失敗] 第2回合:玩家[Priestess of the Moon]向[Mountain King]發動攻擊![命中:成功]
生命值--[Priestess of the Moon:500]-[Mountain King:500]
基本傷害:60;英雄持有以下攻擊道具:物品野獸卷軸,攻擊增加了25%;強擊光環技能,攻擊力增加了10%;[實際攻攻擊力:81]
Mountain King--基本護甲:2;物品保護卷軸,護甲增加了2點;[實際防禦:4]
實際傷害點數:77 第3回合:玩家[10級山丘之王]向[Mountain King]發動攻擊![命中:成功]
生命值--[10級山丘之王:500]-[Mountain King:423]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,傷害提高了20點;物品野獸卷軸,攻擊增加了25%;強擊光環技能,攻擊力增加了10%;[實際攻攻擊力:101]
Mountain King--基本護甲:2;物品保護卷軸,護甲增加了2點;[實際防禦:4]
實際傷害點數:97 第4回合:玩家[Mountain King]向[10級山丘之王]發動攻擊![命中:成功]
生命值--[Mountain King:326]-[10級山丘之王:500]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,傷害提高了20點;[實際攻攻擊力:80]
10級山丘之王--基本護甲:1;專注光環技能,護甲增加了1點!;[實際防禦:2]
實際傷害點數:78 第5回合:玩家[Priestess of the Moon]向[10級山丘之王]發動攻擊![命中:失敗] 第6回合:玩家[10級山丘之王]向[Mountain King]發動攻擊![命中:失敗] 第7回合:玩家[Mountain King]向[Priestess of the Moon]發動攻擊![命中:成功]
生命值--[Mountain King:326]-[Priestess of the Moon:500]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,未使出來;[實際攻攻擊力:60]
Priestess of the Moon--基本護甲:1;專注光環技能,護甲增加了1點!;[實際防禦:2]
實際傷害點數:58 第8回合:玩家[Priestess of the Moon]向[Mountain King]發動攻擊![命中:失敗] 第9回合:玩家[10級山丘之王]向[Mountain King]發動攻擊![命中:成功]
生命值--[10級山丘之王:422]-[Mountain King:326]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,傷害提高了20點;物品野獸卷軸,攻擊增加了25%;強擊光環技能,攻擊力增加了10%;[實際攻攻擊力:101]
Mountain King--基本護甲:2;物品保護卷軸,護甲增加了2點;[實際防禦:4]
實際傷害點數:97 第10回合:玩家[Mountain King]向[Priestess of the Moon]發動攻擊![命中:失敗] 第11回合:玩家[Priestess of the Moon]向[Mountain King]發動攻擊![命中:成功]
生命值--[Priestess of the Moon:442]-[Mountain King:229]
基本傷害:60;英雄持有以下攻擊道具:物品野獸卷軸,攻擊增加了25%;強擊光環技能,攻擊力增加了10%;[實際攻攻擊力:81]
Mountain King--基本護甲:2;物品保護卷軸,護甲增加了2點;[實際防禦:4]
實際傷害點數:77 第12回合:玩家[10級山丘之王]向[Priestess of the Moon]發動攻擊![命中:成功]
生命值--[10級山丘之王:422]-[Priestess of the Moon:442]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,傷害提高了20點;物品野獸卷軸,攻擊增加了25%;強擊光環技能,攻擊力增加了10%;[實際攻攻擊力:101]
Priestess of the Moon--基本護甲:1;專注光環技能,護甲增加了1點!;[實際防禦:2]
實際傷害點數:99 第13回合:玩家[Mountain King]向[Priestess of the Moon]發動攻擊![命中:成功]
生命值--[Mountain King:152]-[Priestess of the Moon:343]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,未使出來;[實際攻攻擊力:60]
Priestess of the Moon--基本護甲:1;專注光環技能,護甲增加了1點!;[實際防禦:2]
實際傷害點數:58 第14回合:玩家[Priestess of the Moon]向[10級山丘之王]發動攻擊![命中:成功]
生命值--[Priestess of the Moon:285]-[10級山丘之王:422]
基本傷害:60;英雄持有以下攻擊道具:物品野獸卷軸,攻擊增加了25%;強擊光環技能,攻擊力增加了10%;[實際攻攻擊力:81]
10級山丘之王--基本護甲:1;專注光環技能,護甲增加了1點!;[實際防禦:2]
實際傷害點數:79 第15回合:玩家[10級山丘之王]向[Priestess of the Moon]發動攻擊![命中:成功]
生命值--[10級山丘之王:343]-[Priestess of the Moon:285]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,傷害提高了20點;物品野獸卷軸,攻擊增加了25%;強擊光環技能,攻擊力增加了10%;[實際攻攻擊力:101]
Priestess of the Moon--基本護甲:1;專注光環技能,護甲增加了1點!;[實際防禦:2]
實際傷害點數:99 第16回合:玩家[Mountain King]向[10級山丘之王]發動攻擊![命中:失敗] 第17回合:玩家[Priestess of the Moon]向[10級山丘之王]發動攻擊![命中:成功]
生命值--[Priestess of the Moon:186]-[10級山丘之王:343]
基本傷害:60;英雄持有以下攻擊道具:物品野獸卷軸,攻擊增加了25%;強擊光環技能,攻擊力增加了10%;[實際攻攻擊力:81]
10級山丘之王--基本護甲:1;專注光環技能,護甲增加了1點!;[實際防禦:2]
實際傷害點數:79 第18回合:玩家[10級山丘之王]向[Mountain King]發動攻擊![命中:失敗] 第19回合:玩家[Mountain King]向[Priestess of the Moon]發動攻擊![命中:成功]
生命值--[Mountain King:152]-[Priestess of the Moon:186]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,傷害提高了20點;[實際攻攻擊力:80]
Priestess of the Moon--基本護甲:1;專注光環技能,護甲增加了1點!;[實際防禦:2]
實際傷害點數:78 第20回合:玩家[Priestess of the Moon]向[Mountain King]發動攻擊![命中:失敗] 第21回合:玩家[10級山丘之王]向[Mountain King]發動攻擊![命中:成功]
生命值--[10級山丘之王:264]-[Mountain King:152]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,傷害提高了20點;物品野獸卷軸,攻擊增加了25%;強擊光環技能,攻擊力增加了10%;[實際攻攻擊力:101]
Mountain King--基本護甲:2;物品保護卷軸,護甲增加了2點;[實際防禦:4]
實際傷害點數:97 第22回合:玩家[Mountain King]向[Priestess of the Moon]發動攻擊![命中:成功]
生命值--[Mountain King:55]-[Priestess of the Moon:108]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,傷害提高了20點;[實際攻攻擊力:80]
Priestess of the Moon--基本護甲:1;專注光環技能,護甲增加了1點!;[實際防禦:2]
實際傷害點數:78 第23回合:玩家[Priestess of the Moon]向[Mountain King]發動攻擊![命中:成功]
生命值--[Priestess of the Moon:30]-[Mountain King:55]
基本傷害:60;英雄持有以下攻擊道具:物品野獸卷軸,攻擊增加了25%;強擊光環技能,攻擊力增加了10%;[實際攻攻擊力:81]
Mountain King--基本護甲:2;物品保護卷軸,護甲增加了2點;[實際防禦:4]
實際傷害點數:77
英雄 Mountain King 掛了 第24回合:玩家[10級山丘之王]向[Priestess of the Moon]發動攻擊![命中:成功]
生命值--[10級山丘之王:264]-[Priestess of the Moon:30]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,傷害提高了20點;物品野獸卷軸,攻擊增加了25%;強擊光環技能,攻擊力增加了10%;[實際攻攻擊力:101]
Priestess of the Moon--基本護甲:1;專注光環技能,護甲增加了1點!;[實際防禦:2]
實際傷害點數:99
英雄 Priestess of the Moon 掛了
最終勝利者:10級山丘之王

相關推薦

山丘Spring AOP引介(Introduction)

  引介(Introduction)是指在不更改原始碼的情況,給一個現有類增加屬性、方法,以及讓現有類實現其它介面或指定其它父類等,從而改變類的靜態結構。Spring AOP通過採代理加攔截器的方式來實現的,可以通過攔截器機制使一個實有類實現指定的介面。   在實際應用中可以使用DefaultIntrodu

.NET和JavaIT這個行業

一、有些事情難以回頭 開篇我得表名自己的立場:.NET JAVA同時使用者,但更加偏愛.NET.原因很簡單 1.NET語言更具開放性,從開源協議和規範可以看出; 2.語言更具優勢嚴謹; 3.開發工具VS更具生產力; 然而 1.Java,C#的職位比率在4:1,雖然這不是什麼問題,因為求職競爭的比例

Spring原理學習系列三:Spring AOP原理(原始碼層面分析)-------上部

引言 本文是Spring原理分析的第三篇博文,主要闡述Spring AOP相關概念,同時從原始碼層面分析AOP實現原理。對於AOP原理的理解有利於加深對Spring框架的深入理解。同時我也希望可以探究Spring框架在處理AOP的解決思路,學習框架的時候,有時候

Spring AOP入門到放棄概念以及Spring Boot AOP demo

AOP核心概念 1、橫切關注點 對哪些方法進行攔截,攔截後怎麼處理,這些關注點稱之為橫切關注點 2、切面(aspect)-》(通知+切點) 類是對物體特徵的抽象,切面就是對橫切關注點的抽象。 通知+切點 意思就是所有要被應用到增強(advic

Spring AOP

ces 代理模式 urn 目標 all ati ron 之前 後置 1、AOP的基本概念 在進行AOP開發前,先熟悉幾個概念: 連接點(Jointpoint):表示需要在程序中插入橫切關註點的擴展點,連接點可能是類初始化、方法執行、方法調用、字段調用或處理異常等等,Spri

SpringBoot集成Spring AOP

切面 pen ogl rac return owa collect web ali SpringBoot集成ApringAOP步驟如下: 1.導包 <dependency> <groupId>org.s

RabbitMQ在阿里雲安裝到在spring boot如何使用這一篇就可以了

//某個服務的具體情況 ps -ef | grep XXX //殺死程序 kill -9 程序ID,第一個 //檢視記憶體 free或者top //檢視磁碟使用情況 df -l //尋找檔案 find -name xxx //檢視埠使用情況 netstat -an |

shiro框架五-----在spring框架使用shiro

1. 下載 在Maven專案中的依賴配置如下: <!-- shiro配置 --> <dependency>   <groupId>org.apache.shiro</groupId> <artifactId>shiro-co

spring security的許可權控制

當我們在OAuth登陸後,獲取了登陸的令牌,使用該令牌,我們就有了訪問一些受OAuth保護的介面的能力。具體可以看本人的這兩篇部落

spring---aop(6)---Spring AOPProxyFactoryBean介紹

except trace col fine erl 參數 owa per face 寫在前面   這篇文章裏面就要說說Spring自己的AOP,搞清楚哪種方式是Spring自己實現的AOP,哪種方式是Spring引入aspectj的AOP。 簡單例子   Spring

Spring AOP高級——源碼實現(2)Spring AOP通知器(Advisor)與切面(Aspect)

color oaf 小麻煩 ntc tro sta ins pack package 本文例子完整源碼地址:https://github.com/yu-linfeng/BlogRepositories/tree/master/repositories/Spring%20AO

轉載《Spring AOPpointcut expression表達式解析 及匹配多個條件》

targe 組合 man fin rgs acc ans value account 原文地址:https://www.cnblogs.com/rainy-shurun/p/5195439.html 原文 Pointcut 是指那些方法需要被執行"AOP",是由"Poi

轉:Spring AOP的動態代理

原文連結:Spring AOP中的動態代理 0  前言 1  動態代理 1.1 JDK動態代理 1.2 CGLIB動態代理 1.2.1 CGLIB的代理用法 1.2.2 CGLIB的過濾功能

Spring AOP常用名詞解釋

Spring AOP中常用名詞解釋 1.切面(Aspect): 一個關注點的模組化,這個關注點可能會橫切多個物件。事務管理是J2EE應用中一個關於橫切關注點的很好的例子。 在Spring AOP中,切面可以使用通用類(基於模式的風格) 或者在普通類中以 @Aspect 註解(@Aspec

說一說 Spring AOP @Aspect 的高階用法

1 切點複合運算 支援在切點定義中加入以下運算子進行復合運算: 運算子 說明 && 與運算。 ! 非運算。 || 或運算。 2 切點命名 一般情況下,切點是直接宣告在需要增強方法處,這種切點的宣告方式稱為匿名切點,匿名切點只能在宣告處被使用 。

基於代理的spring aop目標物件引入新特性的實現

IntroductionInterceptor也是一個標記介面,其子類中有個便捷的實現類,即DelegatingIntroductionInterceptor. 說明,定義引入的實現類,也需要實現新增特性的介面. 目標物件類 package siye; pub

基於代理的spring aop多種通知實現

不需要引入額外的jar包,只需引入需要模組的spring內部jar包即可. 介面結構 標註的都是標記介面,其中大多數有明確約定的介面實現,只有異常通知介面沒有,但有其預設約定. Advice spring aop通知的頂層標記介面

基於代理的spring aop,切面的實現

基於代理的spring aop中,使用介面Advisor表示切面. 對目標物件織入通知可使用PointAdvisor介面及其子類,定義切面.其子類中有便捷的DefaultPointcutAdvisor實現類可使用. 對目標物件織入引入功能時,可使用Introductio

基於代理的spring aop,使用xml實現通知和引入

ProxyFactoryBean xml配置中,實現代理工廠的類 屬性 定義 target 代理的目標物件 proxyInterfaces 代理需要實現的

Spring AOP的JDK動態代理

一、關於靜態代理和動態代理的概念1 代理模式是常用的Java設計模式,它的特徵是代理類與委託類有同樣的介面,代理類主要負責為委託類預處理訊息、過濾訊息、把訊息轉發給委託類,以及事後處理訊息等。代理類與委託類之間通常會存在關聯關係,一個代理類的物件與一個委託類的物