Spring中的lookup-method的作用
在Spring中,默认创建的对象是单例的,Spring会在一级缓存中持有该对象,方便下次直接获取,如果创建的是多例对象,Spring每次则会创建新的对象,不会进行缓存;
如果想在一个单例bean下引用一个多例bean,此时需要使用LookUp来解决;
测试如下:
ObjectA的getObjectC方法用@Lookup注解修饰或在xml配置<lookup-method>属性,而ObjectB和ObjectC对象都是通过@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)配置成了多例;
@Component
public class ObjectA {
private final static Log LOG = LogFactory.getLog(ObjectA.class);
@Autowired
private ObjectB objectB;
@Autowired
private ObjectC objectC;
public ObjectA() {
LOG.info("ObjectA constructor");
}
public ObjectB getObjectB() {
return objectB;
}
@Lookup
public ObjectC getObjectC() {
return objectC;
}
}
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class ObjectB {
private final static Log LOG = LogFactory.getLog(ObjectB.class);
public ObjectB() {
LOG.info("ObjectB constructor");
}
}
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class ObjectC {
private final static Log LOG = LogFactory.getLog(ObjectC.class);
public ObjectC() {
LOG.info("ObjectC constructor");
}
}
@Test
public void lookUpMethodTest() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(MethodOverrideConfig.class);
context.refresh();
ObjectA objectA = context.getBean(ObjectA.class);
ObjectB objectB1 = objectA.getObjectB();
ObjectB objectB2 = objectA.getObjectB();
System.out.println(objectB1);
System.out.println(objectB2);
ObjectC objectC1 = objectA.getObjectC();
ObjectC objectC2 = objectA.getObjectC();
System.out.println(objectC1);
System.out.println(objectC2);
}
结果如下:
ObjectB和ObjectC虽然是配置成多例,但是通过getBean多次获取ObjectB和ObjectC对象的效果不同,每次获取ObjectB的效果还是跟单例一样,而每次获取ObjectC的效果才是多例的;

分析如下:
AbstractAutowireCapableBeanFactory#createBeanInstance方法是使用合适的实例化策略来创建新的实例,创建的过程是会调用instantiateBean方法;
AbstractAutowireCapableBeanFactory#instantiateBean
instantiateBean方法是使用无参构造器进行实例化对象;通过getInstantiationStrategy方法获取实例化策略,根据获取的策略处理instantiate方法实例化对象的操作;

bean的生成策略,默认是cglib,而CglibSubclassingInstantiationStrategy是继承SimpleInstantiationStrategy,如下图;

bean实例化策略为CglibSubclassingInstantiationStrategy时,调用instantiate方法是SimpleInstantiationStrategy的;
SimpleInstantiationStrategy#instantiate(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory)

上面的测试代码中ObjectA#getObjectC有@Lookup注解修饰,因此对应的methodOverrides不为空,执行instantiateWithMethodInjection方法的逻辑,如下图;

CglibSubclassingInstantiationStrategy.CglibSubclassCreator#instantiate

对于有设置了methodOverride属性的bean会设置对应的方法拦截器;
当调用有@Lookup注解修饰或xml配置<lookup-method>的方法时,调用对应的方法会先进入拦截器CglibSubclassingInstantiationStrategy.LookupOverrideMethodInterceptor#intercept;

首先通过beanDefinition获取到对应的LookupOverride的属性,通过属性获取到对应方法的返回值,调用getBean实例化对象;
参考:

浙公网安备 33010602011771号