spring中bean的加载1
来源:互联网 发布:商业网站源码 编辑:程序博客网 时间:2024/06/06 15:52
BEAN的加载
通过对于前面的了解,基本上对于Xml配置文件的加载和解析有一个粗略的了解。如果需要详细的了解,可以再结合郝佳编著的《spring源码深度解析》一书相关内容,可以参考着并且编著一些实例。
对于bean的加载的功能可能比bean的解析要 复杂的多。
对于加载bean,这里还是以刚开始的代码:
ApplicationContext context =newClassPathXmlApplicationContext("spring-config.xml");
PetStoreServiceImpl petstore = context.getBean("petstore",PetStoreServiceImpl.class);
这里个getBean()方法,
BeanFactory:Interface(接口)该接口中getBean方法,实现的类是AbstractBeanFactory :
public <T> T getBean(Stringname, Class<T> requiredType)throwsBeansException {
return doGetBean(name,requiredType, null,false);
}
其中的dogetBean方法:参数name是要获取的bean的name,requiredType为要获取的bean的需要的type,args只有在创建一个原型type时可以使用显示的参数对于一个静态的工厂方法操作,其他任何情形下使用非null的参数都是非法的。Typecheckonly,则是该实例是否止水进行类型的检查,而不是作为实际使用而定的。这里final作为参数变量的修饰符,如果是实际基本数据类型变量,则是在方法内部该变量的副本不允许被改变;如果是对象引用,在方法内部对象引用不能被改变。
@SuppressWarnings("unchecked")
protected <T> TdoGetBean(
final Stringname, final Class<T>requiredType, final Object[]args, booleantypeCheckOnly)
throws BeansException {
//(1)这里需要使用BeanFactoryUtils中静态方法对于beanName进行处理
//提取对应的beanName
final StringbeanName = transformedBeanName(name);
Objectbean;
// Eagerly check singleton cachefor manually registered //singletons.(2)单例bean创建:检查缓存中或者实例工厂中是否有对应的实例。因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,spring创建bean的原则是不等bean创建完成,就会将创建bean的ObjectFactory提早曝光,将ObjectFactory加入到缓存中,一旦下个bean创建的时候需要依赖上个bean,则直接使用ObjectFactory,
//直接尝试从缓存获取或者singletonFactories中的ObjectFactory中获取
ObjectsharedInstance= getSingleton(beanName);
if (sharedInstance !=null && args == null) {
if (logger.isDebugEnabled()) {
if(isSingletonCurrentlyInCreation(beanName)) {
……
}
else {
logger.debug("Returning cached instance of singleton bean '" +beanName+ "'");
}
}
//获得beanfactory或者是通过factory获得beanInstance(3),存在BeanFactory的情况并不是直接返回实例本身而是返回指定方法返回的实例
bean =getObjectForBeanInstance(sharedInstance,name,beanName,null);
}
else {
//原型模式的依赖检查
// 只有在单例情况下才会尝试解决循环依赖,原型模式情况下,如果我们已经创建了该beaninstance,出现循环引用的情况
//当前beanName是否已经在creation中创建,有的话,抛异常
if(isPrototypeCurrentlyInCreation(beanName)) {
throw newBeanCurrentlyInCreationException(beanName);
}
//(5)检测parentBeanFactory:检查相应的beandefintion是否已经在存在,不存在则尝试从parentBeanFactory中检测
// Check if bean definition exists in this factory.
BeanFactoryparentBeanFactory= getParentBeanFactory();
if (parentBeanFactory!=null&& !containsBeanDefinition(beanName)) {
// Not found -> check parent.
StringnameToLookup= originalBeanName(name);
if (args !=null) {
// Delegation to parent with explicit args.
return (T)parentBeanFactory.getBean(nameToLookup,args);
}
else {
// No args -> delegate to standard getBean method.
returnparentBeanFactory.getBean(nameToLookup,requiredType);
}
}
//()仅作为类型检查使用,如果不是仅仅做类型检查,则是创建bean,这里要进行记录
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
//(6)将存储xml配置文件的GenericBeanDefinition转换为RootBeanDefinition,如果指定BEANName是子bean的话,同时合并父类的相关属性(对于beanName相同的beandefintion合并,并进行检查)
try {
final RootBeanDefinitionmbd =getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd,beanName, args);
//(7)寻找依赖:初始化当前bean所依赖的bean
String[]dependsOn=mbd.getDependsOn();
if (dependsOn !=null) {
for (StringdependsOnBean : dependsOn) {
getBean(dependsOnBean);
registerDependentBean(dependsOnBean,beanName);
}
}
//(8)针对不同的scope进行bean的创建,有singleton,prototype ,other
//(8)singleton模式创建bean,创建bean的实例,这里使用了内部类ObjectFactory
if (mbd.isSingleton()) {
sharedInstance =getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject()throws BeansException {
try {
return createBean(beanName,mbd,args);
}
catch (BeansExceptionex) {
destroySingleton(beanName);
throwex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance,name,beanName,mbd);
}
//如果不是singleton,而是prototype原型模式
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
ObjectprototypeInstance=null;
try {
beforePrototypeCreation(beanName);
prototypeInstance= createBean(beanName,mbd,args);
}
finally {
afterPrototypeCreation(beanName);
}
bean =getObjectForBeanInstance(prototypeInstance,name,beanName,mbd);
}
//其他bean的获取,这里是指定scope的上面实例化bean
else {
StringscopeName=mbd.getScope();
final Scopescope = this.scopes.get(scopeName);
if (scope ==null) {
thrownew IllegalStateException("No Scope registered for scope '" +scopeName+ "'");
}
try {
ObjectscopedInstance=scope.get(beanName,newObjectFactory<Object>() {
public Object getObject()throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName,mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean =getObjectForBeanInstance(scopedInstance,name,beanName,mbd);
}
catch (IllegalStateExceptionex) {
thrownew BeanCreationException(beanName,
"Scope '"+scopeName+ "' is not active for the currentthread; " +
"consider defining a scoped proxy for this bean ifyou intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansExceptionex) {
cleanupAfterBeanCreationFailure(beanName);
throwex;
}
}
//(9)类型转换:检查是否需要type match,和实际bean类型是否符合
if (requiredType !=null&& bean!= null&& !requiredType.isAssignableFrom(bean.getClass())) {
try {
returngetTypeConverter().convertIfNecessary(bean,requiredType);
}
catch (TypeMismatchExceptionex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" +name+ "' to required type [" +
ClassUtils.getQualifiedName(requiredType) +"]", ex);
}
throw newBeanNotOfRequiredTypeException(name,requiredType,bean.getClass());
}
}
return (T)bean;
}
(1)final String beanName = transformedBeanName(name);转换对应beanName,这里因为传入的参数可能是别名alias,也可能是FactoryBean,(指定了创建bean的方法的factorybean,因为spring的对factorybean的实现有许多个)。
---》跳到抽象AbstractBeanFactory
protected StringtransformedBeanName(Stringname){
returncanonicalName(BeanFactoryUtils.transformedBeanName(name));
}
BeanFactoryUtils中对于bean,name等处理的静态方法,
(a1)这里是对于&的处理,貌似是过滤掉,原因是?如name=”&createPet”变成name =”createPet”。
(a2)或者是根据别名alias取得最终的beanName。
(a1):public staticString transformedBeanName(Stringname){
Assert.notNull(name,"'name' must not be null");
StringbeanName= name;
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)){
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
return beanName;
}
(a2):处理别名alias,通过do…while循环获取到如A->B->C,C这样的最终名称。
publicString canonicalName(Stringname) {
StringcanonicalName= name;
// Handle aliasing...
StringresolvedName;
do {
resolvedName =this.aliasMap.get(canonicalName);
if (resolvedName !=null){
canonicalName = resolvedName;
}
}
while (resolvedName !=null);
return canonicalName;
}
(2)单例注册,尝试从缓存中加载单例
Object sharedInstance = getSingleton(beanName);
--》DefaultSingletonBeanRegistry:
public ObjectgetSingleton(StringbeanName){
return getSingleton(beanName,true);
}获得相应的单例对象,
同时调用如下方法,主要是返回一个bean实例,
protected ObjectgetSingleton(String beanName,booleanallowEarlyReference){
ObjectsingletonObject= this.singletonObjects.get(beanName);
if (singletonObject ==null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject ==null && allowEarlyReference){
ObjectFactory<?>singletonFactory=this.singletonFactories.get(beanName);
if (singletonFactory !=null) {
singletonObject =singletonFactory.getObject();
this.earlySingletonObjects.put(beanName,singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject !=NULL_OBJECT ?singletonObject : null);
}
单例在spring的同一个容器中只会被创建一次,后续再获取bean,就直接从单例缓存中获取。当然这里只是尝试加载,首先尝试从缓存中加载,如果加载不成功则再次尝试从singletonFactories中加载。因为在创建单例bean的时候会存在依赖注入的情况,而在创建的时候为了避免循环依赖,在spring中创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光到缓存中,一旦下一个bean创建的时候需要依赖上一个bean则直接使用ObjectFactory。(引用自《spring源码深度解析》)
(3)获得bean实例化对象
如果从缓存中获得了bean的原始状态,还需要对bean进行实例化。缓存中记录的知识最原始的bean状态,并不一定是最终想要的bean。可能它还需要工厂bean中定义的factory-method方法中返回的bean,下面这个方法就是完成这个工作的。
bean =getObjectForBeanInstance(sharedInstance,name,beanName,null);
AbstractBeanFactory:
protected Object getObjectForBeanInstance(
ObjectbeanInstance,Stringname,String beanName,RootBeanDefinitionmbd){
// Don't let calling code try to dereference the factoryif the bean isn't a factory.
//(a)如果bean不是一个factory,则会抛出异常
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstanceinstanceof FactoryBean)) {
throw newBeanIsNotAFactoryException(transformedBeanName(name),beanInstance.getClass());
}
// 现在我们是有了一个bean实例,也可能是一个factorybean.
//如果不是一个factorybean的话,我们可以使用工厂的引用来创建一个bean instance。
if (!(beanInstanceinstanceof FactoryBean) ||BeanFactoryUtils.isFactoryDereference(name)) {
returnbeanInstance;
}
Objectobject= null;
if (mbd ==null) {//从缓存对象中获得factorybean
object =getCachedObjectForFactoryBean(beanName);
}
if (object ==null) {
// Return bean instance from factory.
FactoryBean<?>factory= (FactoryBean<?>)beanInstance;
// Caches object obtained from FactoryBean if it is asingleton.//对于相同beanName的beandefinition进行合并(root child)
if (mbd ==null &&containsBeanDefinition(beanName)) {
mbd =getMergedLocalBeanDefinition(beanName);
}
booleansynthetic = (mbd !=null && mbd.isSynthetic());
object =getObjectFromFactoryBean(factory,beanName,!synthetic);
}
return object;
}
(4) 原型模式的依赖检查
只有在单例情况下才会尝试解决依赖。如果实在原型模式的如果存在依赖的话,则抛出异常。
(5)检测parentBeanFactory
(6)将存储xml配置文件的genericBeanDefintion转换成RootBeanDefinition。
(7)需找依赖
(8)针对不同的scope进行bean的创建
(9)类型装换
下面分别进行讲解:
5.1FactoryBean的使用
Bean的实例化,是通过配置文件提供的class通过反射机制实现的。复杂的bean则需要配置方式也复杂一些。这是采用编码的方式会得到一个简单的解决方案。Spring为此提供了一个org.spingframework.bean.factory.FactoryBean的工厂类接口,用户通过实现该接口定制实例化自己的bean的逻辑。(摘自《spring源码深度分析》)
可以看到该接口中定义的三个方法,
T getObject()返回有FactoryBean创建的bean实例,如果是isSingleton()true,则该实例会放到spring容器中单实例缓冲池中。
Boolean isSingleton()返回有factorybean创建的bean实例的作用域是singleton还是prototype。
Class<T> getObjectType()返回factorybean创建的bean类型。
下面是smartfactorybean接口继承自factorybean接口。
当配置文件中<bean>的class属性配置的实现类是factorybean时,通过getBean()方法返回的不是FactoryBean本身,而是factorybean#getObject()方法返回的对象,相当于factorybean#getObject()代理了getBean()方法。
个人觉得《spring源码深度解析》中那个利用getObject()方法,写的carFactoryBean的例子很好的给我们介绍了一个XXXFactoryBean类的实现,并简单的获取到相应的bean。
该例子:
#class:CarInfo
public classCarInfo {
private Stringname ;
private double price;
private Stringbrand;
public CarInfo(){
}
public CarInfo(Stringname,doubleprice,String brand){
this.name =name;
this.price =price;
this.brand =brand;
}
//get set method
……
}
#class:CarFactoryBean
public classCarFactoryBean implementsFactoryBean<CarInfo> {
private StringcarMessage;
@Override
public CarInfo getObject()throws Exception {
// TODO Auto-generated method stub
CarInfocar= newCarInfo();
String[] message= carMessage.split(",");
car.setBrand(message[0]);
car.setName(message[1]);
car.setPrice(Double.parseDouble(message[2]));
return car;
}
@Override
public Class<CarInfo>getObjectType() {
// TODO Auto-generated method stub
return CarInfo.class;
}
@Override
public boolean isSingleton() {
// TODO Auto-generated method stub
return false;
}
public String getCarMessage(){
return carMessage;
}
public void setCarMessage(String carMessage) {
this.carMessage =carMessage;
}
}
配置文件中:
<beanid="carFactoryBean"class="com.springframework.samples.jpetstore.myfactorybean.CarFactoryBean">
<propertyname="carMessage"value ="dazhong,sangtna2000,20.2"/>
</bean>
#test:
BeanFactory bf = newXmlBeanFactory(new ClassPathResource("spring-config.xml"));
CarInfo car = (CarInfo)bf.getBean("carFactoryBean");
System.out.println("Brand:"+car.getBrand()+" ,Name: "+car.getName()+",Price: "+car.getPrice());
CarFactoryBean carFactoryBean = (CarFactoryBean)bf.getBean("&carFactoryBean");
System.out.println(carFactoryBean.getCarMessage());
该xxxFactoryBean的getObject()方法只是模拟给出一个类似的bean。
5.2缓存中获取单例bean
下面介绍bean的加载,前面已经提到过单例在spring的同一容器中只会被创建一次,后续再获得bean直接从单例缓存中获得。当然这也是尝试加载,首先尝试从缓存中加载,然后再次尝试从singletonFactories中加载。因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,spring创建bean的原则是不等bean创建完成就会将bean的objectFactory提早曝光加入到缓存中,一旦下一个bean创建时需要依赖上个bean,则世界使用ObjectFactory.
Object sharedInstance = getSingleton(beanName);
--》DefaultSingletonBeanRegistry:
public ObjectgetSingleton(StringbeanName){
//true参数允许早期依赖
return getSingleton(beanName,true);
}获得相应的单例对象,
同时调用如下方法,主要是返回一个bean实例,----》
protected ObjectgetSingleton(String beanName,booleanallowEarlyReference){
//检查缓存中是否存在实例
ObjectsingletonObject= this.singletonObjects.get(beanName);
//如果为空则锁定全局变量进行处理
if (singletonObject ==null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//如果此bean正在加载则不处理
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject ==null && allowEarlyReference){
//当某些方法需要提前初始化的时候则会调用addSingletonFactory方法将对应的ObjectFactory初始化策略储存在singletonFactories中
ObjectFactory<?>singletonFactory=this.singletonFactories.get(beanName);
if (singletonFactory !=null) {
singletonObject =singletonFactory.getObject();
this.earlySingletonObjects.put(beanName,singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject !=NULL_OBJECT ?singletonObject : null);
}
首先从singletonObjects中获取,如果不成功,则利用尝试从earlySingletonObjects中获取,如果仍然不成功,则从singletonFactories中获取singletonFactory,调用该beanName的ObjectFactory再通过方法getObject()获得object对象(即创建bean),并放到earlySingletonObjects中,并且从singletonFactories中remove掉该ObjectFacotry。
这里几个map集合:
singletonObjects:用于保存BEANName和创建bean实例之间的关系,beanname------beaninstance
singletonFactories :用于保存beanName和创建bean的工厂之间的关系
earlySingletonObjects:保存beanName和创建bean实例之间的关系,与singletonObjects的不同之处是它可以在bean还在创建过程中,就可以通过getBean()方法或得到。
5.3获得实例化bean对象:
在getBean方法中,getObejctForBeanInstance是个高频了的使用的方法,可以从代码中看到从缓存中获取bean,还是根据不同的scope策略来加载bean。
从得到bean实例后要做的是调用该方法验证一下其正确性与否,检测当前bean是否是factorybean类型的bean,还是普通的bean。如果类型时factorybean,需要调用该bean对应的factorybean实例中的getObject()方法作为得到bean返回值。
同时得到的bean,是原始的,有些需要进行加工处理。真正需要的有时是factorybean中定义的factory-method方法返回的bean,而getObejctForBeanInstance方法就是完成这个操作的。
其中的内容是:bean =getObjectForBeanInstance(sharedInstance,name,beanName,null);
AbstractBeanFactory:
protected Object getObjectForBeanInstance(
ObjectbeanInstance,Stringname,String beanName,RootBeanDefinitionmbd){
//(a)如果bean不是一个factorybean类型,且指定的那么是工厂相关(以&前缀),则会抛出异常
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstanceinstanceof FactoryBean)) {
throw newBeanIsNotAFactoryException(transformedBeanName(name),beanInstance.getClass());
}
// 现在我们是有了一个bean实例,也可能是一个factorybean.
//如果不是一个factorybean的话,我们可以使用工厂的引用来创建一个bean instance。但是如果用户想要获得相应的factorybean实例问不是工厂的getObject方法对应的实例,那么可以传入的name应该是加入了前缀&的.
if (!(beanInstanceinstanceof FactoryBean) ||BeanFactoryUtils.isFactoryDereference(name)) {
returnbeanInstance;
}
Objectobject= null;
if (mbd ==null) {//从缓存对象中获得factorybean
object =getCachedObjectForFactoryBean(beanName);
}
if (object ==null) {
// Return bean instance from factory.
FactoryBean<?>factory= (FactoryBean<?>)beanInstance;
// Caches object obtained from FactoryBean if it is asingleton.//对于相同beanName的beandefinition进行合并(root child)
if (mbd ==null &&containsBeanDefinition(beanName)) {
//将存储xml配置文件的GenericBeanDefinition装换为RootBeanDefinition,如果指定beanName是子bean的话同时会合并父类的相关属性
mbd =getMergedLocalBeanDefinition(beanName);
}
//是否是用户定义的
booleansynthetic = (mbd !=null && mbd.isSynthetic());
object =getObjectFromFactoryBean(factory,beanName,!synthetic);
}
return object;
}
其核心的代码则是 object= getObjectFromFactoryBean(factory,beanName,!synthetic);
FactoryBeanRegistrySupport:getObjectFromFactoryBean
protected ObjectgetObjectFromFactoryBean(FactoryBean<?>factory,StringbeanName,booleanshouldPostProcess){
//如果是单例模式,则使用缓存中的beanName
if (factory.isSingleton()&& containsSingleton(beanName)) {
synchronized(getSingletonMutex()) {
Objectobject= this.factoryBeanObjectCache.get(beanName);
if (object ==null) {
object =doGetObjectFromFactoryBean(factory,beanName);
// Only post-process and store if not put there alreadyduring getObject() call above
// (e.g. because of circular reference processingtriggered by custom getBean calls)
ObjectalreadyThere=this.factoryBeanObjectCache.get(beanName);
if (alreadyThere !=null) {
object = alreadyThere;
}
else {
if (object !=null && shouldPostProcess){
try {
object =postProcessObjectFromFactoryBean(object,beanName);
}
catch (Throwableex) {
thrownew BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton objectfailed",ex);
}
}
this.factoryBeanObjectCache.put(beanName, (object !=null ? object : NULL_OBJECT));
}
}
return (object !=NULL_OBJECT? object: null);
}
}
else {
Objectobject= doGetObjectFromFactoryBean(factory,beanName);
if (object !=null && shouldPostProcess){
try {
object =postProcessObjectFromFactoryBean(object,beanName);
}
catch (Throwableex) {
throw new BeanCreationException(beanName,"Post-processing of FactoryBean's objectfailed",ex);
}
}
returnobject;
}
}
真正的方法在doGetObjectFromFactoryBean()中:
private ObjectdoGetObjectFromFactoryBean(final FactoryBean<?>factory, final StringbeanName)
throws BeanCreationException {
Objectobject;
try {//权限验证
if (System.getSecurityManager()!=null){
AccessControlContextacc= getAccessControlContext();
try {
object = AccessController.doPrivileged(newPrivilegedExceptionAction<Object>() {
public Object run()throws Exception {
returnfactory.getObject();
}
},acc);
}
catch(PrivilegedActionExceptionpae) {
throwpae.getException();
}
}
else {
object = factory.getObject();
}
}
catch(FactoryBeanNotInitializedExceptionex) {
throw newBeanCurrentlyInCreationException(beanName,ex.toString());
}
catch (Throwableex) {
throw new BeanCreationException(beanName,"FactoryBean threw exception on objectcreation",ex);
}
// Do not accept a null value for a FactoryBean that'snot fully
// initialized yet: Many FactoryBeans just return nullthen.
if (object ==null &&isSingletonCurrentlyInCreation(beanName)) {
throw newBeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returnednull from getObject");
}
return object;
}
其中factory.getObject()就是我们想要的,工厂中得到了对象。
其实在doGetObjectFromFactoryBean()之后,得到了object之后,进行了一下后处理:postProcessObjectFromFactoryBean
Objectobject= doGetObjectFromFactoryBean(factory,beanName);
if (object !=null && shouldPostProcess){
try {
object =postProcessObjectFromFactoryBean(object,beanName);
跟踪来到
AbstractAutowireCapableBeanFactory:
protected ObjectpostProcessObjectFromFactoryBean(Objectobject,StringbeanName){
returnapplyBeanPostProcessorsAfterInitialization(object,beanName);
}
其中方法:
public ObjectapplyBeanPostProcessorsAfterInitialization(ObjectexistingBean,StringbeanName)
throws BeansException {
Objectresult= existingBean;
for (BeanPostProcessorbeanProcessor :getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result,beanName);
if (result ==null) {
returnresult;
}
}
return result;
}
先到此。Spring中获取bean的规则:尽可能保证所有bean初始化后都会调用注册的BEANPostProcessor的postProcessAfterInitialization进行处理。
其实到这里还是有些晕晕的,获得bean,不是获得了吗?之前应该是从已经存在缓存中获取的bean,或者是尝试使用factorybean,有些时候说的bean,可能是相应的xxxFactoryBean,可以通过其ObjectFactory的getObject获得对象bean。这里只讲了对于(1)beanName的处理;(2)从缓存中加载bean,此时bean的状态时初始的,还需要进一步处理;(3)对于bean的进一步处理,经由xxxObjectFactory的getObject方法返回特定处理的bean。-----------------------------------未完待续2
- spring中bean的加载1
- spring中bean的加载
- Spring中bean的加载过程
- spring bean的加载
- spring的bean加载
- spring的bean加载2
- Spring bean的延迟加载
- spring bean的加载过程
- Spring Bean 的加载顺序
- Spring bean的加载过程
- spring加载bean的过程
- 【spring bean】spring中bean的懒加载和depends-on属性设置
- spring源码学习(六)Bean的加载(中)
- Dubbo中Bean的加载-1-ServiceBean
- Spring源码之bean的加载(三)从bean中获取对象
- spring bean加载--从缓存中获取bean
- spring bean加载--从缓存中获取bean
- spring bean加载--从缓存中获取beanspring bean加载--从缓存中获取bean【转】
- sicily 1211. 商人的宣传
- duilib 自定义控件1 CTileLayoutUI
- c# 把网络文件下载到本地
- Codevs P3372 选学霸
- YARN内存使用优化配置
- spring中bean的加载1
- duilib 自定义控件TeamList 继承与CListUI
- usaco Computational Geometry 计算几何
- (三)seajs中的模块标识
- 小小君的C语言第十课
- Linux file 命令 【转载】
- ANDROID仿淘宝商品浏览滑(拖)动查看详情界面
- centOS 安装 pomelo
- leetcode Combinations