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.Serializable; 020 021import org.apache.commons.logging.Log; 022import org.apache.commons.logging.LogFactory; 023 024import org.springframework.aop.TargetSource; 025import org.springframework.beans.factory.BeanFactory; 026import org.springframework.beans.factory.BeanFactoryAware; 027import org.springframework.util.ObjectUtils; 028 029/** 030 * Base class for {@link org.springframework.aop.TargetSource} implementations 031 * that are based on a Spring {@link org.springframework.beans.factory.BeanFactory}, 032 * delegating to Spring-managed bean instances. 033 * 034 * <p>Subclasses can create prototype instances or lazily access a 035 * singleton target, for example. See {@link LazyInitTargetSource} and 036 * {@link AbstractPrototypeBasedTargetSource}'s subclasses for concrete strategies. 037 * 038 * <p>BeanFactory-based TargetSources are serializable. This involves 039 * disconnecting the current target and turning into a {@link SingletonTargetSource}. 040 * 041 * @author Juergen Hoeller 042 * @author Rod Johnson 043 * @since 1.1.4 044 * @see org.springframework.beans.factory.BeanFactory#getBean 045 * @see LazyInitTargetSource 046 * @see PrototypeTargetSource 047 * @see ThreadLocalTargetSource 048 * @see CommonsPool2TargetSource 049 */ 050public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSource, BeanFactoryAware, Serializable { 051 052 /** use serialVersionUID from Spring 1.2.7 for interoperability. */ 053 private static final long serialVersionUID = -4721607536018568393L; 054 055 056 /** Logger available to subclasses. */ 057 protected final Log logger = LogFactory.getLog(getClass()); 058 059 /** Name of the target bean we will create on each invocation. */ 060 private String targetBeanName; 061 062 /** Class of the target. */ 063 private volatile Class<?> targetClass; 064 065 /** 066 * BeanFactory that owns this TargetSource. We need to hold onto this 067 * reference so that we can create new prototype instances as necessary. 068 */ 069 private BeanFactory beanFactory; 070 071 072 /** 073 * Set the name of the target bean in the factory. 074 * <p>The target bean should not be a singleton, else the same instance will 075 * always be obtained from the factory, resulting in the same behavior as 076 * provided by {@link SingletonTargetSource}. 077 * @param targetBeanName name of the target bean in the BeanFactory 078 * that owns this interceptor 079 * @see SingletonTargetSource 080 */ 081 public void setTargetBeanName(String targetBeanName) { 082 this.targetBeanName = targetBeanName; 083 } 084 085 /** 086 * Return the name of the target bean in the factory. 087 */ 088 public String getTargetBeanName() { 089 return this.targetBeanName; 090 } 091 092 /** 093 * Specify the target class explicitly, to avoid any kind of access to the 094 * target bean (for example, to avoid initialization of a FactoryBean instance). 095 * <p>Default is to detect the type automatically, through a {@code getType} 096 * call on the BeanFactory (or even a full {@code getBean} call as fallback). 097 */ 098 public void setTargetClass(Class<?> targetClass) { 099 this.targetClass = targetClass; 100 } 101 102 /** 103 * Set the owning BeanFactory. We need to save a reference so that we can 104 * use the {@code getBean} method on every invocation. 105 */ 106 @Override 107 public void setBeanFactory(BeanFactory beanFactory) { 108 if (this.targetBeanName == null) { 109 throw new IllegalStateException("Property 'targetBeanName' is required"); 110 } 111 this.beanFactory = beanFactory; 112 } 113 114 /** 115 * Return the owning BeanFactory. 116 */ 117 public BeanFactory getBeanFactory() { 118 return this.beanFactory; 119 } 120 121 122 @Override 123 public Class<?> getTargetClass() { 124 Class<?> targetClass = this.targetClass; 125 if (targetClass != null) { 126 return targetClass; 127 } 128 synchronized (this) { 129 // Full check within synchronization, entering the BeanFactory interaction algorithm only once... 130 targetClass = this.targetClass; 131 if (targetClass == null && this.beanFactory != null) { 132 // Determine type of the target bean. 133 targetClass = this.beanFactory.getType(this.targetBeanName); 134 if (targetClass == null) { 135 if (logger.isTraceEnabled()) { 136 logger.trace("Getting bean with name '" + this.targetBeanName + "' for type determination"); 137 } 138 Object beanInstance = this.beanFactory.getBean(this.targetBeanName); 139 targetClass = beanInstance.getClass(); 140 } 141 this.targetClass = targetClass; 142 } 143 return targetClass; 144 } 145 } 146 147 @Override 148 public boolean isStatic() { 149 return false; 150 } 151 152 @Override 153 public void releaseTarget(Object target) throws Exception { 154 // Nothing to do here. 155 } 156 157 158 /** 159 * Copy configuration from the other AbstractBeanFactoryBasedTargetSource object. 160 * Subclasses should override this if they wish to expose it. 161 * @param other object to copy configuration from 162 */ 163 protected void copyFrom(AbstractBeanFactoryBasedTargetSource other) { 164 this.targetBeanName = other.targetBeanName; 165 this.targetClass = other.targetClass; 166 this.beanFactory = other.beanFactory; 167 } 168 169 170 @Override 171 public boolean equals(Object other) { 172 if (this == other) { 173 return true; 174 } 175 if (other == null || getClass() != other.getClass()) { 176 return false; 177 } 178 AbstractBeanFactoryBasedTargetSource otherTargetSource = (AbstractBeanFactoryBasedTargetSource) other; 179 return (ObjectUtils.nullSafeEquals(this.beanFactory, otherTargetSource.beanFactory) && 180 ObjectUtils.nullSafeEquals(this.targetBeanName, otherTargetSource.targetBeanName)); 181 } 182 183 @Override 184 public int hashCode() { 185 int hashCode = getClass().hashCode(); 186 hashCode = 13 * hashCode + ObjectUtils.nullSafeHashCode(this.beanFactory); 187 hashCode = 13 * hashCode + ObjectUtils.nullSafeHashCode(this.targetBeanName); 188 return hashCode; 189 } 190 191 @Override 192 public String toString() { 193 StringBuilder sb = new StringBuilder(getClass().getSimpleName()); 194 sb.append(" for target bean '").append(this.targetBeanName).append("'"); 195 if (this.targetClass != null) { 196 sb.append(" of type [").append(this.targetClass.getName()).append("]"); 197 } 198 return sb.toString(); 199 } 200 201}