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實例化對象;

 

參考:

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-method-injection


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM