Skip to content

Commit 3b9605b

Browse files
committed
init/destroy methods get processed in the order of declaration at each hierarchy level (SPR-6344); process DestructionAwareBeanPostProcessors in common post-processor order; aligned metadata retrieval code
1 parent 4375b9c commit 3b9605b

File tree

3 files changed

+113
-94
lines changed

3 files changed

+113
-94
lines changed

org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java

Lines changed: 47 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -303,61 +303,65 @@ public void processInjection(Object bean) throws BeansException {
303303
}
304304

305305

306-
private InjectionMetadata findAutowiringMetadata(final Class clazz) {
306+
private InjectionMetadata findAutowiringMetadata(Class clazz) {
307307
// Quick check on the concurrent map first, with minimal locking.
308308
InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);
309309
if (metadata == null) {
310310
synchronized (this.injectionMetadataCache) {
311311
metadata = this.injectionMetadataCache.get(clazz);
312312
if (metadata == null) {
313-
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
314-
Class<?> targetClass = clazz;
315-
316-
do {
317-
LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>();
318-
for (Field field : targetClass.getDeclaredFields()) {
319-
Annotation annotation = findAutowiredAnnotation(field);
320-
if (annotation != null) {
321-
if (Modifier.isStatic(field.getModifiers())) {
322-
if (logger.isWarnEnabled()) {
323-
logger.warn("Autowired annotation is not supported on static fields: " + field);
324-
}
325-
continue;
326-
}
327-
boolean required = determineRequiredStatus(annotation);
328-
currElements.add(new AutowiredFieldElement(field, required));
329-
}
313+
metadata = buildAutowiringMetadata(clazz);
314+
this.injectionMetadataCache.put(clazz, metadata);
315+
}
316+
}
317+
}
318+
return metadata;
319+
}
320+
321+
private InjectionMetadata buildAutowiringMetadata(Class clazz) {
322+
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
323+
Class<?> targetClass = clazz;
324+
325+
do {
326+
LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>();
327+
for (Field field : targetClass.getDeclaredFields()) {
328+
Annotation annotation = findAutowiredAnnotation(field);
329+
if (annotation != null) {
330+
if (Modifier.isStatic(field.getModifiers())) {
331+
if (logger.isWarnEnabled()) {
332+
logger.warn("Autowired annotation is not supported on static fields: " + field);
330333
}
331-
for (Method method : targetClass.getDeclaredMethods()) {
332-
Annotation annotation = findAutowiredAnnotation(method);
333-
if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
334-
if (Modifier.isStatic(method.getModifiers())) {
335-
if (logger.isWarnEnabled()) {
336-
logger.warn("Autowired annotation is not supported on static methods: " + method);
337-
}
338-
continue;
339-
}
340-
if (method.getParameterTypes().length == 0) {
341-
if (logger.isWarnEnabled()) {
342-
logger.warn("Autowired annotation should be used on methods with actual parameters: " + method);
343-
}
344-
}
345-
boolean required = determineRequiredStatus(annotation);
346-
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
347-
currElements.add(new AutowiredMethodElement(method, required, pd));
348-
}
334+
continue;
335+
}
336+
boolean required = determineRequiredStatus(annotation);
337+
currElements.add(new AutowiredFieldElement(field, required));
338+
}
339+
}
340+
for (Method method : targetClass.getDeclaredMethods()) {
341+
Annotation annotation = findAutowiredAnnotation(method);
342+
if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
343+
if (Modifier.isStatic(method.getModifiers())) {
344+
if (logger.isWarnEnabled()) {
345+
logger.warn("Autowired annotation is not supported on static methods: " + method);
349346
}
350-
elements.addAll(0, currElements);
351-
targetClass = targetClass.getSuperclass();
347+
continue;
352348
}
353-
while (targetClass != null && targetClass != Object.class);
354-
355-
metadata = new InjectionMetadata(clazz, elements);
356-
this.injectionMetadataCache.put(clazz, metadata);
349+
if (method.getParameterTypes().length == 0) {
350+
if (logger.isWarnEnabled()) {
351+
logger.warn("Autowired annotation should be used on methods with actual parameters: " + method);
352+
}
353+
}
354+
boolean required = determineRequiredStatus(annotation);
355+
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
356+
currElements.add(new AutowiredMethodElement(method, required, pd));
357357
}
358358
}
359+
elements.addAll(0, currElements);
360+
targetClass = targetClass.getSuperclass();
359361
}
360-
return metadata;
362+
while (targetClass != null && targetClass != Object.class);
363+
364+
return new InjectionMetadata(clazz, elements);
361365
}
362366

363367
private Annotation findAutowiredAnnotation(AccessibleObject ao) {

org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java

Lines changed: 64 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@
2525
import java.lang.reflect.Modifier;
2626
import java.util.Collection;
2727
import java.util.Iterator;
28+
import java.util.LinkedHashSet;
2829
import java.util.LinkedList;
2930
import java.util.Map;
31+
import java.util.Set;
3032
import java.util.concurrent.ConcurrentHashMap;
3133

3234
import org.apache.commons.logging.Log;
@@ -118,24 +120,7 @@ public int getOrder() {
118120
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) {
119121
if (beanType != null) {
120122
LifecycleMetadata metadata = findLifecycleMetadata(beanType);
121-
for (Iterator<LifecycleElement> it = metadata.getInitMethods().iterator(); it.hasNext();) {
122-
String methodIdentifier = it.next().getIdentifier();
123-
if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) {
124-
beanDefinition.registerExternallyManagedInitMethod(methodIdentifier);
125-
}
126-
else {
127-
it.remove();
128-
}
129-
}
130-
for (Iterator<LifecycleElement> it = metadata.getDestroyMethods().iterator(); it.hasNext();) {
131-
String methodIdentifier = it.next().getIdentifier();
132-
if (!beanDefinition.isExternallyManagedDestroyMethod(methodIdentifier)) {
133-
beanDefinition.registerExternallyManagedDestroyMethod(methodIdentifier);
134-
}
135-
else {
136-
it.remove();
137-
}
138-
}
123+
metadata.checkConfigMembers(beanDefinition);
139124
}
140125
}
141126

@@ -197,30 +182,41 @@ private LifecycleMetadata findLifecycleMetadata(Class clazz) {
197182
return metadata;
198183
}
199184

200-
private LifecycleMetadata buildLifecycleMetadata(final Class clazz) {
201-
final LifecycleMetadata newMetadata = new LifecycleMetadata();
185+
private LifecycleMetadata buildLifecycleMetadata(Class clazz) {
202186
final boolean debug = logger.isDebugEnabled();
203-
ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() {
204-
public void doWith(Method method) {
205-
if (initAnnotationType != null) {
206-
if (method.getAnnotation(initAnnotationType) != null) {
207-
newMetadata.addInitMethod(method);
187+
LinkedList<LifecycleElement> initMethods = new LinkedList<LifecycleElement>();
188+
LinkedList<LifecycleElement> destroyMethods = new LinkedList<LifecycleElement>();
189+
Class<?> targetClass = clazz;
190+
191+
do {
192+
LinkedList<LifecycleElement> currInitMethods = new LinkedList<LifecycleElement>();
193+
LinkedList<LifecycleElement> currDestroyMethods = new LinkedList<LifecycleElement>();
194+
for (Method method : targetClass.getDeclaredMethods()) {
195+
if (this.initAnnotationType != null) {
196+
if (method.getAnnotation(this.initAnnotationType) != null) {
197+
LifecycleElement element = new LifecycleElement(method);
198+
currInitMethods.add(element);
208199
if (debug) {
209200
logger.debug("Found init method on class [" + clazz.getName() + "]: " + method);
210201
}
211202
}
212203
}
213-
if (destroyAnnotationType != null) {
214-
if (method.getAnnotation(destroyAnnotationType) != null) {
215-
newMetadata.addDestroyMethod(method);
204+
if (this.destroyAnnotationType != null) {
205+
if (method.getAnnotation(this.destroyAnnotationType) != null) {
206+
currDestroyMethods.add(new LifecycleElement(method));
216207
if (debug) {
217208
logger.debug("Found destroy method on class [" + clazz.getName() + "]: " + method);
218209
}
219210
}
220211
}
221212
}
222-
});
223-
return newMetadata;
213+
initMethods.addAll(0, currInitMethods);
214+
destroyMethods.addAll(currDestroyMethods);
215+
targetClass = targetClass.getSuperclass();
216+
}
217+
while (targetClass != null && targetClass != Object.class);
218+
219+
return new LifecycleMetadata(clazz, initMethods, destroyMethods);
224220
}
225221

226222

@@ -242,19 +238,49 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound
242238
*/
243239
private class LifecycleMetadata {
244240

245-
private final LinkedList<LifecycleElement> initMethods = new LinkedList<LifecycleElement>();
241+
private final Set<LifecycleElement> initMethods;
242+
243+
private final Set<LifecycleElement> destroyMethods;
244+
245+
public LifecycleMetadata(Class targetClass, Collection<LifecycleElement> initMethods,
246+
Collection<LifecycleElement> destroyMethods) {
246247

247-
private final LinkedList<LifecycleElement> destroyMethods = new LinkedList<LifecycleElement>();
248+
this.initMethods = new LinkedHashSet<LifecycleElement>();
249+
for (LifecycleElement element : initMethods) {
250+
if (logger.isDebugEnabled()) {
251+
logger.debug("Found init method on class [" + targetClass.getName() + "]: " + element);
252+
}
253+
this.initMethods.add(element);
254+
}
248255

249-
public void addInitMethod(Method method) {
250-
LifecycleElement element = new LifecycleElement(method);
251-
if (!this.initMethods.contains(element)) {
252-
this.initMethods.addFirst(element);
256+
this.destroyMethods = new LinkedHashSet<LifecycleElement>();
257+
for (LifecycleElement element : destroyMethods) {
258+
if (logger.isDebugEnabled()) {
259+
logger.debug("Found destroy method on class [" + targetClass.getName() + "]: " + element);
260+
}
261+
this.destroyMethods.add(element);
253262
}
254263
}
255264

256-
public Collection<LifecycleElement> getInitMethods() {
257-
return this.initMethods;
265+
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
266+
for (Iterator<LifecycleElement> it = this.initMethods.iterator(); it.hasNext();) {
267+
String methodIdentifier = it.next().getIdentifier();
268+
if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) {
269+
beanDefinition.registerExternallyManagedInitMethod(methodIdentifier);
270+
}
271+
else {
272+
it.remove();
273+
}
274+
}
275+
for (Iterator<LifecycleElement> it = this.destroyMethods.iterator(); it.hasNext();) {
276+
String methodIdentifier = it.next().getIdentifier();
277+
if (!beanDefinition.isExternallyManagedDestroyMethod(methodIdentifier)) {
278+
beanDefinition.registerExternallyManagedDestroyMethod(methodIdentifier);
279+
}
280+
else {
281+
it.remove();
282+
}
283+
}
258284
}
259285

260286
public void invokeInitMethods(Object target, String beanName) throws Throwable {
@@ -269,17 +295,6 @@ public void invokeInitMethods(Object target, String beanName) throws Throwable {
269295
}
270296
}
271297

272-
public void addDestroyMethod(Method method) {
273-
LifecycleElement element = new LifecycleElement(method);
274-
if (!this.destroyMethods.contains(element)) {
275-
this.destroyMethods.addLast(element);
276-
}
277-
}
278-
279-
public Collection<LifecycleElement> getDestroyMethods() {
280-
return this.destroyMethods;
281-
}
282-
283298
public void invokeDestroyMethods(Object target, String beanName) throws Throwable {
284299
if (!this.destroyMethods.isEmpty()) {
285300
boolean debug = logger.isDebugEnabled();

org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,8 @@ public void run() {
162162

163163
public void destroy() {
164164
if (this.beanPostProcessors != null && !this.beanPostProcessors.isEmpty()) {
165-
for (int i = this.beanPostProcessors.size() - 1; i >= 0; i--) {
166-
this.beanPostProcessors.get(i).postProcessBeforeDestruction(this.bean, this.beanName);
165+
for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
166+
processor.postProcessBeforeDestruction(this.bean, this.beanName);
167167
}
168168
}
169169

0 commit comments

Comments
 (0)