001/* 002 * Copyright 2002-2016 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.beans.factory.support; 018 019import java.lang.reflect.Constructor; 020import java.lang.reflect.InvocationTargetException; 021import java.lang.reflect.Method; 022import java.security.AccessController; 023import java.security.PrivilegedAction; 024import java.security.PrivilegedExceptionAction; 025 026import org.springframework.beans.BeanInstantiationException; 027import org.springframework.beans.BeanUtils; 028import org.springframework.beans.factory.BeanFactory; 029import org.springframework.beans.factory.config.ConfigurableBeanFactory; 030import org.springframework.util.ReflectionUtils; 031import org.springframework.util.StringUtils; 032 033/** 034 * Simple object instantiation strategy for use in a BeanFactory. 035 * 036 * <p>Does not support Method Injection, although it provides hooks for subclasses 037 * to override to add Method Injection support, for example by overriding methods. 038 * 039 * @author Rod Johnson 040 * @author Juergen Hoeller 041 * @since 1.1 042 */ 043public class SimpleInstantiationStrategy implements InstantiationStrategy { 044 045 private static final ThreadLocal<Method> currentlyInvokedFactoryMethod = new ThreadLocal<Method>(); 046 047 048 /** 049 * Return the factory method currently being invoked or {@code null} if none. 050 * <p>Allows factory method implementations to determine whether the current 051 * caller is the container itself as opposed to user code. 052 */ 053 public static Method getCurrentlyInvokedFactoryMethod() { 054 return currentlyInvokedFactoryMethod.get(); 055 } 056 057 058 @Override 059 public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) { 060 // Don't override the class with CGLIB if no overrides. 061 if (bd.getMethodOverrides().isEmpty()) { 062 Constructor<?> constructorToUse; 063 synchronized (bd.constructorArgumentLock) { 064 constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod; 065 if (constructorToUse == null) { 066 final Class<?> clazz = bd.getBeanClass(); 067 if (clazz.isInterface()) { 068 throw new BeanInstantiationException(clazz, "Specified class is an interface"); 069 } 070 try { 071 if (System.getSecurityManager() != null) { 072 constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() { 073 @Override 074 public Constructor<?> run() throws Exception { 075 return clazz.getDeclaredConstructor((Class[]) null); 076 } 077 }); 078 } 079 else { 080 constructorToUse = clazz.getDeclaredConstructor((Class[]) null); 081 } 082 bd.resolvedConstructorOrFactoryMethod = constructorToUse; 083 } 084 catch (Throwable ex) { 085 throw new BeanInstantiationException(clazz, "No default constructor found", ex); 086 } 087 } 088 } 089 return BeanUtils.instantiateClass(constructorToUse); 090 } 091 else { 092 // Must generate CGLIB subclass. 093 return instantiateWithMethodInjection(bd, beanName, owner); 094 } 095 } 096 097 /** 098 * Subclasses can override this method, which is implemented to throw 099 * UnsupportedOperationException, if they can instantiate an object with 100 * the Method Injection specified in the given RootBeanDefinition. 101 * Instantiation should use a no-arg constructor. 102 */ 103 protected Object instantiateWithMethodInjection(RootBeanDefinition bd, String beanName, BeanFactory owner) { 104 throw new UnsupportedOperationException("Method Injection not supported in SimpleInstantiationStrategy"); 105 } 106 107 @Override 108 public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner, 109 final Constructor<?> ctor, Object... args) { 110 111 if (bd.getMethodOverrides().isEmpty()) { 112 if (System.getSecurityManager() != null) { 113 // use own privileged to change accessibility (when security is on) 114 AccessController.doPrivileged(new PrivilegedAction<Object>() { 115 @Override 116 public Object run() { 117 ReflectionUtils.makeAccessible(ctor); 118 return null; 119 } 120 }); 121 } 122 return BeanUtils.instantiateClass(ctor, args); 123 } 124 else { 125 return instantiateWithMethodInjection(bd, beanName, owner, ctor, args); 126 } 127 } 128 129 /** 130 * Subclasses can override this method, which is implemented to throw 131 * UnsupportedOperationException, if they can instantiate an object with 132 * the Method Injection specified in the given RootBeanDefinition. 133 * Instantiation should use the given constructor and parameters. 134 */ 135 protected Object instantiateWithMethodInjection(RootBeanDefinition bd, String beanName, BeanFactory owner, 136 Constructor<?> ctor, Object... args) { 137 138 throw new UnsupportedOperationException("Method Injection not supported in SimpleInstantiationStrategy"); 139 } 140 141 @Override 142 public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner, 143 Object factoryBean, final Method factoryMethod, Object... args) { 144 145 try { 146 if (System.getSecurityManager() != null) { 147 AccessController.doPrivileged(new PrivilegedAction<Object>() { 148 @Override 149 public Object run() { 150 ReflectionUtils.makeAccessible(factoryMethod); 151 return null; 152 } 153 }); 154 } 155 else { 156 ReflectionUtils.makeAccessible(factoryMethod); 157 } 158 159 Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get(); 160 try { 161 currentlyInvokedFactoryMethod.set(factoryMethod); 162 return factoryMethod.invoke(factoryBean, args); 163 } 164 finally { 165 if (priorInvokedFactoryMethod != null) { 166 currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod); 167 } 168 else { 169 currentlyInvokedFactoryMethod.remove(); 170 } 171 } 172 } 173 catch (IllegalArgumentException ex) { 174 throw new BeanInstantiationException(factoryMethod, 175 "Illegal arguments to factory method '" + factoryMethod.getName() + "'; " + 176 "args: " + StringUtils.arrayToCommaDelimitedString(args), ex); 177 } 178 catch (IllegalAccessException ex) { 179 throw new BeanInstantiationException(factoryMethod, 180 "Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex); 181 } 182 catch (InvocationTargetException ex) { 183 String msg = "Factory method '" + factoryMethod.getName() + "' threw exception"; 184 if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory && 185 ((ConfigurableBeanFactory) owner).isCurrentlyInCreation(bd.getFactoryBeanName())) { 186 msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " + 187 "declaring the factory method as static for independence from its containing instance. " + msg; 188 } 189 throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException()); 190 } 191 } 192 193}