Browse Source
+ Provide @Primary annotation (SPR-5590) + Provide @Lazy annotation (SPR-5591) + Test @Bean initMethod/destroyMethod functionality (SPR-5592) + Test @Bean dependsOn functionality (SPR-5593)pull/23217/head
9 changed files with 360 additions and 46 deletions
@ -0,0 +1,64 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2009 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. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.springframework.context.annotation; |
||||||
|
|
||||||
|
import java.lang.annotation.Documented; |
||||||
|
import java.lang.annotation.ElementType; |
||||||
|
import java.lang.annotation.Retention; |
||||||
|
import java.lang.annotation.RetentionPolicy; |
||||||
|
import java.lang.annotation.Target; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Indicates whether a bean is to be lazily initialized. |
||||||
|
* |
||||||
|
* <p>May be used on any class directly or indirectly annotated with |
||||||
|
* {@link org.springframework.stereotype.Component} or on methods annotated with |
||||||
|
* {@link Bean}. |
||||||
|
* |
||||||
|
* <p>If this annotation is not present on a Component or Bean definition, eager |
||||||
|
* initialization will occur. If present and set to {@literal true}, the |
||||||
|
* Bean/Component will not be initialized until referenced by another bean or |
||||||
|
* explicitly retrieved from the enclosing |
||||||
|
* {@link org.springframework.beans.factory.BeanFactory}. If present and set to |
||||||
|
* {@literal false}, the bean will be instantiated on startup by bean factories |
||||||
|
* that perform eager initialization of singletons. |
||||||
|
* |
||||||
|
* <p>If Lazy is present on a {@link Configuration} class, this indicates that all |
||||||
|
* {@link Bean} methods within that {@literal Configuration} should be lazily |
||||||
|
* initialized. If Lazy is present and false on a Bean method within a |
||||||
|
* Lazy-annotated Configuration class, this indicates overriding the 'default |
||||||
|
* lazy' behavior and that the bean should be eagerly initialized. |
||||||
|
* |
||||||
|
* @author Chris Beams |
||||||
|
* @since 3.0 |
||||||
|
* @see Primary |
||||||
|
* @see Bean |
||||||
|
* @see Configuration |
||||||
|
* @see org.springframework.stereotype.Component |
||||||
|
*/ |
||||||
|
@Target({ ElementType.TYPE, ElementType.METHOD }) |
||||||
|
@Retention(RetentionPolicy.RUNTIME) |
||||||
|
@Documented |
||||||
|
public @interface Lazy { |
||||||
|
|
||||||
|
/** |
||||||
|
* Whether lazy initialization should occur. |
||||||
|
*/ |
||||||
|
boolean value() default true; |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,51 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2009 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. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.springframework.context.annotation; |
||||||
|
|
||||||
|
import java.lang.annotation.Documented; |
||||||
|
import java.lang.annotation.ElementType; |
||||||
|
import java.lang.annotation.Retention; |
||||||
|
import java.lang.annotation.RetentionPolicy; |
||||||
|
import java.lang.annotation.Target; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Indicates that a bean should be given preference when multiple candidates |
||||||
|
* are qualified to autowire a single-valued dependency. If exactly one 'primary' |
||||||
|
* bean exists among the candidates, it will be the autowired value. |
||||||
|
* |
||||||
|
* <p>May be used on any class directly or indirectly annotated with |
||||||
|
* {@link org.springframework.stereotype.Component} or on methods annotated |
||||||
|
* with {@link Bean}. |
||||||
|
* |
||||||
|
* <p>Using {@link Primary} at the class level has no effect unless component-scanning |
||||||
|
* is being used. If a {@link Primary}-annotated class is declared via XML, |
||||||
|
* {@link Primary} annotation metadata is ignored, and |
||||||
|
* {@literal <bean primary="true|false"/>} is respected instead. |
||||||
|
* |
||||||
|
* @author Chris Beams |
||||||
|
* @since 3.0 |
||||||
|
* @see Lazy |
||||||
|
* @see Bean |
||||||
|
* @see org.springframework.stereotype.Component |
||||||
|
*/ |
||||||
|
@Target({ ElementType.TYPE, ElementType.METHOD }) |
||||||
|
@Retention(RetentionPolicy.RUNTIME) |
||||||
|
@Documented |
||||||
|
public @interface Primary { |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,157 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2009 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. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.springframework.context.annotation.configuration; |
||||||
|
|
||||||
|
import static org.junit.Assert.*; |
||||||
|
|
||||||
|
import org.junit.Test; |
||||||
|
import org.springframework.beans.factory.config.BeanDefinition; |
||||||
|
import org.springframework.beans.factory.support.AbstractBeanDefinition; |
||||||
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory; |
||||||
|
import org.springframework.beans.factory.support.RootBeanDefinition; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.context.annotation.ConfigurationClassPostProcessor; |
||||||
|
import org.springframework.context.annotation.Lazy; |
||||||
|
import org.springframework.context.annotation.Primary; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Unit tests proving that the various attributes available via the {@link Bean} |
||||||
|
* annotation are correctly reflected in the {@link BeanDefinition} created when |
||||||
|
* processing the {@link Configuration} class. |
||||||
|
* |
||||||
|
* <p>Also includes tests proving that using {@link Lazy} and {@link Primary} |
||||||
|
* annotations in conjunction with Bean propagate their respective metadata |
||||||
|
* correctly into the resulting BeanDefinition |
||||||
|
* |
||||||
|
* @author Chris Beams |
||||||
|
*/ |
||||||
|
@SuppressWarnings("unused") // for unused @Bean methods in local classes
|
||||||
|
public class BeanAnnotationAttributePropagationTests { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void initMethodMetadataIsPropagated() { |
||||||
|
@Configuration class Config { |
||||||
|
@Bean(initMethod="start") Object foo() { return null; } |
||||||
|
} |
||||||
|
|
||||||
|
assertEquals("init method name was not propagated", |
||||||
|
"start", beanDef(Config.class).getInitMethodName()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void destroyMethodMetadataIsPropagated() { |
||||||
|
@Configuration class Config { |
||||||
|
@Bean(destroyMethod="destroy") Object foo() { return null; } |
||||||
|
} |
||||||
|
|
||||||
|
assertEquals("destroy method name was not propagated", |
||||||
|
"destroy", beanDef(Config.class).getDestroyMethodName()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void dependsOnMetadataIsPropagated() { |
||||||
|
@Configuration class Config { |
||||||
|
@Bean(dependsOn={"bar", "baz"}) Object foo() { return null; } |
||||||
|
} |
||||||
|
|
||||||
|
assertArrayEquals("dependsOn metadata was not propagated", |
||||||
|
new String[] {"bar", "baz"}, beanDef(Config.class).getDependsOn()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void primaryMetadataIsPropagated() { |
||||||
|
@Configuration class Config { |
||||||
|
@Primary @Bean |
||||||
|
Object foo() { return null; } |
||||||
|
} |
||||||
|
|
||||||
|
assertTrue("primary metadata was not propagated", |
||||||
|
beanDef(Config.class).isPrimary()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void primaryMetadataIsFalseByDefault() { |
||||||
|
@Configuration class Config { |
||||||
|
@Bean Object foo() { return null; } |
||||||
|
} |
||||||
|
|
||||||
|
assertFalse("@Bean methods should be non-primary by default", |
||||||
|
beanDef(Config.class).isPrimary()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void lazyMetadataIsPropagated() { |
||||||
|
@Configuration class Config { |
||||||
|
@Lazy @Bean |
||||||
|
Object foo() { return null; } |
||||||
|
} |
||||||
|
|
||||||
|
assertTrue("lazy metadata was not propagated", |
||||||
|
beanDef(Config.class).isLazyInit()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void lazyMetadataIsFalseByDefault() { |
||||||
|
@Configuration class Config { |
||||||
|
@Bean Object foo() { return null; } |
||||||
|
} |
||||||
|
|
||||||
|
assertFalse("@Bean methods should be non-lazy by default", |
||||||
|
beanDef(Config.class).isLazyInit()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void defaultLazyConfigurationPropagatesToIndividualBeans() { |
||||||
|
@Lazy @Configuration class Config { |
||||||
|
@Bean Object foo() { return null; } |
||||||
|
} |
||||||
|
|
||||||
|
assertTrue("@Bean methods declared in a @Lazy @Configuration should be lazily instantiated", |
||||||
|
beanDef(Config.class).isLazyInit()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void eagerBeanOverridesDefaultLazyConfiguration() { |
||||||
|
@Lazy @Configuration class Config { |
||||||
|
@Lazy(false) @Bean Object foo() { return null; } |
||||||
|
} |
||||||
|
|
||||||
|
assertFalse("@Lazy(false) @Bean methods declared in a @Lazy @Configuration should be eagerly instantiated", |
||||||
|
beanDef(Config.class).isLazyInit()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void eagerConfigurationProducesEagerBeanDefinitions() { |
||||||
|
@Lazy(false) @Configuration class Config { // will probably never happen, doesn't make much sense
|
||||||
|
@Bean Object foo() { return null; } |
||||||
|
} |
||||||
|
|
||||||
|
assertFalse("@Lazy(false) @Configuration should produce eager bean definitions", |
||||||
|
beanDef(Config.class).isLazyInit()); |
||||||
|
} |
||||||
|
|
||||||
|
private AbstractBeanDefinition beanDef(Class<?> configClass) { |
||||||
|
DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); |
||||||
|
factory.registerBeanDefinition("config", new RootBeanDefinition(configClass)); |
||||||
|
new ConfigurationClassPostProcessor().postProcessBeanFactory(factory); |
||||||
|
|
||||||
|
return (AbstractBeanDefinition) factory.getBeanDefinition("foo"); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue