引介(Introduction)是指在不更改源代碼的情況,給一個現(xiàn)有類增加屬性、方法,以及讓現(xiàn)有類實現(xiàn)其它接口或指定其它父類等,從而改變類的靜態(tài)結(jié)構(gòu)。Spring AOP通過采代理加攔截器的方式來實現(xiàn)的,可以通過攔截器機制使一個實有類實現(xiàn)指定的接口。
在實際應(yīng)用中可以使用DefaultIntroductionAdvisor來配置引介,也可以直接繼承DefaultIntroductionAdvisor來實現(xiàn)引介。這里是昨天在《深入Spring 2:輕量級J2EE開發(fā)框架原理與實踐》中作的一個示例。總體感覺代理攔截機制實現(xiàn)的引介,達到類似于AspectJ那樣的語言擴展方式實現(xiàn)的AOP引介的火力還差很多。
示例是一個模擬Warcraft的小游戲,包括英雄、道具、技能、戰(zhàn)場(地圖)等。整個示例UML圖如下所示:
示例中的英雄、地圖及各自持有的道具等全部通過在Spring配置文件中設(shè)置。下面是配置文件中英雄及戰(zhàn)場的部分:
<!--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級山丘之王)實現(xiàn)了SuperHero接口,這樣使得概率出招成功的技能具有100%的出招成功率。
比如,下面是重擊技能的代碼:
import java.util.Random;
//重擊技能,具有20%的概率,可以增加英雄的攻擊力20點,如果角色變?yōu)镾uperHero,則重擊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只是一個標(biāo)識接口,內(nèi)容如下:
public interface SuperHero {
}
?
我們重點看看SuperHeroIntroductionAdvisor,這個引介就是讓某一個現(xiàn)有的對象實現(xiàn)指定接口。代碼如下示:
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);
?}
}
現(xiàn)在我們來討Spring AOP中引介的問題。假如我們的程序需要在Hero上有一個增強,然后通過Hero的實現(xiàn)BaseHero自身來發(fā)出技能,也即在BaseHero中包含調(diào)用Bash的代碼,則該引介將會失效。這是因為當(dāng)Hero自身調(diào)用的時候,已經(jīng)不再是通過代理對象調(diào)用,而是通過目標(biāo)對象Hero本身來調(diào)用,所有代理攔截都將失效,包括引介。
?
假如你是在Hero之外的另外一個攔截中來調(diào)用Bash,也就是說想讓一個引介外的攔截跟引介混合使用,則引介同樣失效。由于引介的失效,所以造成Bash認不出來SuperHero角色,這就是為什么10級山丘之王的重擊技能不能100%發(fā)出的原因。
?
代理攔截引介實際上是代理類實現(xiàn)指定接口,并沒有改變實際的類,比如不會因為superHero引入了SuperHero接口而對其它的Hero造成影響。另外注意的是,Spring AOP中的引介不能和任何切入點一起使用,因為它是應(yīng)用在類級別而不是方法級別。
?
確保是在代理對象上調(diào)用引介模塊,而不是在目標(biāo)對象。下面是修正后的山丘之王的作戰(zhàn)記錄:
?
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]
戰(zhàn)斗開始......
第1回合:玩家[Mountain King]向[Priestess of the Moon]發(fā)動攻擊![命中:失敗]
第2回合:玩家[Priestess of the Moon]向[Mountain King]發(fā)動攻擊![命中:成功]
生命值--[Priestess of the Moon:500]-[Mountain King:500]
基本傷害:60;英雄持有以下攻擊道具:物品野獸卷軸,攻擊增加了25%;強擊光環(huán)技能,攻擊力增加了10%;[實際攻攻擊力:81]
Mountain King--基本護甲:2;物品保護卷軸,護甲增加了2點;[實際防御:4]
實際傷害點數(shù):77
第3回合:玩家[10級山丘之王]向[Mountain King]發(fā)動攻擊![命中:成功]
生命值--[10級山丘之王:500]-[Mountain King:423]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,傷害提高了20點;物品野獸卷軸,攻擊增加了25%;強擊光環(huán)技能,攻擊力增加了10%;[實際攻攻擊力:101]
Mountain King--基本護甲:2;物品保護卷軸,護甲增加了2點;[實際防御:4]
實際傷害點數(shù):97
第4回合:玩家[Mountain King]向[10級山丘之王]發(fā)動攻擊![命中:成功]
生命值--[Mountain King:326]-[10級山丘之王:500]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,傷害提高了20點;[實際攻攻擊力:80]
10級山丘之王--基本護甲:1;專注光環(huán)技能,護甲增加了1點!;[實際防御:2]
實際傷害點數(shù):78
第5回合:玩家[Priestess of the Moon]向[10級山丘之王]發(fā)動攻擊![命中:失敗]
第6回合:玩家[10級山丘之王]向[Mountain King]發(fā)動攻擊![命中:失敗]
第7回合:玩家[Mountain King]向[Priestess of the Moon]發(fā)動攻擊![命中:成功]
生命值--[Mountain King:326]-[Priestess of the Moon:500]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,未使出來;[實際攻攻擊力:60]
Priestess of the Moon--基本護甲:1;專注光環(huán)技能,護甲增加了1點!;[實際防御:2]
實際傷害點數(shù):58
第8回合:玩家[Priestess of the Moon]向[Mountain King]發(fā)動攻擊![命中:失敗]
第9回合:玩家[10級山丘之王]向[Mountain King]發(fā)動攻擊![命中:成功]
生命值--[10級山丘之王:422]-[Mountain King:326]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,傷害提高了20點;物品野獸卷軸,攻擊增加了25%;強擊光環(huán)技能,攻擊力增加了10%;[實際攻攻擊力:101]
Mountain King--基本護甲:2;物品保護卷軸,護甲增加了2點;[實際防御:4]
實際傷害點數(shù):97
第10回合:玩家[Mountain King]向[Priestess of the Moon]發(fā)動攻擊![命中:失敗]
第11回合:玩家[Priestess of the Moon]向[Mountain King]發(fā)動攻擊![命中:成功]
生命值--[Priestess of the Moon:442]-[Mountain King:229]
基本傷害:60;英雄持有以下攻擊道具:物品野獸卷軸,攻擊增加了25%;強擊光環(huán)技能,攻擊力增加了10%;[實際攻攻擊力:81]
Mountain King--基本護甲:2;物品保護卷軸,護甲增加了2點;[實際防御:4]
實際傷害點數(shù):77
第12回合:玩家[10級山丘之王]向[Priestess of the Moon]發(fā)動攻擊![命中:成功]
生命值--[10級山丘之王:422]-[Priestess of the Moon:442]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,傷害提高了20點;物品野獸卷軸,攻擊增加了25%;強擊光環(huán)技能,攻擊力增加了10%;[實際攻攻擊力:101]
Priestess of the Moon--基本護甲:1;專注光環(huán)技能,護甲增加了1點!;[實際防御:2]
實際傷害點數(shù):99
第13回合:玩家[Mountain King]向[Priestess of the Moon]發(fā)動攻擊![命中:成功]
生命值--[Mountain King:152]-[Priestess of the Moon:343]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,未使出來;[實際攻攻擊力:60]
Priestess of the Moon--基本護甲:1;專注光環(huán)技能,護甲增加了1點!;[實際防御:2]
實際傷害點數(shù):58
第14回合:玩家[Priestess of the Moon]向[10級山丘之王]發(fā)動攻擊![命中:成功]
生命值--[Priestess of the Moon:285]-[10級山丘之王:422]
基本傷害:60;英雄持有以下攻擊道具:物品野獸卷軸,攻擊增加了25%;強擊光環(huán)技能,攻擊力增加了10%;[實際攻攻擊力:81]
10級山丘之王--基本護甲:1;專注光環(huán)技能,護甲增加了1點!;[實際防御:2]
實際傷害點數(shù):79
第15回合:玩家[10級山丘之王]向[Priestess of the Moon]發(fā)動攻擊![命中:成功]
生命值--[10級山丘之王:343]-[Priestess of the Moon:285]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,傷害提高了20點;物品野獸卷軸,攻擊增加了25%;強擊光環(huán)技能,攻擊力增加了10%;[實際攻攻擊力:101]
Priestess of the Moon--基本護甲:1;專注光環(huán)技能,護甲增加了1點!;[實際防御:2]
實際傷害點數(shù):99
第16回合:玩家[Mountain King]向[10級山丘之王]發(fā)動攻擊![命中:失敗]
第17回合:玩家[Priestess of the Moon]向[10級山丘之王]發(fā)動攻擊![命中:成功]
生命值--[Priestess of the Moon:186]-[10級山丘之王:343]
基本傷害:60;英雄持有以下攻擊道具:物品野獸卷軸,攻擊增加了25%;強擊光環(huán)技能,攻擊力增加了10%;[實際攻攻擊力:81]
10級山丘之王--基本護甲:1;專注光環(huán)技能,護甲增加了1點!;[實際防御:2]
實際傷害點數(shù):79
第18回合:玩家[10級山丘之王]向[Mountain King]發(fā)動攻擊![命中:失敗]
第19回合:玩家[Mountain King]向[Priestess of the Moon]發(fā)動攻擊![命中:成功]
生命值--[Mountain King:152]-[Priestess of the Moon:186]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,傷害提高了20點;[實際攻攻擊力:80]
Priestess of the Moon--基本護甲:1;專注光環(huán)技能,護甲增加了1點!;[實際防御:2]
實際傷害點數(shù):78
第20回合:玩家[Priestess of the Moon]向[Mountain King]發(fā)動攻擊![命中:失敗]
第21回合:玩家[10級山丘之王]向[Mountain King]發(fā)動攻擊![命中:成功]
生命值--[10級山丘之王:264]-[Mountain King:152]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,傷害提高了20點;物品野獸卷軸,攻擊增加了25%;強擊光環(huán)技能,攻擊力增加了10%;[實際攻攻擊力:101]
Mountain King--基本護甲:2;物品保護卷軸,護甲增加了2點;[實際防御:4]
實際傷害點數(shù):97
第22回合:玩家[Mountain King]向[Priestess of the Moon]發(fā)動攻擊![命中:成功]
生命值--[Mountain King:55]-[Priestess of the Moon:108]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,傷害提高了20點;[實際攻攻擊力:80]
Priestess of the Moon--基本護甲:1;專注光環(huán)技能,護甲增加了1點!;[實際防御:2]
實際傷害點數(shù):78
第23回合:玩家[Priestess of the Moon]向[Mountain King]發(fā)動攻擊![命中:成功]
生命值--[Priestess of the Moon:30]-[Mountain King:55]
基本傷害:60;英雄持有以下攻擊道具:物品野獸卷軸,攻擊增加了25%;強擊光環(huán)技能,攻擊力增加了10%;[實際攻攻擊力:81]
Mountain King--基本護甲:2;物品保護卷軸,護甲增加了2點;[實際防御:4]
實際傷害點數(shù):77
英雄 Mountain King 掛了
第24回合:玩家[10級山丘之王]向[Priestess of the Moon]發(fā)動攻擊![命中:成功]
生命值--[10級山丘之王:264]-[Priestess of the Moon:30]
基本傷害:60;英雄持有以下攻擊道具:重擊技能,傷害提高了20點;物品野獸卷軸,攻擊增加了25%;強擊光環(huán)技能,攻擊力增加了10%;[實際攻攻擊力:101]
Priestess of the Moon--基本護甲:1;專注光環(huán)技能,護甲增加了1點!;[實際防御:2]
實際傷害點數(shù):99
英雄 Priestess of the Moon 掛了