diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java index 05eb217803..6e6aae64ba 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 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. @@ -133,7 +133,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport private final Set targetSourcedBeans = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); - private final Set earlyProxyReferences = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); + private final Map earlyProxyReferences = new ConcurrentHashMap<>(16); private final Map> proxyTypes = new ConcurrentHashMap<>(16); @@ -236,9 +236,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport @Override public Object getEarlyBeanReference(Object bean, String beanName) { Object cacheKey = getCacheKey(bean.getClass(), beanName); - if (!this.earlyProxyReferences.contains(cacheKey)) { - this.earlyProxyReferences.add(cacheKey); - } + this.earlyProxyReferences.put(cacheKey, bean); return wrapIfNecessary(bean, beanName, cacheKey); } @@ -297,7 +295,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); - if (!this.earlyProxyReferences.contains(cacheKey)) { + if (this.earlyProxyReferences.remove(cacheKey) != bean) { return wrapIfNecessary(bean, beanName, cacheKey); } } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java index 39b160e15f..a0d64955f5 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 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. @@ -133,8 +133,7 @@ public interface BeanFactory { * Will ask the parent factory if the bean cannot be found in this factory instance. * @param name the name of the bean to retrieve * @return an instance of the bean - * @throws NoSuchBeanDefinitionException if there is no bean definition - * with the specified name + * @throws NoSuchBeanDefinitionException if there is no bean with the specified name * @throws BeansException if the bean could not be obtained */ Object getBean(String name) throws BeansException; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/InjectionPoint.java b/spring-beans/src/main/java/org/springframework/beans/factory/InjectionPoint.java index 4a6eda2bbf..cd0812d187 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/InjectionPoint.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/InjectionPoint.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. @@ -29,6 +29,8 @@ import org.springframework.util.ObjectUtils; /** * A simple descriptor for an injection point, pointing to a method/constructor * parameter or a field. Exposed by {@link UnsatisfiedDependencyException}. + * Also available as an argument for factory methods, reacting to the + * requesting injection point for building a customized bean instance. * * @author Juergen Hoeller * @since 4.3 diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/AutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/AutowireCapableBeanFactory.java index 49b3abf9a7..6d17d6f161 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/AutowireCapableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/AutowireCapableBeanFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 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. @@ -337,8 +337,7 @@ public interface AutowireCapableBeanFactory extends BeanFactory { * including its bean name. *

This is effectively a variant of {@link #getBean(Class)} which preserves the * bean name of the matching instance. - * @param requiredType type the bean must match; can be an interface or superclass. - * {@code null} is disallowed. + * @param requiredType type the bean must match; can be an interface or superclass * @return the bean name plus bean instance * @throws NoSuchBeanDefinitionException if no matching bean was found * @throws NoUniqueBeanDefinitionException if more than one matching bean was found @@ -348,6 +347,22 @@ public interface AutowireCapableBeanFactory extends BeanFactory { */ NamedBeanHolder resolveNamedBean(Class requiredType) throws BeansException; + /** + * Resolve a bean instance for the given bean name, providing a dependency descriptor + * for exposure to target factory methods. + *

This is effectively a variant of {@link #getBean(String, Class)} which supports + * factory methods with an {@link org.springframework.beans.factory.InjectionPoint} + * argument. + * @param name the name of the bean to look up + * @param descriptor the dependency descriptor for the requesting injection point + * @return the corresponding bean instance + * @throws NoSuchBeanDefinitionException if there is no bean with the specified name + * @throws BeansException if the bean could not be created + * @since 5.1.5 + * @see #getBean(String, Class) + */ + Object resolveBeanByName(String name, DependencyDescriptor descriptor) throws BeansException; + /** * Resolve the specified dependency against the beans defined in this factory. * @param descriptor the descriptor for the dependency (field/method/constructor) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java index 13bb3cf44e..6ccc3bbf8c 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 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. @@ -58,6 +58,7 @@ import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.InjectionPoint; import org.springframework.beans.factory.UnsatisfiedDependencyException; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.beans.factory.config.BeanDefinition; @@ -337,12 +338,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac return initializeBean(beanName, existingBean, bd); } - @Override - @Nullable - public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException { - return resolveDependency(descriptor, requestingBeanName, null, null); - } - //------------------------------------------------------------------------- // Specialized methods for fine-grained control over the bean lifecycle @@ -446,6 +441,28 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac } + //------------------------------------------------------------------------- + // Delegate methods for resolving injection points + //------------------------------------------------------------------------- + + @Override + public Object resolveBeanByName(String name, DependencyDescriptor descriptor) { + InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor); + try { + return getBean(name, descriptor.getDependencyType()); + } + finally { + ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint); + } + } + + @Override + @Nullable + public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException { + return resolveDependency(descriptor, requestingBeanName, null, null); + } + + //--------------------------------------------------------------------- // Implementation of relevant AbstractBeanFactory template methods //--------------------------------------------------------------------- diff --git a/spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java b/spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java index 772d5972a1..2ed96949b3 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 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. @@ -512,13 +512,19 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean Set autowiredBeanNames; String name = element.name; - if (this.fallbackToDefaultTypeMatch && element.isDefaultName && - factory instanceof AutowireCapableBeanFactory && !factory.containsBean(name)) { - autowiredBeanNames = new LinkedHashSet<>(); - resource = ((AutowireCapableBeanFactory) factory).resolveDependency( - element.getDependencyDescriptor(), requestingBeanName, autowiredBeanNames, null); - if (resource == null) { - throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object"); + if (factory instanceof AutowireCapableBeanFactory) { + AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory; + DependencyDescriptor descriptor = element.getDependencyDescriptor(); + if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) { + autowiredBeanNames = new LinkedHashSet<>(); + resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null); + if (resource == null) { + throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object"); + } + } + else { + resource = beanFactory.resolveBeanByName(name, descriptor); + autowiredBeanNames = Collections.singleton(name); } } else { diff --git a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java index ee1603ef17..54c3850158 100644 --- a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java +++ b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 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. @@ -212,7 +212,11 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader /** Statically specified listeners. */ private final Set> applicationListeners = new LinkedHashSet<>(); - /** ApplicationEvents published early. */ + /** Local listeners registered before refresh. */ + @Nullable + private Set> earlyApplicationListeners; + + /** ApplicationEvents published before the multicaster setup. */ @Nullable private Set earlyApplicationEvents; @@ -483,7 +487,6 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader this.beanFactoryPostProcessors.add(postProcessor); } - /** * Return the list of BeanFactoryPostProcessors that will get applied * to the internal BeanFactory. @@ -578,6 +581,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader * active flag as well as performing any initialization of property sources. */ protected void prepareRefresh() { + // Switch to active. this.startupDate = System.currentTimeMillis(); this.closed.set(false); this.active.set(true); @@ -591,13 +595,23 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader } } - // Initialize any placeholder property sources in the context environment + // Initialize any placeholder property sources in the context environment. initPropertySources(); - // Validate that all properties marked as required are resolvable + // Validate that all properties marked as required are resolvable: // see ConfigurablePropertyResolver#setRequiredProperties getEnvironment().validateRequiredProperties(); + // Store pre-refresh ApplicationListeners... + if (this.earlyApplicationListeners == null) { + this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners); + } + else { + // Reset local application listeners to pre-refresh state. + this.applicationListeners.clear(); + this.applicationListeners.addAll(this.earlyApplicationListeners); + } + // Allow for the collection of early ApplicationEvents, // to be published once the multicaster is available... this.earlyApplicationEvents = new LinkedHashSet<>(); @@ -982,6 +996,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader * @see #registerShutdownHook() */ protected void doClose() { + // Check whether an actual close attempt is necessary... if (this.active.get() && this.closed.compareAndSet(false, true)) { if (logger.isDebugEnabled()) { logger.debug("Closing " + this); @@ -1016,6 +1031,13 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader // Let subclasses do some final clean-up if they wish... onClose(); + // Reset local application listeners to pre-refresh state. + if (this.earlyApplicationListeners != null) { + this.applicationListeners.clear(); + this.applicationListeners.addAll(this.earlyApplicationListeners); + } + + // Switch to inactive. this.active.set(false); } } @@ -1302,7 +1324,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader @Nullable protected MessageSource getInternalParentMessageSource() { return (getParent() instanceof AbstractApplicationContext ? - ((AbstractApplicationContext) getParent()).messageSource : getParent()); + ((AbstractApplicationContext) getParent()).messageSource : getParent()); } diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java index 5d172cbb01..79a165b2db 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 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. @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.List; import java.util.Set; import java.util.function.Supplier; +import javax.annotation.Resource; import javax.inject.Provider; import org.junit.Rule; @@ -228,6 +229,22 @@ public class ConfigurationClassProcessingTests { ctx.close(); } + @Test + public void configurationWithAdaptiveResourcePrototypes() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(ConfigWithPrototypeBean.class, AdaptiveResourceInjectionPoints.class); + ctx.refresh(); + + AdaptiveResourceInjectionPoints adaptive = ctx.getBean(AdaptiveResourceInjectionPoints.class); + assertEquals("adaptiveInjectionPoint1", adaptive.adaptiveInjectionPoint1.getName()); + assertEquals("setAdaptiveInjectionPoint2", adaptive.adaptiveInjectionPoint2.getName()); + + adaptive = ctx.getBean(AdaptiveResourceInjectionPoints.class); + assertEquals("adaptiveInjectionPoint1", adaptive.adaptiveInjectionPoint1.getName()); + assertEquals("setAdaptiveInjectionPoint2", adaptive.adaptiveInjectionPoint2.getName()); + ctx.close(); + } + @Test public void configurationWithPostProcessor() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); @@ -444,6 +461,21 @@ public class ConfigurationClassProcessingTests { } + @Scope("prototype") + static class AdaptiveResourceInjectionPoints { + + @Resource(name = "adaptive1") + public TestBean adaptiveInjectionPoint1; + + public TestBean adaptiveInjectionPoint2; + + @Resource(name = "adaptive2") + public void setAdaptiveInjectionPoint2(TestBean adaptiveInjectionPoint2) { + this.adaptiveInjectionPoint2 = adaptiveInjectionPoint2; + } + } + + static class ConfigWithPostProcessor extends ConfigWithPrototypeBean { @Value("${myProp}") diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StubWebApplicationContext.java b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StubWebApplicationContext.java index 99a575f17e..e41e12d4f1 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StubWebApplicationContext.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StubWebApplicationContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 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. @@ -411,6 +411,11 @@ class StubWebApplicationContext implements WebApplicationContext { throw new UnsupportedOperationException("Dependency resolution not supported"); } + @Override + public Object resolveBeanByName(String name, DependencyDescriptor descriptor) throws BeansException { + throw new UnsupportedOperationException("Dependency resolution not supported"); + } + @Override @Nullable public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) { diff --git a/src/docs/asciidoc/core/core-beans.adoc b/src/docs/asciidoc/core/core-beans.adoc index 75c6bcec41..38e63c1c6e 100644 --- a/src/docs/asciidoc/core/core-beans.adoc +++ b/src/docs/asciidoc/core/core-beans.adoc @@ -1044,7 +1044,8 @@ load an entire Spring IoC container instance. Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. Note that use of the <> -annotation on a setter method can be used to make the property be a required dependency. +annotation on a setter method can be used to make the property be a required dependency; +however, constructor injection with programmatic validation of arguments is preferable. The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies @@ -1076,8 +1077,8 @@ The container performs bean dependency resolution as follows: describes all the beans. Configuration metadata can be specified by XML, Java code, or annotations. * For each bean, its dependencies are expressed in the form of properties, constructor - arguments, or arguments to the static-factory method( if you use that instead of - a normal constructor). These dependencies are provided to the bean, when the bean is + arguments, or arguments to the static-factory method (if you use that instead of a + normal constructor). These dependencies are provided to the bean, when the bean is actually created. * Each property or constructor argument is an actual definition of the value to set, or a reference to another bean in the container. @@ -3070,8 +3071,8 @@ of a bean. This section groups them as follows: [[beans-factory-lifecycle]] === Lifecycle Callbacks -To interact with the container's management of the bean lifecycle, you can implement the -Spring `InitializingBean` and `DisposableBean` interfaces. The container calls +To interact with the container's management of the bean lifecycle, you can implement +the Spring `InitializingBean` and `DisposableBean` interfaces. The container calls `afterPropertiesSet()` for the former and `destroy()` for the latter to let the bean perform certain actions upon initialization and destruction of your beans. @@ -3079,11 +3080,11 @@ perform certain actions upon initialization and destruction of your beans. ==== The JSR-250 `@PostConstruct` and `@PreDestroy` annotations are generally considered best practice for receiving lifecycle callbacks in a modern Spring application. Using these -annotations means that your beans are not coupled to Spring-specific interfaces. For -details, see <>. +annotations means that your beans are not coupled to Spring-specific interfaces. +For details, see <>. If you do not want to use the JSR-250 annotations but you still want to remove -coupling, consider using of `init-method` and `destroy-method` object definition metadata. +coupling, consider `init-method` and `destroy-method` bean definition metadata. ==== Internally, the Spring Framework uses `BeanPostProcessor` implementations to process any @@ -3099,7 +3100,6 @@ startup and shutdown process, as driven by the container's own lifecycle. The lifecycle callback interfaces are described in this section. - [[beans-factory-lifecycle-initializingbean]] ==== Initialization Callbacks @@ -3138,8 +3138,8 @@ no-argument signature. With Java configuration, you can use the `initMethod` att } ---- -The preceding example has almost exactly the same effect as the following example (which -consists of two listings): +The preceding example has almost exactly the same effect as the following example +(which consists of two listings): [source,xml,indent=0] [subs="verbatim,quotes"] @@ -4313,11 +4313,18 @@ example: This annotation indicates that the affected bean property must be populated at configuration time, through an explicit property value in a bean definition or through autowiring. The container throws an exception if the affected bean property has not been -populated. This allows for eager and explicit failure, avoiding `NullPointerException` instances -or the like later on. We still recommend that you put assertions into the bean -class itself (for example, into an init method). Doing so enforces those required +populated. This allows for eager and explicit failure, avoiding `NullPointerException` +instances or the like later on. We still recommend that you put assertions into the +bean class itself (for example, into an init method). Doing so enforces those required references and values even when you use the class outside of a container. +[NOTE] +==== +The `@Required` annotation is formally deprecated as of Spring Framework 5.1, in favor +of using constructor injection for required settings (or a custom implementation of +`InitializingBean.afterPropertiesSet()` along with bean property setter methods). +==== + [[beans-autowired-annotation]] @@ -5149,14 +5156,14 @@ attribute set to `true`, it is selected. [[beans-resource-annotation]] === Injection with `@Resource` -Spring also supports injection by using the JSR-250 `@Resource` annotation on fields or -bean property setter methods. This is a common pattern in Java EE 5 and 6 (for example, -in JSF 1.2 managed beans or JAX-WS 2.0 endpoints). Spring supports this pattern for -Spring-managed objects as well. +Spring also supports injection by using the JSR-250 `@Resource` annotation +(`javax.annotation.Resource`) on fields or bean property setter methods. +This is a common pattern in Java EE: for example, in JSF-managed beans and JAX-WS +endpoints. Spring supports this pattern for Spring-managed objects as well. -`@Resource` takes a name attribute. By default, Spring interprets that value as the -bean name to be injected. In other words, it follows by-name semantics, as -demonstrated in the following example: +`@Resource` takes a name attribute. By default, Spring interprets that value as +the bean name to be injected. In other words, it follows by-name semantics, +as demonstrated in the following example: [source,java,indent=0] [subs="verbatim,quotes"] @@ -5207,7 +5214,7 @@ and resolves well known resolvable dependencies: the `BeanFactory`, interfaces. Thus, in the following example, the `customerPreferenceDao` field first looks for a bean -named customerPreferenceDao and then falls back to a primary type match for the type +named "customerPreferenceDao" and then falls back to a primary type match for the type `CustomerPreferenceDao`: [source,java,indent=0] @@ -5236,15 +5243,16 @@ named customerPreferenceDao and then falls back to a primary type match for the === Using `@PostConstruct` and `@PreDestroy` The `CommonAnnotationBeanPostProcessor` not only recognizes the `@Resource` annotation -but also the JSR-250 lifecycle annotations. Introduced in Spring 2.5, the support -for these annotations offers yet another alternative to those described in +but also the JSR-250 lifecycle annotations: `javax.annotation.PostConstruct` and +`javax.annotation.PreDestroy`. Introduced in Spring 2.5, the support for these +annotations offers an alternative to the lifecycle callback mechanism described in <> and <>. Provided that the -`CommonAnnotationBeanPostProcessor` is registered within the Spring -`ApplicationContext`, a method carrying one of these annotations is invoked at the same -point in the lifecycle as the corresponding Spring lifecycle interface method or -explicitly declared callback method. In the following example, the cache is -pre-populated upon initialization and cleared upon destruction: +`CommonAnnotationBeanPostProcessor` is registered within the Spring `ApplicationContext`, +a method carrying one of these annotations is invoked at the same point in the lifecycle +as the corresponding Spring lifecycle interface method or explicitly declared callback +method. In the following example, the cache is pre-populated upon initialization and +cleared upon destruction: [source,java,indent=0] [subs="verbatim,quotes"] @@ -5263,9 +5271,19 @@ pre-populated upon initialization and cleared upon destruction: } ---- -NOTE: For details about the effects of combining various lifecycle mechanisms, see +For details about the effects of combining various lifecycle mechanisms, see <>. +[NOTE] +==== +Like `@Resource`, the `@PostConstruct` and `@PreDestroy` annotation types were a part +of the standard Java libraries from JDK 6 to 8. However, the entire `javax.annotation` +package got separated from the core Java modules in JDK 9 and eventually removed in +JDK 11. If needed, the `javax.annotation-api` artifact needs to be obtained via Maven +Central now, simply to be added to the application's classpath like any other library. +==== + + [[beans-classpath-scanning]] @@ -6722,8 +6740,8 @@ The following example shows how to prevent an automatic destruction callback for } ---- -Also, with `@Bean` methods, you typically use programmatic JNDI lookups, -either by using Spring's `JndiTemplate` or `JndiLocatorDelegate` helpers or straight JNDI +Also, with `@Bean` methods, you typically use programmatic JNDI lookups, either by +using Spring's `JndiTemplate` or `JndiLocatorDelegate` helpers or straight JNDI `InitialContext` usage but not the `JndiObjectFactoryBean` variant (which would force you to declare the return type as the `FactoryBean` type instead of the actual target type, making it harder to use for cross-reference calls in other `@Bean` methods that @@ -6790,7 +6808,7 @@ Spring offers a convenient way of working with scoped dependencies through <>. The easiest way to create such a proxy when using the XML configuration is the `` element. Configuring your beans in Java with a `@Scope` annotation offers equivalent support with -the `proxyMode` attribute. The default is no proxy ( `ScopedProxyMode.NO`), but you can +the `proxyMode` attribute. The default is no proxy (`ScopedProxyMode.NO`), but you can specify `ScopedProxyMode.TARGET_CLASS` or `ScopedProxyMode.INTERFACES`. If you port the scoped proxy example from the XML reference documentation (see @@ -8847,9 +8865,9 @@ exist, the listener uses `/WEB-INF/applicationContext.xml` as a default. When th parameter does exist, the listener separates the `String` by using predefined delimiters (comma, semicolon, and whitespace) and uses the values as locations where application contexts are searched. Ant-style path patterns are supported as well. -Examples are `/WEB-INF/{asterisk}Context.xml` (for all files with names that end with `Context.xml` -and that reside in the `WEB-INF` directory) and `/WEB-INF/**/*Context.xml`( for all such files -in any subdirectory of `WEB-INF`). +Examples are `/WEB-INF/{asterisk}Context.xml` (for all files with names that end with +`Context.xml` and that reside in the `WEB-INF` directory) and `/WEB-INF/**/*Context.xml` +(for all such files in any subdirectory of `WEB-INF`). @@ -8860,17 +8878,17 @@ It is possible to deploy a Spring `ApplicationContext` as a RAR file, encapsulat context and all of its required bean classes and library JARs in a Java EE RAR deployment unit. This is the equivalent of bootstrapping a stand-alone `ApplicationContext` (only hosted in Java EE environment) being able to access the Java EE servers facilities. RAR deployment -is a more natural alternative to a scenario of deploying a headless WAR file -- in effect, a WAR -file without any HTTP entry points that is used only for bootstrapping a Spring +is a more natural alternative to a scenario of deploying a headless WAR file -- in effect, +a WAR file without any HTTP entry points that is used only for bootstrapping a Spring `ApplicationContext` in a Java EE environment. RAR deployment is ideal for application contexts that do not need HTTP entry points but rather consist only of message endpoints and scheduled jobs. Beans in such a context can use application server resources such as the JTA transaction manager and JNDI-bound JDBC -`DataSource` instances and JMS `ConnectionFactory` instances and can also register with the -platform's JMX server -- all through Spring's standard transaction management and JNDI -and JMX support facilities. Application components can also interact with the -application server's JCA `WorkManager` through Spring's `TaskExecutor` abstraction. +`DataSource` instances and JMS `ConnectionFactory` instances and can also register with +the platform's JMX server -- all through Spring's standard transaction management and JNDI +and JMX support facilities. Application components can also interact with the application +server's JCA `WorkManager` through Spring's `TaskExecutor` abstraction. See the javadoc of the {api-spring-framework}/jca/context/SpringContextResourceAdapter.html[`SpringContextResourceAdapter`] @@ -8889,13 +8907,13 @@ and the corresponding Spring XML bean definition file(s) (typically . Drop the resulting RAR file into your application server's deployment directory. -NOTE: Such RAR deployment units are usually self-contained. They do not expose components to -the outside world, not even to other modules of the same application. Interaction with a +NOTE: Such RAR deployment units are usually self-contained. They do not expose components +to the outside world, not even to other modules of the same application. Interaction with a RAR-based `ApplicationContext` usually occurs through JMS destinations that it shares with other modules. A RAR-based `ApplicationContext` may also, for example, schedule some jobs or react to new files in the file system (or the like). If it needs to allow synchronous -access from the outside, it could (for example) export RMI endpoints, which may -be used by other application modules on the same machine. +access from the outside, it could (for example) export RMI endpoints, which may be used +by other application modules on the same machine.