一起来读官方文档-----SpringIOC(06)

1.6。自定义bean的性质

Spring框架提供了许多接口,可用于自定义Bean的性质。本节将它们分组如下:

  • 生命周期回调Lifecycle Callbacks
  • ApplicationContextAware 和 BeanNameAware
  • 其他Aware
1.6.1。生命周期回调

为了与参与容器对bean生命周期的管理,您可以实现Spring 的InitializingBean和DisposableBean接口。
容器初始化会调用 afterPropertiesSet()方法和销毁会调用destroy()方法来执行某些操作。

通常,@PostConstruct和@PreDestroy注解被认为是在Spring应用程序中接收生命周期回调的最佳实践。
使用这些注解意味着您的bean没有耦合到特定于Spring的接口。

如果你不希望使用JSR-250注解,但你仍然要删除的耦合,考虑init-method和destroy-methodbean定义元数据。


public class InitAndDestroyBean implements InitializingBean, DisposableBean {
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean destroy");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean init" );
    }

    @PostConstruct
    public void init(){
        System.out.println("PostConstruct init");
    }

    @PreDestroy
    public void destroy2(){
        System.out.println("PreDestroy destroy");
    }

    public void initMethod(){
        System.out.println("Init-method init");
    }

    public void destroyMethod(){
        System.out.println("Destroy-method destroy");
    }
}


    <bean id="initAndDestroyBean" class="org.springframework.example.lifecycle.InitAndDestroyBean"
    init-method="initMethod" destroy-method="destroyMethod">

控制台打印:
    PostConstruct init
    InitializingBean init
    Init-method init
    .
    .
    .
    PreDestroy destroy
    DisposableBean destroy
    Destroy-method destroy

在内部,Spring框架使用BeanPostProcessor实现来处理它可以找到的任何回调接口并调用适当的方法。如果您需要自定义功能或其他Spring默认不提供生命周期行为,则您可以BeanPostProcessor自己实现。

除了初始化和销毁回调之外,spring管理的对象还可以实现Lifecycle 接口,以便这些对象可以参与启动和关闭过程,这是由容器自己的生命周期驱动的。

上述的Lifecycle类上有这么一个注释
 * <p>Note that the present {@code Lifecycle} interface is only supported on
 * <b>top-level singleton beans</b>. On any other component, the {@code Lifecycle}
 * interface will remain undetected and hence ignored. Also, note that the extended
 * {@link SmartLifecycle} interface provides sophisticated integration with the
 * application context's startup and shutdown phases.

 一开始看没看懂top-level singleton beans的含义自己试了一下实现Lifecycle
 @Component
 public class CustomLifecycle implements Lifecycle {
    @Override
    public void start() {
        System.out.println("start-----------");
    }

    @Override
    public void stop() {
        System.out.println("stop-----------");
    }
    @Override
    public boolean isRunning() {
        return false;
    }
}

控制台输出
PostConstruct init
InitializingBean init
Init-method init
PreDestroy destroy
DisposableBean destroy
Destroy-method destroy

这些代码并没有起作用
调试了源码发现在启动关闭容器的时候,容器确实找到Lifecycle的所有实现类但是还有一个if操作
if (bean instanceof SmartLifecycle) {
    .
    .
    .
}
更改了继承关系
@Component
public class CustomSmartLifecycle implements SmartLifecycle {
    @Override
    public void start() {
        System.out.println("start-----------");
    }

    @Override
    public void stop() {
        System.out.println("stop-----------");
    }
    @Override
    public boolean isRunning() {
        return false;
    }
}

控制台输出
PostConstruct init
InitializingBean init
Init-method init
start-----------
PreDestroy destroy
DisposableBean destroy
Destroy-method destroy

这才稍微理解那段注释,意思大概就是如果你直接继承自Lifecycle接口,
那么容器不会调用你的自定义接口,只有继承SmartLifecycle才行
本节介绍了生命周期回调接口。
初始化回调

org.springframework.beans.factory.InitializingBean接口允许容器在bean上设置了所有必要的属性之后执行初始化工作。

InitializingBean接口指定了一个方法:

void afterPropertiesSet() throws Exception;

我们建议您不要使用该InitializingBean接口,因为它将您的代码耦合到Spring。
另外,我们建议使用@PostConstruct注释或指定POJO初始化方法。
对于基于XML的配置元数据,可以使用init-method属性指定具有无效无参数签名的方法的名称。
通过Java配置,您可以使用的initMethod属性@Bean。

请参阅接收生命周期回调。考虑以下示例:


public class ExampleBean {
        public void init() {
            // do some initialization work
        }
}
您可以使用xml
    <bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
或者JAVA Bean配置
    @Bean(initMethod = "init")
    public void exampleBean(){
        return new ExampleBean();
    }

前面的示例与下面的示例几乎具有完全相同的效果:

<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>

public class AnotherExampleBean implements InitializingBean {

    @Override
    public void afterPropertiesSet() {
        // do some initialization work
    }
}

但是,前面两个示例中的第一个示例并未将代码耦合到Spring。

销毁回调

org.springframework.beans.factory.DisposableBean当包含该接口的容器被销毁时,实现该接口可使Bean获得回调。

该DisposableBean接口指定一个方法:

void destroy() throws Exception;

我们建议您不要使用DisposableBean回调接口,因为它将您的代码耦合到Spring。
另外,我们建议使用@PreDestroy注释或指定bean定义支持的通用方法。
使用基于XML的配置元数据时,您可以在destroy-method上使用属性 。 通过Java配置,您可以使用的destroyMethod属性@Bean。
考虑以下定义:

public class ExampleBean {
    public void cleanup() {
        // do some destruction work (like releasing pooled connections)
    }
}

您可以使用xml
    <bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>

或者JAVA Bean配置
    @Bean(destroyMethod = "cleanup")
    public void exampleBean(){
        return new ExampleBean();
    }

前面的定义与下面的定义几乎具有完全相同的效果:

<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>

public class AnotherExampleBean implements DisposableBean {
    @Override
    public void destroy() {
        // do some destruction work (like releasing pooled connections)
    }
}

但是,前面两个定义中的第一个没有将代码耦合到Spring。

您可以为<bean>元素的destroy-method属性指定一个特殊的(inferred)值,
该值指示Spring自动检测特定bean类上的公共close 或shutdown 方法(任何实现java.lang.AutoCloseable or java.io.Closeable也会匹配)。

@Component
public class CustomAutoCloseable implements AutoCloseable {
    @Override
    public void close() {
        System.out.println("AutoCloseable close");
    }
}

@Component
public class CustomCloseable implements Closeable {
    @Override
    public void close()  {
        System.out.println("Closeable close");
    }
}

控制台输出:
    Closeable close
    AutoCloseable close

您还可以在<beans>元素的default-destroy-method属性上设置这个特殊的(inferred)值,
以便将此行为应用于整个bean集合。
<beans default-destroy-method="destroy" default-init-method="init"></beans>
默认初始化和销毁方法

当您编写初始化和销毁没有使用特定的spring的InitializingBean和DisposableBean回调接口的特定方法时,
您通常编写具有init()、initialize()、dispose()等名称的方法。
理想情况下,这种生命周期回调方法的名称在整个项目中标准化,
以便所有开发人员使用相同的方法名称并确保一致性。

您可以配置Spring容器来“查找”已命名的初始化,并销毁每个bean上的回调方法名称。
这意味着,作为应用程序开发人员,您可以编写应用程序类并使用名为init()的初始化回调,而不必为每个bean定义配置init-method="init"属性。
Spring IoC容器在创建bean时调用该方法(并且与前面描述的标准生命周期回调契约一致)。该特性还强制对初始化和销毁方法回调执行一致的命名约定。

假设您的初始化回调方法名为init(),而销毁回调方法名为destroy()。然后,您的类就像下面示例中的类:

public class DefaultBlogService implements BlogService {

    private BlogDao blogDao;

    public void setBlogDao(BlogDao blogDao) {
        this.blogDao = blogDao;
    }

    // this is (unsurprisingly) the initialization callback method
    public void init() {
        if (this.blogDao == null) {
            throw new IllegalStateException("The [blogDao] property must be set.");
        }
    }
}

然后,您可以在类似于以下内容的Bean中使用该类:

<beans default-init-method="init">
    <bean id="blogService" class="com.something.DefaultBlogService">
        <property name="blogDao" ref="blogDao" />
    </bean>
</beans>

在顶级 元素属性中出现的default-init-method属性会导致Spring IoC容器识别bean类中名为init的方法作为初始化方法回调。
在创建和组装bean时,如果bean类有这样的方法,则会在适当的时候调用它。

您可以使用顶级 元素上的default-destroy-method属性来配置销毁方法回调(也就是在XML中)。

如果现有的bean类已经有了根据约定命名的回调方法,那么您可以通过使用 本身的init-method和destroy-method属性来指定(在XML中,也就是)方法名来覆盖默认值。

Spring容器保证在为bean提供所有依赖项后立即调用已配置的初始化回调。  
因此,初始化回调是在原始bean引用上调用的,这意味着AOP拦截器等还没有应用到bean。  
所以AOP执行顺序是先创建一个目标bean,然后再应用一个带有拦截器链的AOP代理(例如)。 
因此,将拦截器应用到init方法是不适用的。
组合生命周期机制

从Spring 2.5开始,您可以使用三个选项来控制Bean生命周期行为:

  • InitializingBean和 DisposableBean回调接口
  • 自定义init()和destroy()方法
  • 在@PostConstruct和@PreDestroy 注释。 您可以结合使用这些机制来控制给定的bean。

如果为一个bean配置了多个生命周期机制,并且为每个机制配置了不同的方法名称,则每个配置的方法都将按照此注释后列出的顺序运行。
但是,如果init()同时带有@PostConstruct注解和xml的init-method方法,那么这个init()方法就会被执行一次。

使用不同的初始化方法,为同一个bean配置的多个生命周期机制如下所示: 初始化方法的调用顺序:

  • 用注释的方法 @PostConstruct
  • afterPropertiesSet()由InitializingBean回调接口定义
  • 定制配置的init()方法

销毁方法的调用顺序相同:

  • 用注释的方法 @PreDestroy
  • destroy()由DisposableBean回调接口定义
  • 定制配置的destroy()方法
启动和关机回调

该Lifecycle接口为具有生命周期要求(例如启动和停止某些后台进程)的任何对象定义了基本方法:

public interface Lifecycle {
    void start();
    void stop();
    boolean isRunning();
}

任何Spring管理的对象都可以实现该Lifecycle接口。
然后,当 ApplicationContext自身接收到启动和停止信号时(例如,对于运行时的停止/重新启动场景),它将这些调用层叠到Lifecycle该上下文中定义的所有实现中。
它通过委派给LifecycleProcessor,如下面的清单所示:

public interface LifecycleProcessor extends Lifecycle {
    void onRefresh();
    void onClose();
}

请注意,LifecycleProcessor本身是Lifecycle 接口的扩展。它还添加了两种其他方法来响应正在刷新和关闭的上下文。

请注意,常规org.springframework.context.Lifecycle接口是用于显式启动和停止通知的普通协议,并不意味着在上下文刷新时自动启动。为了对特定bean的自动启动进行精细控制(包括启动阶段),请考虑实施org.springframework.context.SmartLifecycle。

另外,请注意,不能保证会在销毁之前发出停止通知。在常规关闭时,Lifecycle在传播常规销毁回调之前,所有Bean首先都会收到停止通知。但是,在上下文生命周期中进行热刷新或停止刷新尝试时,仅调用destroy方法。

启动和关闭调用的顺序可能很重要。
如果任何两个对象之间存在“依赖”关系,则依赖方在其依赖之后开始,而在依赖之前停止。
但是,有时直接依赖项是未知的。
您可能只知道某种类型的对象应该先于另一种类型的对象开始。
在这些情况下,SmartLifecycle接口定义了另一个选项,即在其接口Phased上定义的getPhase()方法。 以下清单显示了Phased接口的定义:

public interface Phased {
    int getPhase();
}

以下清单显示了SmartLifecycle接口的定义:

public interface SmartLifecycle extends Lifecycle, Phased {

    boolean isAutoStartup();
    void stop(Runnable callback);
}

启动时,相位最低的对象首先启动。
停止时,遵循相反的顺序。
因此,实现SmartLifecycle并getPhase()返回其方法的对象Integer.MIN_VALUE将是第一个开始且最后一个停止的对象。
在频谱的另一端,相位值Integer.MAX_VALUE表示该对象应最后启动并首先停止(可能因为该对象取决于正在运行的其他进程)。
当考虑相位值,同样重要的是要知道,对于任何“正常”的默认阶段 Lifecycle目标没有实现SmartLifecycle的0。
因此,任何负相位值都表明对象应在这些标准组件之前开始(并在它们之后停止)。对于任何正相位值,反之亦然。

SmartLifecycle的stop方法接受Runnable callback作为方法入参。

    default void stop(Runnable callback) {
        stop();
        callback.run();
    }

在该stop()的子类的实现执行完成之后,调用该callback.run()的方法。

由于LifecycleProcessor接口的默认实现DefaultLifecycleProcessor会在每个阶段内的对象组等待其超时值,以调用该回调,因此可以在必要时启用异步关闭。

默认的每阶段超时为30秒。
您可以通过定义lifecycleProcessor上下文中命名的bean来覆盖默认的生命周期处理器实例 。
如果只想修改超时,则定义以下内容即可:

<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
    <!-- timeout value in milliseconds -->
    <property name="timeoutPerShutdownPhase" value="10000"/>
</bean>

正如前面提到的,LifecycleProcessor接口还定义了刷新和关闭上下文的回调方法。
后者驱动关闭过程,就好像是显式地调用了stop(),但是它发生在上下文关闭时。
另一方面,“刷新”回调可以实现SmartLifecycle bean的另一个特性。
当上下文被刷新时(在所有对象被实例化和初始化之后),回调被调用。
这时,默认的生命周期处理器会检查每个SmartLifecycle对象的isAutoStartup()方法返回的布尔值。
如果为真,则在该点启动该对象,而不是等待上下文或其自己的start()方法的显式调用(与上下文刷新不同,对于标准上下文实现,上下文启动不会自动发生)。
如上所述,相位值和任何“依赖”关系决定启动顺序。

    Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
        Map<Integer, LifecycleGroup> phases = new HashMap<>();
        lifecycleBeans.forEach((beanName, bean) -> {
            //DefaultLifecycleProcessor 调用该方法autoStartupOnly始终未true
            //如果bean  instanceof SmartLifecycle 并且isAutoStartup()方法返回true
            if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
                int phase = getPhase(bean);
                LifecycleGroup group = phases.get(phase);
                if (group == null) {
                    group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
                    phases.put(phase, group);
                }
                group.add(beanName, bean);
            }
        });
        if (!phases.isEmpty()) {
            List<Integer> keys = new ArrayList<>(phases.keySet());
            Collections.sort(keys);
            for (Integer key : keys) {
                phases.get(key).start();
            }
        }
    }
在非Web应用程序中正常关闭Spring IoC容器

本节仅适用于非Web应用程序。
Spring的基于Web的 ApplicationContext实现已经有了相应的代码,可以在相关Web应用程序关闭时正常关闭Spring IoC容器。

如果您在非web应用程序环境中(例如,在富客户机桌面环境中)使用Spring的IoC容器,请向JVM注册一个关机钩子。
这样做可以确保优雅地关闭,并调用单例bean上的相关销毁方法,从而释放所有资源。
您仍然必须正确配置和实现这些销毁回调。

要注册一个关机钩子,调用registerShutdownHook()方法,该方法在ConfigurableApplicationContext接口上声明,如下面的例子所示:

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public final class Boot {

    public static void main(final String[] args) throws Exception {
        ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");

        // add a shutdown hook for the above context...
        ctx.registerShutdownHook();

        // app runs here...

        // main method exits, hook is called prior to the app shutting down...
    }
}
1.6.2。ApplicationContextAware和BeanNameAware

当ApplicationContext创建一个实现org.springframework.context.ApplicationContextAware的对象实例时,该实例提供对ApplicationContext的引用。下面的清单显示了applicationcontext taware接口的定义:

public interface ApplicationContextAware {
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

因此,bean可以通过ApplicationContext接口或通过将引用转换为该接口的已知子类(比如ConfigurableApplicationContext,它公开了其他功能),以编程方式操作创建它们的ApplicationContext。
一种用途是对其他bean进行编程检索。
有时这个功能是有用的。
但是,通常应该避免使用它,因为它将代码与Spring结合在一起,并且不遵循控制反转风格,在这种风格中协作者作为属性提供给bean。
ApplicationContext的其他方法提供了对文件资源的访问、发布应用程序事件和访问消息源。
这些附加特性在ApplicationContext的附加功能中进行了描述。

自动装配是获得对ApplicationContext的引用的另一种选择。
传统的constructor和byType自动装配模式可以分别为构造函数参数或setter方法参数提供类型ApplicationContext的依赖关系。

为了获得更大的灵活性,包括自动装配字段和多个参数方法的能力,可以使用基于注解的自动装配特性。如果你这样做了,ApplicationContext就会自动生成一个字段、构造函数参数或方法参数,如果有问题的字段、构造函数或方法带有@Autowired注解,那么这些参数期望得到ApplicationContext类型。

说了半天不如看代码:
public class CustomAutowiringApplicationContext {
    @Autowired
    private ApplicationContext applicationContext;

    public CustomAutowiringApplicationContext(ApplicationContext applicationContext){
        System.out.println(applicationContext);
    }

    public void setApplicationContext(ApplicationContext applicationContext){
        System.out.println(applicationContext);
    }
}
//只有配置byType 或者 byName set注入才会生效
<bean id="customAutowiringApplicationContext"
          autowire="byType"
          class="org.springframework.example.applicationcontext.CustomAutowiringApplicationContext"/>

当ApplicationContext创建一个实现org.springframework.beans.factory.BeanNameAware的类时。BeanNameAware接口,提供当前bean的名称的引用。下面的清单显示了BeanNameAware接口的定义:

public interface BeanNameAware {
    void setBeanName(String name) throws BeansException;
}

源码:
    private void invokeAwareMethods(String beanName, Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware) bean).setBeanName(beanName);
            }
            if (bean instanceof BeanClassLoaderAware) {
                ClassLoader bcl = getBeanClassLoader();
                if (bcl != null) {
                    ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
                }
            }
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
            }
        }
    }
执行顺序源码:
    if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                //处理aware 如上方法
                invokeAwareMethods(beanName, bean);
                return null;
            }, getAccessControlContext());
        }
        else {
            invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            //执行初始化方法如InitializingBean、afterPropertiesSet或自定义init-method
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    (mbd != null ? mbd.getResourceDescription() : null),
                    beanName, "Invocation of init method failed", ex);
        }
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

BeanNameAware,BeanClassLoaderAware,BeanFactoryAware 执行是在填充普通bean属性之后,但在初始化回调(如InitializingBean、afterPropertiesSet或自定义init-method)之前调用回调。

1.6.3。其他Aware介面

除了applicationcontext taware和BeanNameAware(前面讨论过)之外,Spring还提供了广泛的可感知回调接口,让bean向容器表明它们需要某种基础设施依赖关系。作为一般规则,名称表示依赖类型。下表总结了最重要的感知接口:

表4.Aware接口 好多没用过,没法做详细解释后续再补充,此处进行简单罗列
名称注入的对象
ApplicationContextAwareApplicationContext
ApplicationEventPublisherAware事件发布者ApplicationContext
BeanClassLoaderAware类加载器,用于加载Bean类。
BeanFactoryAwareBeanFactory
BeanNameAwarebean的名称。
BootstrapContextAwareBootstrapContext容器在其中运行的资源适配器。
通常仅在支持JCA的ApplicationContext实例中可用。
LoadTimeWeaverAware定义了在加载时处理类定义的weaver
MessageSourceAware解决消息的已配置策略(支持参数化和国际化)
NotificationPublisherAwareSpring JMX通知发布者
ResourceLoaderAware已配置用于解析消息的策略(支持参数化和国际化)
ServletConfigAware当前ServletConfig容器在其中运行。
仅在WebApplicationContext环境下运行
ServletContextAware当前ServletContext容器在其中运行。
仅在WebApplicationContext环境下运行

再次注意,使用这些接口会将您的代码与Spring API绑定在一起,并且不遵循“控制反转”样式。因此,我们建议将它们用于需要以编程方式访问容器的基础结构Bean。

1.7。Bean Definition继承

bean定义可以包含许多配置信息,包括构造函数参数、属性值和特定于容器的信息,比如初始化方法、静态工厂方法名,等等。子bean定义从父bean定义继承配置数据。子定义可以覆盖某些值,也可以根据需要添加其他值。使用父bean和子bean定义可以节省大量输入。实际上,这是一种模板形式。

如果您以编程方式使用ApplicationContext接口,则子bean定义由ChildBeanDefinition类表示。大多数用户不会在这个级别上使用它们。相反,它们在类(如ClassPathXmlApplicationContext)中声明性地配置bean定义。当您使用基于xml的配置元数据时,您可以通过使用父属性来指示子bean定义,并将父bean指定为该属性的值。下面的例子展示了如何做到这一点:

<bean id="inheritedTestBean" abstract="true"
        class="org.springframework.beans.TestBean">
    <property name="name" value="parent"/>
    <property name="age" value="1"/>
</bean>

<bean id="inheritsWithDifferentClass"
        class="org.springframework.beans.DerivedTestBean"
        parent="inheritedTestBean" init-method="initialize">  
        <!-- 注意parent属性 -->
    <property name="name" value="override"/>
    <!--age 属性则继承父类-->
</bean>

如果没有指定bean 的class属性,子bean定义使用父定义中的bean的class,但是也可以覆盖它。在后一种情况下,子bean类必须与父bean兼容(也就是说,它必须接受父bean的属性值)。

子bean定义从父bean继承scope、构造函数参数值、属性值,并且覆盖父类方法,并提供添加新值的选项。
您指定的任何Scope、初始化方法、销毁方法或静态工厂方法设置都会覆盖相应的父设置。

其余的设置总是取自子定义:依赖、自动装配模式、依赖检查、单例和 lazy init。

前面的示例通过使用抽象属性显式地将父bean定义标记为抽象。如果父定义没有指定类,则需要显式地将父bean定义标记为抽象,如下面的示例所示:

<bean id="inheritedTestBeanWithoutClass" abstract="true">
    <property name="name" value="parent"/>
    <property name="age" value="1"/>
</bean>

<bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean"
        parent="inheritedTestBeanWithoutClass" init-method="initialize">
    <property name="name" value="override"/>
     <!--age 属性则继承父类-->
</bean>

父bean不能自己实例化,因为它不完整,而且它还显式地标记为抽象。当定义是抽象的时候,它只能作为纯模板bean定义使用,作为子定义的父定义。试图单独使用这样一个抽象的父bean,通过引用它作为另一个bean的ref属性,或者使用父bean ID执行显式的getBean()调用,都会返回错误。类似地,容器的内部预实例化esingletons()方法忽略被定义为抽象的bean定义。

默认情况下,ApplicationContext预实例化所有单例。
因此,如果你有一个(父)bean定义你只打算使用作为模板,
并且这个父bean定义指定了一个类,您必须确保设置抽象属性为true,
否则应用程序上下文会(试图)预实例化abstract的bean。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值