深入理解Spring中的Lookup(方法注入)——最好用的@Lookup标签实例

前言

本文主要给大家介绍了关于Spring中Lookup(方法注入)的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍:

在使用Spring时,可能会遇到这种情况:一个单例的Bean依赖另一个非单例的Bean。如果简单的使用自动装配来注入依赖,就可能会出现一些问题,如下所示:

单例的Class A

1

2

3

4

5

6

7

8

9

10

@Component

public class ClassA {

 @Autowired

 private ClassB classB;

 public void printClass() {

  System.out.println("This is Class A: " this);

  classB.printClass();

 }

}

非单例的Class B

1

2

3

4

5

6

7

@Component

@Scope(value = SCOPE_PROTOTYPE)//注意这里,classB务必一直都得有这个多例prototype标签

public class ClassB {

  public void printClass() {

    System.out.println("This is Class B: " this);

  }

}

这里Class A采用了默认的单例scope,并依赖于Class B, 而Class B的scope是prototype,因此不是单例的,这时候跑个测试就看出这样写的问题:

1

2

3

4

5

6

7

8

9

10

11

12

13

@RunWith(SpringRunner.class)

@ContextConfiguration(classes = {ClassA.class, ClassB.class})

public class MyTest {

  @Autowired

  private ClassA classA;

  @Test

  public void simpleTest() {

    for (int i = 0; i < 3; i++) {

      classA.printClass();

    }

  }

}

输出的结果是:

This is Class A: ClassA@282003e1
This is Class B: ClassB@7fad8c79
This is Class A: ClassA@282003e1
This is Class B: ClassB@7fad8c79
This is Class A: ClassA@282003e1
This is Class B: ClassB@7fad8c79

可以看到,两个类的Hash Code在三次输出中都是一样。Class A的值不变是可以理解的,因为它是单例的,但是Class B的scope是prototype却也保持Hash Code不变,似乎也成了单例?

产生这种的情况的原因是,Class A的scope是默认的singleton,因此Context只会创建Class A的bean一次,所以也就只有一次注入依赖的机会,容器也就无法每次给Class A提供一个新的Class B。

不那么好的解决方案

要解决上述问题,可以对Class A做一些修改,让它实现ApplicationContextAware。(别忘了classB务必一直都得有这个多例prototype标签

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

@Component

public class ClassA implements ApplicationContextAware {

  private ApplicationContext applicationContext;

  public void printClass() {

    System.out.println("This is Class A: " this);

    getClassB().printClass();

  }

  public ClassB getClassB() {

    return applicationContext.getBean(ClassB.class);

  }

  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

    this.applicationContext = applicationContext;

  }

}

这样就能够在每次需要到Class B的时候手动去Context里找到新的bean。再跑一次测试后得到了以下输出:

This is Class A: com.devhao.ClassA@4df828d7
This is Class B: com.devhao.ClassB@31206beb
This is Class A: com.devhao.ClassA@4df828d7
This is Class B: com.devhao.ClassB@3e77a1ed
This is Class A: com.devhao.ClassA@4df828d7
This is Class B: com.devhao.ClassB@3ffcd140

可以看到Class A的Hash Code在三次输出中保持不变,而Class B的却每次都不同,说明问题得到了解决,每次调用时用到的都是新的实例。

但是这样的写法就和Spring强耦合在一起了,Spring提供了另外一种方法来降低侵入性。

@Lookup

Spring提供了一个名为@Lookup的注解,这是一个作用在方法上的注解,被其标注的方法会被重写,然后根据其返回值的类型,容器调用BeanFactory的getBean()方法来返回一个bean。(别忘了classB务必一直都得有这个多例prototype标签

1

2

3

4

5

6

7

8

9

10

11

12

@Component

public class ClassA {

  public void printClass() {

    System.out.println("This is Class A: " this);

    getClassB().printClass();

  }

  @Lookup

  public ClassB getClassB() {

    return null;

  }

}

可以发现简洁了很多,而且不再和Spring强耦合,再次运行测试依然可以得到正确的输出。
被标注的方法的返回值不再重要,因为容器会动态生成一个子类然后将这个被注解的方法重写/实现,最终调用的是子类的方法。

使用的@Lookup的方法需要符合如下的签名:

1

<public|protected> [abstract] <return-type> theMethodName(no-arguments);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值