alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Spring Framework example source code file (InitDestroyAnnotationBeanPostProcessor.java)

This example Spring Framework source code file (InitDestroyAnnotationBeanPostProcessor.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Spring Framework tags/keywords

annotation, annotation, beancreationexception, beansexception, class, io, lifecycleelement, lifecycleelement, lifecyclemetadata, lifecyclemetadata, object, reflection, set, string, string, threading, threads, throwable, throwable, util

The Spring Framework InitDestroyAnnotationBeanPostProcessor.java source code

/*
 * Copyright 2002-2008 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.beans.factory.annotation;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.util.ReflectionUtils;

/**
 * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
 * that invokes annotated init and destroy methods. Allows for an annotation
 * alternative to Spring's {@link org.springframework.beans.factory.InitializingBean}
 * and {@link org.springframework.beans.factory.DisposableBean} callback interfaces.
 *
 * <p>The actual annotation types that this post-processor checks for can be
 * configured through the {@link #setInitAnnotationType "initAnnotationType"}
 * and {@link #setDestroyAnnotationType "destroyAnnotationType"} properties.
 * Any custom annotation can be used, since there are no required annotation
 * attributes.
 *
 * <p>Init and destroy annotations may be applied to methods of any visibility:
 * public, package-protected, protected, or private. Multiple such methods
 * may be annotated, but it is recommended to only annotate one single
 * init method and destroy method, respectively.
 *
 * <p>Spring's {@link org.springframework.context.annotation.CommonAnnotationBeanPostProcessor}
 * supports the JSR-250 {@link javax.annotation.PostConstruct} and {@link javax.annotation.PreDestroy}
 * annotations out of the box, as init annotation and destroy annotation, respectively.
 * Furthermore, it also supports the {@link javax.annotation.Resource} annotation
 * for annotation-driven injection of named beans.
 *
 * @author Juergen Hoeller
 * @since 2.5
 * @see #setInitAnnotationType
 * @see #setDestroyAnnotationType
 * @see org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
 */
public class InitDestroyAnnotationBeanPostProcessor
		implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {

	/** Logger available to subclasses */
	protected final Log logger = LogFactory.getLog(getClass());

	private Class<? extends Annotation> initAnnotationType;

	private Class<? extends Annotation> destroyAnnotationType;

	private int order = Ordered.LOWEST_PRECEDENCE - 1;

	private transient final Map<Class lifecycleMetadataCache =
			new ConcurrentHashMap<Class();


	/**
	 * Specify the init annotation to check for, indicating initialization
	 * methods to call after configuration of a bean.
	 * <p>Any custom annotation can be used, since there are no required
	 * annotation attributes. There is no default, although a typical choice
	 * is the JSR-250 {@link javax.annotation.PostConstruct} annotation.
	 */
	public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
		this.initAnnotationType = initAnnotationType;
	}

	/**
	 * Specify the destroy annotation to check for, indicating destruction
	 * methods to call when the context is shutting down.
	 * <p>Any custom annotation can be used, since there are no required
	 * annotation attributes. There is no default, although a typical choice
	 * is the JSR-250 {@link javax.annotation.PreDestroy} annotation.
	 */
	public void setDestroyAnnotationType(Class<? extends Annotation> destroyAnnotationType) {
		this.destroyAnnotationType = destroyAnnotationType;
	}

	public void setOrder(int order) {
	  this.order = order;
	}

	public int getOrder() {
	  return this.order;
	}


	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) {
		if (beanType != null) {
			LifecycleMetadata metadata = findLifecycleMetadata(beanType);
			for (Iterator<LifecycleElement> it = metadata.getInitMethods().iterator(); it.hasNext();) {
				String methodName = it.next().getMethod().getName();
				if (!beanDefinition.isExternallyManagedInitMethod(methodName)) {
					beanDefinition.registerExternallyManagedInitMethod(methodName);
				}
				else {
					it.remove();
				}
			}
			for (Iterator<LifecycleElement> it = metadata.getDestroyMethods().iterator(); it.hasNext();) {
				String methodName = it.next().getMethod().getName();
				if (!beanDefinition.isExternallyManagedDestroyMethod(methodName)) {
					beanDefinition.registerExternallyManagedDestroyMethod(methodName);
				}
				else {
					it.remove();
				}
			}
		}
	}

	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
		try {
			metadata.invokeInitMethods(bean, beanName);
		}
		catch (InvocationTargetException ex) {
			throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Couldn't invoke init method", ex);
		}
		return bean;
	}

	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
		LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
		try {
			metadata.invokeDestroyMethods(bean, beanName);
		}
		catch (InvocationTargetException ex) {
			String msg = "Invocation of destroy method failed on bean with name '" + beanName + "'";
			if (logger.isDebugEnabled()) {
				logger.warn(msg, ex.getTargetException());
			}
			else {
				logger.warn(msg + ": " + ex.getTargetException());
			}
		}
		catch (Throwable ex) {
			logger.error("Couldn't invoke destroy method on bean with name '" + beanName + "'", ex);
		}
	}


	private LifecycleMetadata findLifecycleMetadata(Class clazz) {
		if (this.lifecycleMetadataCache == null) {
			// Happens after deserialization, during destruction...
			return buildLifecycleMetadata(clazz);
		}
		// Quick check on the concurrent map first, with minimal locking.
		LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
		if (metadata == null) {
			synchronized (this.lifecycleMetadataCache) {
				metadata = this.lifecycleMetadataCache.get(clazz);
				if (metadata == null) {
					metadata = buildLifecycleMetadata(clazz);
					this.lifecycleMetadataCache.put(clazz, metadata);
				}
				return metadata;
			}
		}
		return metadata;
	}

	private LifecycleMetadata buildLifecycleMetadata(final Class clazz) {
		final LifecycleMetadata newMetadata = new LifecycleMetadata();
		final boolean debug = logger.isDebugEnabled();
		ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() {
			public void doWith(Method method) {
				if (initAnnotationType != null) {
					if (method.getAnnotation(initAnnotationType) != null) {
						newMetadata.addInitMethod(method);
						if (debug) {
							logger.debug("Found init method on class [" + clazz.getName() + "]: " + method);
						}
					}
				}
				if (destroyAnnotationType != null) {
					if (method.getAnnotation(destroyAnnotationType) != null) {
						newMetadata.addDestroyMethod(method);
						if (debug) {
							logger.debug("Found destroy method on class [" + clazz.getName() + "]: " + method);
						}
					}
				}
			}
		});
		return newMetadata;
	}


	/**
	 * Class representing information about annotated init and destroy methods.
	 */
	private class LifecycleMetadata {

		private final Set<LifecycleElement> initMethods = new LinkedHashSet();

		private final Set<LifecycleElement> destroyMethods = new LinkedHashSet();

		public void addInitMethod(Method method) {
			this.initMethods.add(new LifecycleElement(method));
		}

		public Set<LifecycleElement> getInitMethods() {
			return this.initMethods;
		}

		public void invokeInitMethods(Object target, String beanName) throws Throwable {
			if (!this.initMethods.isEmpty()) {
				boolean debug = logger.isDebugEnabled();
				for (LifecycleElement element : this.initMethods) {
					if (debug) {
						logger.debug("Invoking init method on bean '" + beanName + "': " + element.getMethod());
					}
					element.invoke(target);
				}
			}
		}

		public void addDestroyMethod(Method method) {
			this.destroyMethods.add(new LifecycleElement(method));
		}

		public Set<LifecycleElement> getDestroyMethods() {
			return this.destroyMethods;
		}

		public void invokeDestroyMethods(Object target, String beanName) throws Throwable {
			if (!this.destroyMethods.isEmpty()) {
				boolean debug = logger.isDebugEnabled();
				for (LifecycleElement element : this.destroyMethods) {
					if (debug) {
						logger.debug("Invoking destroy method on bean '" + beanName + "': " + element.getMethod());
					}
					element.invoke(target);
				}
			}
		}
	}


	/**
	 * Class representing injection information about an annotated method.
	 */
	private static class LifecycleElement {

		private final Method method;

		public LifecycleElement(Method method) {
			if (method.getParameterTypes().length != 0) {
				throw new IllegalStateException("Lifecycle method annotation requires a no-arg method: " + method);
			}
			this.method = method;
		}

		public Method getMethod() {
			return this.method;
		}

		public void invoke(Object target) throws Throwable {
			ReflectionUtils.makeAccessible(this.method);
			this.method.invoke(target, (Object[]) null);
		}

		public boolean equals(Object other) {
			return (this == other || (other instanceof LifecycleElement &&
					this.method.getName().equals(((LifecycleElement) other).method.getName())));
		}

		public int hashCode() {
			return this.method.getName().hashCode();
		}
	}

}

Other Spring Framework examples (source code examples)

Here is a short list of links related to this Spring Framework InitDestroyAnnotationBeanPostProcessor.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.