Spring之根据BeanDefinition创建Bean

前面已经说明白了所有的BeanDefinition的扫描过程以及配置类的代理过程之后,下面就给对所有的BeanDefinition进行实例化了。

那么如何来进行实例化阶段的呢

从方法注释上来看,是实例化所有的非懒加载的单例bean。那么直接来到org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

这里主要分成了两个大的步骤:

一、循环遍历并创建非懒加载的单例bean;

二、所有的非懒加载的单例bean创建完成之后,执行单例实例化之后的方法;

二、创建非懒加载的单例Bean

// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
    RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
        if (isFactoryBean(beanName)) {
            Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
            if (bean instanceof FactoryBean) {
                FactoryBean<?> factory = (FactoryBean<?>) bean;
                boolean isEagerInit;
                if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                    isEagerInit = AccessController.doPrivileged(
                        (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
                        getAccessControlContext());
                }
                else {
                    isEagerInit = (factory instanceof SmartFactoryBean &&
                                   ((SmartFactoryBean<?>) factory).isEagerInit());
                }
                if (isEagerInit) {
                    getBean(beanName);
                }
            }
        }
        else {
            getBean(beanName);
        }
    }
}

2.1、合并BeanDefinition的意义

是否还记得前面讲过的抽象父BeanDefinition和具体的子BeanDefinition,这里就有了具体的体现。

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(AppConfig.class);

        GenericBeanDefinition parentGenericBeanDefinition  = new GenericBeanDefinition();
        parentGenericBeanDefinition.setInitMethodName("init");
        parentGenericBeanDefinition.setLazyInit(false);
        parentGenericBeanDefinition.setPrimary(true);
        parentGenericBeanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
        parentGenericBeanDefinition.setDestroyMethodName("destroy");

        parentGenericBeanDefinition.setAbstract(true);

        applicationContext.registerBeanDefinition("parent",parentGenericBeanDefinition);


        GenericBeanDefinition aGenericBeanDefinition  = new GenericBeanDefinition();
        aGenericBeanDefinition.setBeanClass(A.class);
        aGenericBeanDefinition.setParentName("parent");
        applicationContext.registerBeanDefinition("a",aGenericBeanDefinition);

        GenericBeanDefinition bGenericBeanDefinition  = new GenericBeanDefinition();
        bGenericBeanDefinition.setBeanClass(B.class);
        bGenericBeanDefinition.setParentName("parent");
        applicationContext.registerBeanDefinition("b",bGenericBeanDefinition);

        applicationContext.refresh();

        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println("bean的名称是:"+beanDefinitionName);
        }
    }
}

因为是两个beanName叫parent和b的BeanDefinition,但是因为存在着抽象的BeanDefinition,无法创建出来Bean,所以首先需要将抽象BeanDefinition给筛选掉,其次因为父子BeanDefinition中存在着继承关系,所以需要将子BeanDefinition继承父BeanDefinition中的属性设置到子BeanDefinition中来,而这里的合并BeanDefinition就是为了来实现这样的逻辑。

对于合并了的bean来说,会放入到mergedBeanDefinitions集合中来,而后续的操作就是围绕着mergedBeanDefinitions来进行操作了。

2.2、单例bean

只有单例的BeanDefinition才会在这个阶段中称为候选的bean

2.3、非懒加载

懒加载强调的是在某一个过程之后进行加载,而非懒加载强调的是开始阶段就要来进行创建。

2.4、源代码

三、FactoryBean

3.1、官方解释

看看官方对FactoryBean类的解释

/**
 * Interface to be implemented by objects used within a {@link BeanFactory} which
 * are themselves factories for individual objects. If a bean implements this
 * interface, it is used as a factory for an object to expose, not directly as a
 * bean instance that will be exposed itself.
 *
 * <p><b>NB: A bean that implements this interface cannot be used as a normal bean.</b>
 * A FactoryBean is defined in a bean style, but the object exposed for bean
 * references ({@link #getObject()}) is always the object that it creates.
 *
 * <p>FactoryBeans can support singletons and prototypes, and can either create
 * objects lazily on demand or eagerly on startup. The {@link SmartFactoryBean}
 * interface allows for exposing more fine-grained behavioral metadata.
 *
 * <p>This interface is heavily used within the framework itself, for example for
 * the AOP {@link org.springframework.aop.framework.ProxyFactoryBean} or the
 * {@link org.springframework.jndi.JndiObjectFactoryBean}. It can be used for
 * custom components as well; however, this is only common for infrastructure code.
 *
 * <p><b>{@code FactoryBean} is a programmatic contract. Implementations are not
 * supposed to rely on annotation-driven injection or other reflective facilities.</b>
 * {@link #getObjectType()} {@link #getObject()} invocations may arrive early in the
 * bootstrap process, even ahead of any post-processor setup. If you need access to
 * other beans, implement {@link BeanFactoryAware} and obtain them programmatically.
 *
 * <p><b>The container is only responsible for managing the lifecycle of the FactoryBean
 * instance, not the lifecycle of the objects created by the FactoryBean.</b> Therefore,
 * a destroy method on an exposed bean object (such as {@link java.io.Closeable#close()}
 * will <i>not</i> be called automatically. Instead, a FactoryBean should implement
 * {@link DisposableBean} and delegate any such close call to the underlying object.
 *
 * <p>Finally, FactoryBean objects participate in the containing BeanFactory's
 * synchronization of bean creation. There is usually no need for internal
 * synchronization other than for purposes of lazy initialization within the
 * FactoryBean itself (or the like).
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 08.03.2003
 * @param <T> the bean type
 * @see org.springframework.beans.factory.BeanFactory
 * @see org.springframework.aop.framework.ProxyFactoryBean
 * @see org.springframework.jndi.JndiObjectFactoryBean
 */

可以得到以下信息:

  • 1、FactoryBean是一个创建bean的工厂;
  • 2、如果一个类是实现了FactoryBean接口,那么利用接口中的getObject()方法来创建bean;
  • 3、FactoryBean是spring中具有特殊意义的一个类;

3.2、作用

那么怎么特殊呢?利用这个类可以获取得到两个Bean

3.3、示例代码

示例代码:

public class AService {}
@Component
public class MyFactoryBean implements FactoryBean<AService> {
    @Override
    public AService getObject() throws Exception {
        return new AService();
    }
    @Override
    public Class<?> getObjectType() {
        return AService.class;
    }
}

对应的测试代码:

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(AppConfig.class);
applicationContext.refresh();
System.out.println(applicationContext.getBean("myFactoryBean"));
System.out.println(applicationContext.getBean("&myFactoryBean"));

打印效果如下所示:

com.guang.spring.service.AService@2eda0940
com.guang.spring.factorybean.MyFactoryBean@3578436e

从上面的测试代码中可以知道,传递的bean的名称不同,得到的bean也是不同的。

加了&的符号的,获取得到的是MyFactoryBean类型的;而没有加&的是getObejct返回的类型。

所以既然有两种名称,而对于getBean方法来说,是公共的方法,所以spring也应该提供对两个不同名称的bean进行解析判断

3.4、SmartFactoryBean

public interface SmartFactoryBean<T> extends FactoryBean<T> {
    
    default boolean isPrototype() {
		return false;
	}
    
    default boolean isEagerInit() {
		return false;
	}

是FactoryBean的拓展接口,为了能够提前实例化FactoryBean对应的getObject()方法对应的bean提前实例化。

四、SmartInitializingSingleton

在所有的单例的非懒加载的bean完成完整的生命周期后,调用实现SmartInitializingSingleton接口的bean的初始化完成方法。

posted @ 2023-01-08 19:10  雩娄的木子  阅读(159)  评论(0编辑  收藏  举报