Spring in Acton 4读书笔记之使用AOP为类动态添加方法

我计划完成50到100篇有关Spring的文章,这是第十三篇。本文对应Spring in Action(Spring实战)第四版第四章中(4.3.4 Annotating introductions)的内容,将讲解如何使用标签为类动态添加方法。

一些像Ruby和Groovy这样的语言,有开放类(open classes)的概念,可以在不改变类和对象的定义的情况下,增加新的方法。不幸的是,Java没有那么动态,一旦一个类编译好之后,很难再为这个类增加功能了。

但是仔细想想,使用AOP的时候,难道不是在动态增加功能吗?虽然没有为类增加方法,但是为这些类执行时增加了一些功能性。进而,使用AOP的introduction的概念,可以给Spring的bean添加方法。

在Spring中,aspect对目标对象进行代理,并且和目标对象有相同接口。试想一下,如果不仅具有目标对象的接口,还添加了一些目标对象没有的接口,那么通过调用这个代理,就可以实现目标对象没有实现的接口了。这样,尽管没有改变目标对象的代码,却在功能上添加了方法。

工作原理如下图:
使用AOP为类动态添加方法

举个例子,假设Performance是一个接口,现在想为这个接口的所有实现,动态添加一个performEncore()方法。首先我们要定义一个包含performEncore()方法的接口,再定义一个aspect将这个接口与Performance的实例关联。

定义包含要引入的方法的接口

定义包含要引入的performEncore()方法的接口:

1
2
3
public interface Encoreable {
void performEncore();
}

定义aspect,将方法引入到实例

1
2
3
4
5
6
7
@Aspect
public class EncoreableIntroducer {
@DeclareParents(value="concert.Performance+",
defaultImpl=DefaultEncoreable.class)
public static Encoreable encoreable;
}

在这个aspect中,没有使用常用的@Before,@After,@Around等标签,而是使用了@DeclareParents标签。它的value属性指定了哪些实例要引入方法,defaultImpl属性则指定了引入的接口(这个例子中是指Encoreable接口)的默认实现类,而在这个类(DefaultEncoreable)中有引入的方法的具体实现。此外,被引入的接口,使用static修饰。上面的语句中,concert.Performance+表示Performance的任何具体实现类,不包含Performance接口本身。在这个例子中,Performance接口的所有实现类都默认实现了Encoreable接口。所以,在使用Encoreable接口时,可以做到:既使用Performance的实现类的方法,又使用新添加的performEncore方法。至于Encoreable接口代表Performance的哪个具体实现类的实例,则可以在注入bean时决定,而注入的bean则自动有了新增加的performEncore方法,当然,从语法上看,是在使用Encoreable接口的方法。

下面的例子中,注入的bean(Performance接口的某个具体实现类的实例)执行了DefaultEncoreable的performEncore方法。

1
2
3
4
@Autowired
public void performEncore(Encoreable encoreable){
encoreable.performEncore();
}

最后,别忘了aspect自身需要生成实例,才能起作用:

装配aspect的bean

1
<bean class="concert.EncoreableIntroducer" />

装配bean的方法有很多种,这里是使用xml配置的方式。也可以使用java配置,装配bean,详见《Spring in Acton》第四版第二章《装配bean》读书笔记

© 2022 谈谈IT All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero