关于为什么要使用@Lookup的原因,在我之前的博客Spring注解之@Lookup中有写到。

先看一段有问题的代码。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class AHandler extends Handler{

    public AHandler(Handler next) {
        super(next);
    }

    @Override
    public void d0() {
        System.out.println("A");
    }
}

@Component
public class HandlerFactory {

    private Handler handler;

    public HandlerFactory() {
        this.handler = aHandler();
    }

    @PostConstruct
    protected void init() {

    }

    @Lookup
    private AHandler aHandler() {
        return new AHandler(null);
    }
}

这段代码里有3个问题。3个什么问题,暂且不说,下面先简述一下@Lookup注解的原理。

以上面的错误代码为例:

  • Spring通过Cglib创建HandlerFactory的增强代理子类,然后通过代理类处理@Lookup
  • LookupOverrideMethodInterceptor通过BeanFactorygetBean方法获取AHandler实例。

问题在哪呢?

  1. 不能再HandlerFactory构造函数中调用aHandler()方法。

    上面的代码这么调用,相当于没有使用@Lookup。因为想要@Lookup生效,必须要先有代理类,而执行构造方法的时候还没有。

  2. 不能使用private修饰aHandler()方法。

    Cglib不能代理private修饰的方法,所以@Lookup也会失效。

  3. aHandler()方法应该传入需要的参数。

    这里,从aHandler()传入一个null和直接使用new AHandler(null)使用区别的。前者使用BeanFactory的getBean(Class requiredType, Object… args),后者使用getBean(Class requiredType)

    详见LookupOverrideMethodInterceptorintercept

所以,可以将错误的代码改成这样。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
@Component
public class HandlerFactory {

    private Handler handler;

    public HandlerFactory() {

    }

    @PostConstruct
    protected void init() {
        this.handler = aHandler(null);
    }

    @Lookup
    protected AHandler aHandler(Handler next) {
        return new AHandler(next);
    }
}