笔记9 AOP练习3(通过注解引入新功能 )

切面可以为Spring bean添加新方法。 在Spring中,切面只是实现了它们所包装bean相同接口的 代理。如果除了实现这些接口,代理也能暴露新接口的话,会怎么样 呢?那样的话,切面所通知的bean看起来像是实现了新的接口,即便 底层实现类并没有实现这些接口也无所谓。

使用Spring AOP,我们可以为bean引入新的方法。 代理拦截调用并委托给实现该方法的其他对象

需要注意的是,当引入接口的方法被调用时,代理会把此调用委 托给实现了新接口的某个其他对象。实际上,一个bean的实现被拆分 到了多个类中。 

场景描述:

    在一场音乐会中,添加川剧变脸的环节,但在原来的古典音乐表演类(Classcial.java)中没有这个方法,所以需要为这个表演类再新加一个方法。

1.创建一个新的接口Encoreable.java

1 package concert2;
2 
3 public interface Encoreable {
4     void performEncore();
5 }

2.实现这个接口DefaultEncoreable.java

 1 package concert2;
 2 
 3 public class DefaultEncoreable implements Encoreable {
 4 
 5     @Override
 6     public void performEncore() {
 7         // TODO Auto-generated method stub
 8         System.out.println("川剧变脸");
 9     }
10 
11 }

3.创建一个用于注入新方法的切面EncoreableIntroducer.java

 1 package concert2;
 2 
 3 import org.aspectj.lang.annotation.Aspect;
 4 import org.aspectj.lang.annotation.DeclareParents;
 5 import org.springframework.stereotype.Component;
 6 
 7 @Aspect
 8 @Component
 9 public class EncoreableIntroducer {
10     @DeclareParents(value = "concert2.Performance+", defaultImpl = DefaultEncoreable.class)
11     public static Encoreable encoreable;
12 }

EncoreableIntroducer是一个切面,同时声明它是一个bean。但是,它与我们 之前所创建的切面不同,它并没有提供前置、后置或环绕通知,而是 通过@DeclareParents注解,将Encoreable接口引入 到Performance bean中。 @DeclareParents注解由三部分组成:

  • value属性指定了哪种类型的bean要引入该接口。在本例中,也 就是所有实现Performance的类型。(标记符后面的加号表示 是Performance的所有子类型,而不是Performance本 身。)
  • defaultImpl属性指定了为引入功能提供实现的类。在这里, 我们指定的是DefaultEncoreable提供实现。
  • @DeclareParents注解所标注的静态属性指明了要引入了接 口。在这里,我们所引入的是Encoreable接口。 

而且在将EncoreableIntroducer声明为一个bean后,Encoreable也就成为了一个bean。

3.采用java装配bean  ConcertConfig.java

 1 package concert2;
 2 
 3 import org.springframework.context.annotation.ComponentScan;
 4 import org.springframework.context.annotation.Configuration;
 5 import org.springframework.context.annotation.EnableAspectJAutoProxy;
 6 
 7 @Configuration
 8 @EnableAspectJAutoProxy // 启用AspectJ自动代理
 9 @ComponentScan
10 public class ConcertConfig {
11 
12 }

4.测试

在此做了对比,因为Encoreable已经声明为bean,所以也可以直接加载,然后调用其方法。其次,因为Encoreable的方法已经添加到Performance中,所以也可以通过Performance的对象进行调用,但需要注意的是,在调用新加入的方法时要进行“伪装”,即将Performance的对象强制转换为Encoreable,然后再调用新加入的方法,以逃过编译器的检查。如果不进行引入的话,强行改变Performance对象的类型,然后调用“新方法”,则会报错。

 1 package concert2;
 2 
 3 import org.junit.Test;
 4 import org.junit.runner.RunWith;
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.test.context.ContextConfiguration;
 7 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 8 
 9 @RunWith(SpringJUnit4ClassRunner.class)
10 @ContextConfiguration(classes = concert.ConcertConfig.class)
11 public class ConcertTest {
12     @Autowired
13     public Performance p;
14     @Autowired
15     public Encoreable en;
16     @Test
17     public void test() {
18         p.perform();
19         System.out.println("-----------------------------");
20         System.out.println("自己创建对象调用");
21         en.performEncore();
22         System.out.println("-----------------------------");
23         System.out.println("通过Performance对象调用“新方法”");
24         Encoreable e = (Encoreable) p;
25         e.performEncore();
26     }
27 }

5.结果

省略的部分请参照笔记7

原文地址:https://www.cnblogs.com/lyj-gyq/p/8886259.html