diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java index cb266c4660..a845df267e 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java @@ -145,7 +145,8 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess private boolean abstractFlag = false; - private boolean lazyInit = false; + @Nullable + private Boolean lazyInit; private int autowireMode = AUTOWIRE_NO; @@ -229,7 +230,6 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess setBeanClassName(original.getBeanClassName()); setScope(original.getScope()); setAbstract(original.isAbstract()); - setLazyInit(original.isLazyInit()); setFactoryBeanName(original.getFactoryBeanName()); setFactoryMethodName(original.getFactoryMethodName()); setRole(original.getRole()); @@ -250,6 +250,10 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess if (originalAbd.hasMethodOverrides()) { setMethodOverrides(new MethodOverrides(originalAbd.getMethodOverrides())); } + Boolean lazyInit = originalAbd.getLazyInit(); + if (lazyInit != null) { + setLazyInit(lazyInit); + } setAutowireMode(originalAbd.getAutowireMode()); setDependencyCheck(originalAbd.getDependencyCheck()); setDependsOn(originalAbd.getDependsOn()); @@ -269,6 +273,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess else { setConstructorArgumentValues(new ConstructorArgumentValues(original.getConstructorArgumentValues())); setPropertyValues(new MutablePropertyValues(original.getPropertyValues())); + setLazyInit(original.isLazyInit()); setResourceDescription(original.getResourceDescription()); } } @@ -298,7 +303,6 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess setScope(other.getScope()); } setAbstract(other.isAbstract()); - setLazyInit(other.isLazyInit()); if (StringUtils.hasLength(other.getFactoryBeanName())) { setFactoryBeanName(other.getFactoryBeanName()); } @@ -323,6 +327,10 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess if (otherAbd.hasMethodOverrides()) { getMethodOverrides().addOverrides(otherAbd.getMethodOverrides()); } + Boolean lazyInit = otherAbd.getLazyInit(); + if (lazyInit != null) { + setLazyInit(lazyInit); + } setAutowireMode(otherAbd.getAutowireMode()); setDependencyCheck(otherAbd.getDependencyCheck()); setDependsOn(otherAbd.getDependsOn()); @@ -346,16 +354,21 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess else { getConstructorArgumentValues().addArgumentValues(other.getConstructorArgumentValues()); getPropertyValues().addPropertyValues(other.getPropertyValues()); + setLazyInit(other.isLazyInit()); setResourceDescription(other.getResourceDescription()); } } /** * Apply the provided default values to this bean. - * @param defaults the defaults to apply + * @param defaults the default settings to apply + * @since 2.5 */ public void applyDefaults(BeanDefinitionDefaults defaults) { - setLazyInit(defaults.isLazyInit()); + Boolean lazyInit = defaults.getLazyInit(); + if (lazyInit != null) { + setLazyInit(lazyInit); + } setAutowireMode(defaults.getAutowireMode()); setDependencyCheck(defaults.getDependencyCheck()); setInitMethodName(defaults.getInitMethodName()); @@ -515,16 +528,29 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess /** * Return whether this bean should be lazily initialized, i.e. not * eagerly instantiated on startup. Only applicable to a singleton bean. + * @return whether to apply lazy-init semantics ({@code false} by default) */ @Override public boolean isLazyInit() { + return (this.lazyInit != null && this.lazyInit.booleanValue()); + } + + /** + * Return whether this bean should be lazily initialized, i.e. not + * eagerly instantiated on startup. Only applicable to a singleton bean. + * @return the lazy-init flag if explicitly set, or {@code null} otherwise + * @since 5.2 + */ + @Nullable + public Boolean getLazyInit() { return this.lazyInit; } /** * Set the autowire mode. This determines whether any automagical detection - * and setting of bean references will happen. Default is AUTOWIRE_NO, - * which means there's no autowire. + * and setting of bean references will happen. Default is AUTOWIRE_NO + * which means there won't be convention-based autowiring by name or type + * (however, there may still be explicit annotation-driven autowiring). * @param autowireMode the autowire mode to set. * Must be one of the constants defined in this class. * @see #AUTOWIRE_NO diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionDefaults.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionDefaults.java index 2a3bd635f9..f98567a070 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionDefaults.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionDefaults.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,16 +23,18 @@ import org.springframework.util.StringUtils; * A simple holder for {@code BeanDefinition} property defaults. * * @author Mark Fisher + * @author Juergen Hoeller * @since 2.5 */ public class BeanDefinitionDefaults { - private boolean lazyInit; - - private int dependencyCheck = AbstractBeanDefinition.DEPENDENCY_CHECK_NONE; + @Nullable + private Boolean lazyInit; private int autowireMode = AbstractBeanDefinition.AUTOWIRE_NO; + private int dependencyCheck = AbstractBeanDefinition.DEPENDENCY_CHECK_NONE; + @Nullable private String initMethodName; @@ -40,43 +42,95 @@ public class BeanDefinitionDefaults { private String destroyMethodName; + /** + * Set whether beans should be lazily initialized by default. + *

If {@code false}, the bean will get instantiated on startup by bean + * factories that perform eager initialization of singletons. + */ public void setLazyInit(boolean lazyInit) { this.lazyInit = lazyInit; } + /** + * Return whether beans should be lazily initialized by default, i.e. not + * eagerly instantiated on startup. Only applicable to singleton beans. + * @return whether to apply lazy-init semantics ({@code false} by default) + */ public boolean isLazyInit() { + return (this.lazyInit != null && this.lazyInit.booleanValue()); + } + + /** + * Return whether beans should be lazily initialized by default, i.e. not + * eagerly instantiated on startup. Only applicable to singleton beans. + * @return the lazy-init flag if explicitly set, or {@code null} otherwise + * @since 5.2 + */ + @Nullable + public Boolean getLazyInit() { return this.lazyInit; } - public void setDependencyCheck(int dependencyCheck) { - this.dependencyCheck = dependencyCheck; - } - - public int getDependencyCheck() { - return this.dependencyCheck; - } - + /** + * Set the autowire mode. This determines whether any automagical detection + * and setting of bean references will happen. Default is AUTOWIRE_NO + * which means there won't be convention-based autowiring by name or type + * (however, there may still be explicit annotation-driven autowiring). + * @param autowireMode the autowire mode to set. + * Must be one of the constants defined in {@link AbstractBeanDefinition}. + */ public void setAutowireMode(int autowireMode) { this.autowireMode = autowireMode; } + /** + * Return the default autowire mode. + */ public int getAutowireMode() { return this.autowireMode; } + /** + * Set the dependency check code. + * @param dependencyCheck the code to set. + * Must be one of the constants defined in {@link AbstractBeanDefinition}. + */ + public void setDependencyCheck(int dependencyCheck) { + this.dependencyCheck = dependencyCheck; + } + + /** + * Return the default dependency check code. + */ + public int getDependencyCheck() { + return this.dependencyCheck; + } + + /** + * Set the name of the default initializer method. + */ public void setInitMethodName(@Nullable String initMethodName) { this.initMethodName = (StringUtils.hasText(initMethodName) ? initMethodName : null); } + /** + * Return the name of the default initializer method. + */ @Nullable public String getInitMethodName() { return this.initMethodName; } + /** + * Set the name of the default destroy method. + */ public void setDestroyMethodName(@Nullable String destroyMethodName) { this.destroyMethodName = (StringUtils.hasText(destroyMethodName) ? destroyMethodName : null); } + /** + * Return the name of the default destroy method. + */ @Nullable public String getDestroyMethodName() { return this.destroyMethodName; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java index 86b8fca738..c34e2dacb9 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java @@ -2353,6 +2353,27 @@ public class DefaultListableBeanFactoryTests { lbf.preInstantiateSingletons(); } + @Test + public void testLazyInitFlag() { + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class); + bd1.setLazyInit(true); + factory.registerBeanDefinition("tb1", bd1); + RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class); + bd2.setLazyInit(false); + factory.registerBeanDefinition("tb2", bd2); + factory.registerBeanDefinition("tb3", new RootBeanDefinition(TestBean.class)); + + assertEquals(Boolean.TRUE, ((AbstractBeanDefinition) factory.getMergedBeanDefinition("tb1")).getLazyInit()); + assertEquals(Boolean.FALSE, ((AbstractBeanDefinition) factory.getMergedBeanDefinition("tb2")).getLazyInit()); + assertNull(((AbstractBeanDefinition) factory.getMergedBeanDefinition("tb3")).getLazyInit()); + + factory.preInstantiateSingletons(); + assertFalse(factory.containsSingleton("tb1")); + assertTrue(factory.containsSingleton("tb2")); + assertTrue(factory.containsSingleton("tb3")); + } + @Test public void testLazyInitFactory() { DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); @@ -2877,8 +2898,8 @@ public class DefaultListableBeanFactoryTests { } } - @SuppressWarnings("unchecked") @Test + @SuppressWarnings("unchecked") public void testInitSecurityAwarePrototypeBean() { final DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); RootBeanDefinition bd = new RootBeanDefinition(TestSecuredBean.class); @@ -2889,12 +2910,7 @@ public class DefaultListableBeanFactoryTests { subject.getPrincipals().add(new TestPrincipal("user1")); TestSecuredBean bean = (TestSecuredBean) Subject.doAsPrivileged(subject, - new PrivilegedAction() { - @Override - public Object run() { - return lbf.getBean("test"); - } - }, null); + (PrivilegedAction) () -> lbf.getBean("test"), null); assertNotNull(bean); assertEquals("user1", bean.getUserName()); }