通過切面為Spring bean新增新的方法
阿新 • • 發佈:2019-01-01
背景:
Performance代表任何型別的現場表演,如舞臺劇、電影或音樂會。
Audience有四個方法,定義了一個觀眾在觀看演出時可能會做的事情。在演出之前,觀眾要就坐takeSeats()並將手機調至靜音狀態silenceCellPhones()。如果演出很精彩的話,觀眾應該會鼓掌喝彩applause()。不過,如果演出沒有達到觀眾預期的話,觀眾會要求退款demandRefund()。
加入Encoreable介面,代表此表演有返場演出performEncore()方法。此演出並不是常規的Performance中存在的,屬於新的方法。如何在執行perform()之後執行新的方法?
Java並不是動態語言。一旦類編譯完成了,我們就很難再為該類新增新的功能了。如果切面不僅僅實現了所包裝bean相同的介面,而且還實現了新的介面,那麼切面所通知的bean看起來似乎也像是實現了新的介面。其實底層實現類並沒有真的實現新的介面,當新的介面的方法被呼叫時,代理會把此呼叫委託給實現了新介面的某個實現物件,實際上,一個bean的實現被拆分到了多個類中。
Performance介面與實現類PerformanceImpl
public interface Performance {
void perform();
}
@Component("performance")
public class PerformanceImpl implements Performance {
@Override
public void perform() {
System.out.println("perform...");
}
}
常規的切面類:Audience類
@Component @Aspect public class Audience { @Pointcut("execution(* chapter04.performance.Performance.perform(..))") public void performance(){} @Around("performance()") public void watchPerformance(ProceedingJoinPoint jp){ try { System.out.println("Silencing cell phones"); System.out.println("Taking seats"); jp.proceed(); System.out.println("CLAP CLAP CLAP"); } catch (Throwable throwable) { throwable.printStackTrace(); System.out.println("Demanding a refund"); } } }
引入新的介面:Encoreable介面與實現類DefaultEncoreable
public interface Encoreable {
void performEncore();
}
public class DefaultEncoreable implements Encoreable {
@Override
public void performEncore() {
System.out.println("perform encore...");
}
}
新引入介面需要的切面類EncoreableIntroducer
/** * 通過@DeclareParents註解,將Encoreable介面引入到Performance bean中 * Created by Administrator on 2017/12/1. */ @Component @Aspect public class EncoreableIntroducer { /** * value屬性指定了哪種型別的bean要引入該介面,在本例中,也就是所有實現Performance的型別。 * defaultImpl屬性指定了為引入功能提供實現的類 * @DeclareParents 註解所標註的靜態屬性指明瞭要引入了介面。在這裡,我們所引入的是Encoreable介面。 */ @DeclareParents(value="chapter04.performance.Performance+",defaultImpl = DefaultEncoreable.class) public static Encoreable encoreable; }
applicationContext.xml配置
<context:component-scan base-package="aop_test,chapter04"/>
<!-- 開啟aop註解 -->
<aop:aspectj-autoproxy/>
測試
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class testPerformance {
@Autowired
Performance performance;
@Test
public void test(){
performance.perform();
Encoreable encoreable = (Encoreable) performance;
encoreable.performEncore();
}
}
測試結果
Silencing cell phones
Taking seats
perform...
CLAP CLAP CLAP
perform encore...