我们先贴一下我们自己写的代码
public class Person {
private int id;
private String name;
private int age;
private String gender;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
静态工厂
public class PersonStaticFactory {
public static Person getPerson(String name){
Person person = new Person();
person.setId(1);
person.setName(name);
return person;
}
public static Person getPerson(int age){
return new Person();
}
public static Person getPerson(String name,int id){
Person person = new Person();
person.setId(1);
person.setName(name);
return person;
}
}
实例工厂
public class PersonInstanceFactory {
public Person getPerson(String name){
Person person = new Person();
person.setId(1);
person.setName(name);
return person;
}
}
测试类
public class TestFactoryMethod {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("factoryMethod.xml");
Person person = ac.getBean("person", Person.class);
System.out.println(person);
Person person2 = ac.getBean("person2", Person.class);
System.out.println(person2);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--静态工厂-->
<bean id="person" class="com.mashibing.factoryMethod.PersonStaticFactory" factory-method="getPerson">
<!--constructor-arg:可以为方法指定参数-->
<constructor-arg value="123"></constructor-arg>
</bean>
<!--实例工厂-->
<bean id="personInstanceFactory" class="com.mashibing.factoryMethod.PersonInstanceFactory"></bean>
<bean id="person2" class="com.mashibing.factoryMethod.Person" factory-bean="personInstanceFactory" factory-method="getPerson">
<constructor-arg value="wangwu"></constructor-arg>
</bean>
</beans>
在finishBeanFactoryInitialization-->createBean-->doCreateBean-->createBeanInstance
贴一下这个方法的代码
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
// 确认需要创建的bean实例的类可以实例化
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 确保class不为空,并且访问权限是public
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
// 判断当前beanDefinition中是否包含实例供应器,此处相当于一个回调方法,利用回调方法来创建bean
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// 如果工厂方法不为空则使用工厂方法初始化策略
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// 一个类可能有多个构造器,所以Spring得根据参数个数、类型确定需要调用的构造器
// 在使用构造器创建实例后,Spring会将解析过后确定下来的构造器或工厂方法保存在缓存中,避免再次创建相同bean时再次解析
// Shortcut when re-creating the same bean...
// 标记下,防止重复创建同一个bean
boolean resolved = false;
// 是否需要自动装配
boolean autowireNecessary = false;
// 如果没有参数
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
// 因为一个类可能由多个构造函数,所以需要根据配置文件中配置的参数或传入的参数来确定最终调用的构造函数。
// 因为判断过程会比较,所以spring会将解析、确定好的构造函数缓存到BeanDefinition中的resolvedConstructorOrFactoryMethod字段中。
// 在下次创建相同时直接从RootBeanDefinition中的属性resolvedConstructorOrFactoryMethod缓存的值获取,避免再次解析
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
// 有构造参数的或者工厂方法
if (resolved) {
// 构造器有参数
if (autowireNecessary) {
// 构造函数自动注入
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 使用默认构造函数构造
return instantiateBean(beanName, mbd);
}
}
// Candidate constructors for autowiring?
// 从bean后置处理器中为自动装配寻找构造方法, 有且仅有一个有参构造或者有且仅有@Autowired注解构造
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 以下情况符合其一即可进入
// 1、存在可选构造方法
// 2、自动装配模型为构造函数自动装配
// 3、给BeanDefinition中设置了构造参数值
// 4、有参与构造函数参数列表的参数
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
// 找出最合适的默认构造方法
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
// 构造函数自动注入
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
// 使用默认无参构造函数创建对象,如果没有无参构造且存在多个有参构造且没有@AutoWired注解构造,会报错
return instantiateBean(beanName, mbd);
}
走到这里
判断条件从名字可以看出,当beanDefinition的factoryMethodName不为空的时候, 执行里面操作
点进instantiateUsingFactoryMethod方法
protected BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
// 创建构造器处理器并使用factorymethod进行实例化操作
return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}
public ConstructorResolver(AbstractAutowireCapableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
this.logger = beanFactory.getLogger();
}
构造方法里面做一些赋值操作,重点看后面那个instantiateUsingFactoryMethod方法,
可以看出,①先创建并初始化包装类,②申明几个变量(后面要针对这三个变量进行操作),③获取FactoryBean名称
接下来分两种情况
①FactoryBean名称不为空
②FactoryBean名称为空
因为我们这边的这个值为空,所以进入else
三个变量的值分别为如上图所示
又申明三个变量,含义在图中的注释中
针对判断条件里面的explicitArgs值是否为空,执行不同的方法
我们这里explicitArgs=null,进到else,else里面的factoryMethodToUse为null,往下走跳
因为argsResolve为空,所以不进入,接着往下走
条件满足,进入,点进getUserClass
public static Class<?> getUserClass(Class<?> clazz) {
// 如果clazz的全类名包含'$$'字符串,表示它有可能是GGLIB生成的子类
if (clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
// 获取clazz的父类
Class<?> superclass = clazz.getSuperclass();
// 如果superclass不为null且superclass不是Object
if (superclass != null && superclass != Object.class) {
// 直接返回父类
return superclass;
}
}
// 直接返回检查类
return clazz;
}
getUserClass查看是否有子类,并返回对应的Class.我们这里还是原来传进去的类型,说明我们这个类不是动态代理实现的东西。继续往下走,运行一下这个判断条件
所以这里不进入,看一下下一个判断条件
走到getCandidateMethods,点进去
private Method[] getCandidateMethods(Class<?> factoryClass, RootBeanDefinition mbd) {
// 如果有系统安全管理器
if (System.getSecurityManager() != null) {
// 使用特权方式执行:如果mbd允许访问非公共构造函数和方法,就返回factoryClass子类和其父类的所有声明方法,首先包括子类方法;
// 否则只获取factoryClass的public级别方法
return AccessController.doPrivileged((PrivilegedAction<Method[]>) () ->
(mbd.isNonPublicAccessAllowed() ?
ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods()));
}
else {
// 如果mbd允许访问非公共构造函数和方法,就返回factoryClass子类和其父类的所有声明方法,首先包括子类方法;
// 否则只获取factoryClass的public级别方法
return (mbd.isNonPublicAccessAllowed() ?
ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods());
}
}
这里没有安全管理器,所以直接走到else
所以返回的是ReflectionUtils.getAllDeclaredMethods(factoryClass)的结果,这个方法将该类和父类 的方法都返回回来,看一下返回的方法
可以看到除了getPerson方法以外,其他方法都继承自Object方法。继续往里面走,可以看到遍历获得的方法,如果candidate的修饰符与isStatic一致且candidate有资格作为mdb的工厂方法,就将方法添加进list中。
可以看到,只有getPerson被加入list中。往下走
判断条件为false,没进去,往下走一堆判断,省略。。。
走到这里 根据权重决定使用上面三个getPerson中具体那个方法来使用
然后就将获取得到的方法存进缓存并设置进bean实例的factoryMethodToUse中.当这些东西都有之后,调用instantiate方法进行实例化。
private Object instantiate(String beanName, RootBeanDefinition mbd,
@Nullable Object factoryBean, Method factoryMethod, Object[] args) {
try {
// 如果有安全管理器
if (System.getSecurityManager() != null) {
// 使用特权方式运行:在beanFactory中返回beanName的Bean实例,并通过factoryMethod创建它
return AccessController.doPrivileged((PrivilegedAction<Object>) () ->
this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args),
this.beanFactory.getAccessControlContext());
}
else {
// 在beanFactory中返回beanName的Bean实例,并通过factoryMethod创建它
return this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args);
}
}
// 捕捉所有实例化对象过程中的异常
catch (Throwable ex) {
// 抛出BeanCreationException:通过工厂方法实例化Bean失败
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean instantiation via factory method failed", ex);
}
}
没有安全管理器,这里进入else
继续进入instantiate方法
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
@Nullable Object factoryBean, final Method factoryMethod, Object... args) {
try {
// 是否包含系统安全管理器
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(factoryMethod);
return null;
});
}
else {
// 通过反射工具类设置访问权限
ReflectionUtils.makeAccessible(factoryMethod);
}
// 获取原有的Method对象
Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
try {
// 设置当前的Method
currentlyInvokedFactoryMethod.set(factoryMethod);
// 使用factoryMethod实例化对象
Object result = factoryMethod.invoke(factoryBean, args);
if (result == null) {
result = new NullBean();
}
return result;
}
finally {
// 实例化完成后回复现场
if (priorInvokedFactoryMethod != null) {
currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
}
else {
currentlyInvokedFactoryMethod.remove();
}
}
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(factoryMethod,
"Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
"args: " + StringUtils.arrayToCommaDelimitedString(args), ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(factoryMethod,
"Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex);
}
catch (InvocationTargetException ex) {
String msg = "Factory method '" + factoryMethod.getName() + "' threw exception";
if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory &&
((ConfigurableBeanFactory) owner).isCurrentlyInCreation(bd.getFactoryBeanName())) {
msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
"declaring the factory method as static for independence from its containing instance. " + msg;
}
throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException());
}
}
在实例化中设置了访问权限,设置Factorymethod的method方法,并执行。点进factoryMethod.invoke()方法。
就调用到我们要执行的方法。最后创建好并返回包装类BeanWrapperImpl。