工厂方法获取对象。同时也是 @Bean 注解的处理。

代码示例

  1. if (mbd.getFactoryMethodName() != null) {
  2. return instantiateUsingFactoryMethod(beanName, mbd, args);
  3. }

工厂模式创建实例中,工厂主要有两种:

  • 静态工厂(无需工厂的实例对象)
  • 实例工厂(需要创建工厂的实例对象)

测试bean

  1. package cn.lichenghao.entity;
  2. public class Dog {
  3. private String name;
  4. private Integer age;
  5. public Dog() {
  6. System.out.println("Dog init!!");
  7. }
  8. public Dog(String name, Integer age) {
  9. System.out.println("Dog init!!");
  10. this.name = name;
  11. this.age = age;
  12. }
  13. public void say(){
  14. System.out.println("wwwwwwwww");
  15. }
  16. public String getName() {
  17. return name;
  18. }
  19. public void setName(String name) {
  20. this.name = name;
  21. }
  22. public Integer getAge() {
  23. return age;
  24. }
  25. public void setAge(Integer age) {
  26. this.age = age;
  27. }
  28. }
  1. package cn.lichenghao.entity;
  2. public class Cat extends Animal {
  3. private String name;
  4. private Integer age;
  5. public Cat() {
  6. }
  7. public Cat(String name, Integer age) {
  8. super();
  9. this.name = name;
  10. this.age = age;
  11. }
  12. public String getName() {
  13. return name;
  14. }
  15. public void setName(String name) {
  16. this.name = name;
  17. }
  18. public Integer getAge() {
  19. return age;
  20. }
  21. public void setAge(Integer age) {
  22. this.age = age;
  23. }
  24. }

工厂

  1. public class CatInstanceFactory {
  2. public Cat getCat(String name, int age) {
  3. Cat cat = new Cat();
  4. cat.setName(name);
  5. cat.setAge(age);
  6. return cat;
  7. }
  8. }
  1. public class DogStaticFactory {
  2. public static Dog getDog(String name, int age) {
  3. Dog dog = new Dog();
  4. dog.setName(name);
  5. dog.setAge(age);
  6. return dog;
  7. }
  8. }

加入 IOC 容器

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans
  3. xmlns="http://www.springframework.org/schema/beans"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
  7. <bean id="catA" class="cn.lichenghao.entity.Cat" factory-bean="catInstanceFactory" factory-method="getCat">
  8. <constructor-arg name="name" value="11"></constructor-arg>
  9. <constructor-arg name="age" value="11"></constructor-arg>
  10. </bean>
  11. <bean id="catInstanceFactory" class="cn.lichenghao.factory.CatInstanceFactory"/>
  12. <bean id="dogA" class="cn.lichenghao.factory.DogStaticFactory" factory-method="getDog">
  13. <constructor-arg name="name" value="22"></constructor-arg>
  14. <constructor-arg name="age" value="22"></constructor-arg>
  15. </bean>
  16. </beans>

测试

  1. @DisplayName("测试factoryMethod")
  2. @Test
  3. public void factoryMethodTest() {
  4. ClassPathXmlApplicationContext classPathXmlApplicationContext
  5. = new ClassPathXmlApplicationContext("factory-method.xml");
  6. Cat cat = classPathXmlApplicationContext.getBean(Cat.class);
  7. System.out.println(cat);
  8. Dog dog = classPathXmlApplicationContext.getBean(Dog.class);
  9. System.out.println(dog);
  10. }

有了工厂后,就会进入方法

  1. protected BeanWrapper instantiateUsingFactoryMethod(
  2. String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
  3. return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
  4. }

继而进入方法
org.springframework.beans.factory.support.ConstructorResolver#instantiateUsingFactoryMethod

  1. public BeanWrapper instantiateUsingFactoryMethod(
  2. String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
  3. BeanWrapperImpl bw = new BeanWrapperImpl();
  4. this.beanFactory.initBeanWrapper(bw);
  5. Object factoryBean;
  6. Class<?> factoryClass;
  7. boolean isStatic;
  8. String factoryBeanName = mbd.getFactoryBeanName();
  9. if (factoryBeanName != null) {
  10. if (factoryBeanName.equals(beanName)) {
  11. throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
  12. "factory-bean reference points back to the same bean definition");
  13. }
  14. factoryBean = this.beanFactory.getBean(factoryBeanName);
  15. if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
  16. throw new ImplicitlyAppearedSingletonException();
  17. }
  18. this.beanFactory.registerDependentBean(factoryBeanName, beanName);
  19. factoryClass = factoryBean.getClass();
  20. isStatic = false;
  21. }
  22. else {
  23. // It's a static factory method on the bean class.
  24. if (!mbd.hasBeanClass()) {
  25. throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
  26. "bean definition declares neither a bean class nor a factory-bean reference");
  27. }
  28. factoryBean = null;
  29. factoryClass = mbd.getBeanClass();
  30. isStatic = true;
  31. }
  32. Method factoryMethodToUse = null;
  33. ArgumentsHolder argsHolderToUse = null;
  34. Object[] argsToUse = null;
  35. if (explicitArgs != null) {
  36. argsToUse = explicitArgs;
  37. }
  38. else {
  39. Object[] argsToResolve = null;
  40. synchronized (mbd.constructorArgumentLock) {
  41. factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
  42. if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
  43. // Found a cached factory method...
  44. argsToUse = mbd.resolvedConstructorArguments;
  45. if (argsToUse == null) {
  46. argsToResolve = mbd.preparedConstructorArguments;
  47. }
  48. }
  49. }
  50. if (argsToResolve != null) {
  51. argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve);
  52. }
  53. }
  54. if (factoryMethodToUse == null || argsToUse == null) {
  55. // Need to determine the factory method...
  56. // Try all methods with this name to see if they match the given arguments.
  57. factoryClass = ClassUtils.getUserClass(factoryClass);
  58. List<Method> candidates = null;
  59. if (mbd.isFactoryMethodUnique) {
  60. if (factoryMethodToUse == null) {
  61. factoryMethodToUse = mbd.getResolvedFactoryMethod();
  62. }
  63. if (factoryMethodToUse != null) {
  64. candidates = Collections.singletonList(factoryMethodToUse);
  65. }
  66. }
  67. if (candidates == null) {
  68. candidates = new ArrayList<>();
  69. Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
  70. for (Method candidate : rawCandidates) {
  71. if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
  72. candidates.add(candidate);
  73. }
  74. }
  75. }
  76. if (candidates.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
  77. Method uniqueCandidate = candidates.get(0);
  78. if (uniqueCandidate.getParameterCount() == 0) {
  79. mbd.factoryMethodToIntrospect = uniqueCandidate;
  80. synchronized (mbd.constructorArgumentLock) {
  81. mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
  82. mbd.constructorArgumentsResolved = true;
  83. mbd.resolvedConstructorArguments = EMPTY_ARGS;
  84. }
  85. bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
  86. return bw;
  87. }
  88. }
  89. if (candidates.size() > 1) { // explicitly skip immutable singletonList
  90. candidates.sort(AutowireUtils.EXECUTABLE_COMPARATOR);
  91. }
  92. ConstructorArgumentValues resolvedValues = null;
  93. boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
  94. int minTypeDiffWeight = Integer.MAX_VALUE;
  95. Set<Method> ambiguousFactoryMethods = null;
  96. int minNrOfArgs;
  97. if (explicitArgs != null) {
  98. minNrOfArgs = explicitArgs.length;
  99. }
  100. else {
  101. // We don't have arguments passed in programmatically, so we need to resolve the
  102. // arguments specified in the constructor arguments held in the bean definition.
  103. if (mbd.hasConstructorArgumentValues()) {
  104. ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
  105. resolvedValues = new ConstructorArgumentValues();
  106. minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
  107. }
  108. else {
  109. minNrOfArgs = 0;
  110. }
  111. }
  112. LinkedList<UnsatisfiedDependencyException> causes = null;
  113. for (Method candidate : candidates) {
  114. int parameterCount = candidate.getParameterCount();
  115. if (parameterCount >= minNrOfArgs) {
  116. ArgumentsHolder argsHolder;
  117. Class<?>[] paramTypes = candidate.getParameterTypes();
  118. if (explicitArgs != null) {
  119. // Explicit arguments given -> arguments length must match exactly.
  120. if (paramTypes.length != explicitArgs.length) {
  121. continue;
  122. }
  123. argsHolder = new ArgumentsHolder(explicitArgs);
  124. }
  125. else {
  126. // Resolved constructor arguments: type conversion and/or autowiring necessary.
  127. try {
  128. String[] paramNames = null;
  129. ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
  130. if (pnd != null) {
  131. paramNames = pnd.getParameterNames(candidate);
  132. }
  133. argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
  134. paramTypes, paramNames, candidate, autowiring, candidates.size() == 1);
  135. }
  136. catch (UnsatisfiedDependencyException ex) {
  137. if (logger.isTraceEnabled()) {
  138. logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
  139. }
  140. // Swallow and try next overloaded factory method.
  141. if (causes == null) {
  142. causes = new LinkedList<>();
  143. }
  144. causes.add(ex);
  145. continue;
  146. }
  147. }
  148. int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
  149. argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
  150. // Choose this factory method if it represents the closest match.
  151. if (typeDiffWeight < minTypeDiffWeight) {
  152. factoryMethodToUse = candidate;
  153. argsHolderToUse = argsHolder;
  154. argsToUse = argsHolder.arguments;
  155. minTypeDiffWeight = typeDiffWeight;
  156. ambiguousFactoryMethods = null;
  157. }
  158. // Find out about ambiguity: In case of the same type difference weight
  159. // for methods with the same number of parameters, collect such candidates
  160. // and eventually raise an ambiguity exception.
  161. // However, only perform that check in non-lenient constructor resolution mode,
  162. // and explicitly ignore overridden methods (with the same parameter signature).
  163. else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
  164. !mbd.isLenientConstructorResolution() &&
  165. paramTypes.length == factoryMethodToUse.getParameterCount() &&
  166. !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
  167. if (ambiguousFactoryMethods == null) {
  168. ambiguousFactoryMethods = new LinkedHashSet<>();
  169. ambiguousFactoryMethods.add(factoryMethodToUse);
  170. }
  171. ambiguousFactoryMethods.add(candidate);
  172. }
  173. }
  174. }
  175. if (factoryMethodToUse == null || argsToUse == null) {
  176. if (causes != null) {
  177. UnsatisfiedDependencyException ex = causes.removeLast();
  178. for (Exception cause : causes) {
  179. this.beanFactory.onSuppressedException(cause);
  180. }
  181. throw ex;
  182. }
  183. List<String> argTypes = new ArrayList<>(minNrOfArgs);
  184. if (explicitArgs != null) {
  185. for (Object arg : explicitArgs) {
  186. argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
  187. }
  188. }
  189. else if (resolvedValues != null) {
  190. Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());
  191. valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
  192. valueHolders.addAll(resolvedValues.getGenericArgumentValues());
  193. for (ValueHolder value : valueHolders) {
  194. String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
  195. (value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
  196. argTypes.add(argType);
  197. }
  198. }
  199. String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
  200. throw new BeanCreationException(mbd.getResourceDescription(), beanName,
  201. "No matching factory method found on class [" + factoryClass.getName() + "]: " +
  202. (mbd.getFactoryBeanName() != null ?
  203. "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
  204. "factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
  205. "Check that a method with the specified name " +
  206. (minNrOfArgs > 0 ? "and arguments " : "") +
  207. "exists and that it is " +
  208. (isStatic ? "static" : "non-static") + ".");
  209. }
  210. else if (void.class == factoryMethodToUse.getReturnType()) {
  211. throw new BeanCreationException(mbd.getResourceDescription(), beanName,
  212. "Invalid factory method '" + mbd.getFactoryMethodName() + "' on class [" +
  213. factoryClass.getName() + "]: needs to have a non-void return type!");
  214. }
  215. else if (ambiguousFactoryMethods != null) {
  216. throw new BeanCreationException(mbd.getResourceDescription(), beanName,
  217. "Ambiguous factory method matches found on class [" + factoryClass.getName() + "] " +
  218. "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
  219. ambiguousFactoryMethods);
  220. }
  221. if (explicitArgs == null && argsHolderToUse != null) {
  222. mbd.factoryMethodToIntrospect = factoryMethodToUse;
  223. argsHolderToUse.storeCache(mbd, factoryMethodToUse);
  224. }
  225. }
  226. bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
  227. return bw;
  228. }

方法执行流程图

instantiateUsingFactoryMethod.xmind
instantiateUsingFactoryMethod.svg