001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.aop.target; 018 019import java.io.IOException; 020import java.io.NotSerializableException; 021import java.io.ObjectInputStream; 022import java.io.ObjectStreamException; 023 024import org.springframework.beans.BeansException; 025import org.springframework.beans.factory.BeanDefinitionStoreException; 026import org.springframework.beans.factory.BeanFactory; 027import org.springframework.beans.factory.DisposableBean; 028import org.springframework.beans.factory.config.ConfigurableBeanFactory; 029 030/** 031 * Base class for dynamic {@link org.springframework.aop.TargetSource} implementations 032 * that create new prototype bean instances to support a pooling or 033 * new-instance-per-invocation strategy. 034 * 035 * <p>Such TargetSources must run in a {@link BeanFactory}, as it needs to 036 * call the {@code getBean} method to create a new prototype instance. 037 * Therefore, this base class extends {@link AbstractBeanFactoryBasedTargetSource}. 038 * 039 * @author Rod Johnson 040 * @author Juergen Hoeller 041 * @see org.springframework.beans.factory.BeanFactory#getBean 042 * @see PrototypeTargetSource 043 * @see ThreadLocalTargetSource 044 * @see CommonsPool2TargetSource 045 */ 046@SuppressWarnings("serial") 047public abstract class AbstractPrototypeBasedTargetSource extends AbstractBeanFactoryBasedTargetSource { 048 049 @Override 050 public void setBeanFactory(BeanFactory beanFactory) throws BeansException { 051 super.setBeanFactory(beanFactory); 052 053 // Check whether the target bean is defined as prototype. 054 if (!beanFactory.isPrototype(getTargetBeanName())) { 055 throw new BeanDefinitionStoreException( 056 "Cannot use prototype-based TargetSource against non-prototype bean with name '" + 057 getTargetBeanName() + "': instances would not be independent"); 058 } 059 } 060 061 /** 062 * Subclasses should call this method to create a new prototype instance. 063 * @throws BeansException if bean creation failed 064 */ 065 protected Object newPrototypeInstance() throws BeansException { 066 if (logger.isDebugEnabled()) { 067 logger.debug("Creating new instance of bean '" + getTargetBeanName() + "'"); 068 } 069 return getBeanFactory().getBean(getTargetBeanName()); 070 } 071 072 /** 073 * Subclasses should call this method to destroy an obsolete prototype instance. 074 * @param target the bean instance to destroy 075 */ 076 protected void destroyPrototypeInstance(Object target) { 077 if (logger.isDebugEnabled()) { 078 logger.debug("Destroying instance of bean '" + getTargetBeanName() + "'"); 079 } 080 if (getBeanFactory() instanceof ConfigurableBeanFactory) { 081 ((ConfigurableBeanFactory) getBeanFactory()).destroyBean(getTargetBeanName(), target); 082 } 083 else if (target instanceof DisposableBean) { 084 try { 085 ((DisposableBean) target).destroy(); 086 } 087 catch (Throwable ex) { 088 logger.warn("Destroy method on bean with name '" + getTargetBeanName() + "' threw an exception", ex); 089 } 090 } 091 } 092 093 094 //--------------------------------------------------------------------- 095 // Serialization support 096 //--------------------------------------------------------------------- 097 098 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { 099 throw new NotSerializableException("A prototype-based TargetSource itself is not deserializable - " + 100 "just a disconnected SingletonTargetSource or EmptyTargetSource is"); 101 } 102 103 /** 104 * Replaces this object with a SingletonTargetSource on serialization. 105 * Protected as otherwise it won't be invoked for subclasses. 106 * (The {@code writeReplace()} method must be visible to the class 107 * being serialized.) 108 * <p>With this implementation of this method, there is no need to mark 109 * non-serializable fields in this class or subclasses as transient. 110 */ 111 protected Object writeReplace() throws ObjectStreamException { 112 if (logger.isDebugEnabled()) { 113 logger.debug("Disconnecting TargetSource [" + this + "]"); 114 } 115 try { 116 // Create disconnected SingletonTargetSource/EmptyTargetSource. 117 Object target = getTarget(); 118 return (target != null ? new SingletonTargetSource(target) : 119 EmptyTargetSource.forClass(getTargetClass())); 120 } 121 catch (Exception ex) { 122 String msg = "Cannot get target for disconnecting TargetSource [" + this + "]"; 123 logger.error(msg, ex); 124 throw new NotSerializableException(msg + ": " + ex); 125 } 126 } 127 128}