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