Spring中創建對象的方式整理


在沒有使用Spring時,開發者創建對象一般都是使用new/反射創建對象;Spring出來后簡化了開發方式,它提供了一個IoC容器的實現,用於幫助開發者以依賴注入的方式管理對象之間的依賴關系,從而將開發者創建對象的所有權轉移到IoC容器上,這使得Spring易於整合第三方模塊,因此Spring更是一個分層的框架;

 

對於Spring創建對象的方式創建整理如下:

方式一:自定義BeanPostProcessor,生成代理對象

如實現InstantiationAwareBeanPostProcessor接口,其中InstantiationAwareBeanPostProcessor是一個BeanPostProcessor,它可用於處理bean實例創建前后的回調;

 

測試如下:

@Test
public void instantiationAwareBeanPostProcessorTest() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

    GenericBeanDefinition definition1 = new GenericBeanDefinition();
    definition1.setBeanClass(DemoInstantiationAwareBPP.class);
    context.registerBeanDefinition("demoInstantiationAwareBPP", definition1);

    GenericBeanDefinition definition2 = new GenericBeanDefinition();
    definition2.setBeanClass(InstantiationDemo.class);
    context.registerBeanDefinition("instantiationDemo", definition2);

    context.refresh();
    InstantiationDemo bean = context.getBean(InstantiationDemo.class);
    bean.invoke();
}

  

public class DemoInstantiationAwareBPP implements InstantiationAwareBeanPostProcessor {
	private final static Log LOG = LogFactory.getLog(DemoInstantiationAwareBPP.class);

	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		LOG.info("beanName:" + beanName + "執行postProcessBeforeInstantiation方法");
		// 使用cglib生成代理對象
		if (beanClass == InstantiationDemo.class) {
			Enhancer enhancer = new Enhancer();
			enhancer.setSuperclass(beanClass);
			enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
				boolean objFlag = method.getDeclaringClass().getName().equals("java.lang.Object");
				if (!objFlag) {

					LOG.info("執行方法" + method + "前");
					Object rtn = methodProxy.invokeSuper(o, objects);
					LOG.info("執行方法" + method + "后");
					return rtn;
				} else {
					return methodProxy.invokeSuper(o, objects);
				}
			});
			InstantiationDemo bean = (InstantiationDemo) enhancer.create();
			LOG.info("創建代理對象:" + bean);
			return bean;
		}

		return null;
	}

	@Override
	public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		LOG.info("beanName:" + beanName + "執行postProcessAfterInstantiation方法");
		return false;
	}
}

 

public class InstantiationDemo {
	private final static Log LOG = LogFactory.getLog(InstantiationDemo.class);
	public void invoke() {
		LOG.info(this);
		LOG.info("InstantiationDemo invoke");
	}
}

  

 

注:

MethodProxy#invokeSuper是退出當前interceptor的處理,進入下一個callback處理;

MethodProxy#invoke則會繼續回調該方法,如果傳遞給invoke的obj參數出錯容易造成遞歸調用;

 

方式二:通過反射創建

AbstractAutowireCapableBeanFactory#doCreateBean為真正創建bean的邏輯,該方法是最復雜的,包含了調用構造函數,給bean的屬性賦值,調用bean的初始化操作以及生成代理對象;

該方法會調用AbstractAutowireCapableBeanFactory#createBeanInstance實例化對象,如下圖;

 

AbstractAutowireCapableBeanFactory#createBeanInstance

判斷Bean定義信息中的resolvedConstructorOrFactoryMethod是否緩存,因為需要根據參數確認到底使用哪個構造器,該過程比較消耗性能,所以采用緩存機制;

 

通過bean的后置處理器進行獲取合適的構造器對象,有且只有一個有參構造或有且只有一個@Autowired注解構造;

 

創建對象方式

AbstractAutowireCapableBeanFactory#createBeanInstance根據@Autowried自動注入/調用無參構造器創建,進行相應的處理;

  • instantiateBean 調用無參數的構造器進行創建對象;
  • autowireConstructor @Autowired自動注入,調用構造器注入;

 

方式三:通過FactoryBean創建對象

AbstractBeanFactory#getObjectForBeanInstance

如果有實現了FactoryBean接口的實例,則從FactoryBean中獲取實例;

 

測試如下:
@Test
public void mainTest13() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
            MainConfig10.class);
 
    System.out.println("IOC容器創建完成...");
 
    // 調用FactoryBean#getBean方法,入參為Bean id,得到的對象為FactoryBean#getObjectType的對象
    // FactoryBean要獲取工廠Bean本身,需要在id前加個&
    // org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance
    Object factoryBean1 = context.getBean("demoFactoryBean");
    Object factoryBean2 = context.getBean("demoFactoryBean");
    System.out.println("factoryBean1==factoryBean2 :" + (factoryBean1 == factoryBean2));
    System.out.println("bean的類型:" + factoryBean1.getClass());
 
    Object factoryBean3 = context.getBean("&demoFactoryBean");
    System.out.println("bean的類型:" + factoryBean3.getClass());
}

  

@Configuration
public class MainConfig10 {
    @Bean
    public DemoFactoryBean demoFactoryBean() {
        return new DemoFactoryBean();
    }
}

  

public class DemoFactoryBean implements FactoryBean<Person> {
 
    /**
     * 是否單例進行控制
     * @return
     */
    @Override
    public boolean isSingleton() {
        return true;
    }
 
    /**
     * 返回對象,把對象放到容器中
     * @return
     * @throws Exception
     */
    @Override
    public Person getObject() throws Exception {
        return new Person();
    }
 
    /**
     * 返回對象類型
     * @return
     */
    @Override
    public Class<?> getObjectType() {
        return Person.class;
    }
}

  

 

方式四:通過設置BeanDefinition屬性Supplier創建對象

AbstractAutowireCapableBeanFactory#createBeanInstance

獲取bean的supplier; 

 

AbstractAutowireCapableBeanFactory#obtainFromSupplier

通過Suupplier#get方法獲取實例,此時獲取實例不是使用反射; 

 

測試如下:

@Test
public void supplierTest() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

    GenericBeanDefinition definition = new GenericBeanDefinition();
    definition.setBeanClass(BeanC.class);
    definition.setInstanceSupplier((Supplier<BeanC>) BeanC::new);

    context.registerBeanDefinition("beanC", definition);
    context.refresh();
    Assertions.assertNotNull(context.getBean("beanC"));
}

  

public class BeanC {
	private final static Log LOG = LogFactory.getLog(BeanC.class);

	public BeanC() {
		LOG.info("BeanC constructor");
	}
}

  

 

方式五:通過設置BeanDefinition屬性factoryMethod創建對象

AbstractAutowireCapableBeanFactory#createBeanInstance

createBeanInstance是實例化對象的過程,如果beanDefinition設置了factoryMethod,則從設置的factoryMethod實例化,而supplier屬性的優先級高於factoryMethod即beanDefinition同時存在supplier和factoryMethod屬性時,優先執行supplier的實例化邏輯

 

mbd的factoryMethodNameBeanDefiniton加載時賦值的,如下: 

ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod

 

factoryMethod使用方式:往beanDefinition設置factoryMethod所屬類的beanNamefactoryMethodName的屬性;

使用factoryMethod實例化對象的解析邏輯:ConstructorResolver#instantiateUsingFactoryMethod

 

SimpleInstantiationStrategy最終通過對factoryBean反射調用factoryMethod;

 

 

測試如下:

beanDefinition只有factoryMethod屬性

public class FactoryDemo {
	private final static Log LOG = LogFactory.getLog(FactoryDemo.class);
	private int num;
	private String msg;

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	public FactoryDemo() {
		LOG.info("FactoryDemo no params constructor");
	}

	public BeanDemo create() {
		BeanDemo beanDemo = new BeanDemo();
		LOG.info("invoke create without args,beanDemo:" + beanDemo);
		return beanDemo;
	}

	public BeanDemo create(int num, String msg) {
		BeanDemo beanDemo = new BeanDemo();
		beanDemo.setMsg(msg);
		beanDemo.setNum(num);
		LOG.info("invoke create with args,beanDemo:" + "[" + beanDemo + "]" + beanDemo.getMsg() + "," + beanDemo.getNum());
		return beanDemo;
	}
}

  

public class BeanDemo {
	private final static Log LOG = LogFactory.getLog(BeanDemo.class);

	private int num;
	private String msg;

	public BeanDemo() {
		LOG.info("BeanDemo constructor");
	}

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}
} 
 
調用無參的factoryMethod
@Test
public void factoryBeanNameTestWithoutArgs() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(FactoryDemo.class);

    GenericBeanDefinition definition = new GenericBeanDefinition();
    // 設置factoryBean
    definition.setFactoryBeanName("factoryDemo");
    definition.setFactoryMethodName("create");

    definition.setBeanClass(BeanDemo.class);
    context.registerBeanDefinition("beanDemo", definition);
    context.refresh();

    System.out.println(context.getBean(BeanDemo.class));
}

  

 

調用有參factoryMethod
@Test
public void factoryBeanNameWithArgsTest() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(FactoryDemo.class);

    GenericBeanDefinition definition = new GenericBeanDefinition();
    // 設置factoryBean
    definition.setFactoryBeanName("factoryDemo");
    definition.setFactoryMethodName("create");

    ConstructorArgumentValues argumentValues = new ConstructorArgumentValues();
    argumentValues.addGenericArgumentValue("test", "java.lang.String");
    argumentValues.addGenericArgumentValue(1, "int");
    definition.setConstructorArgumentValues(argumentValues);

    definition.setBeanClass(BeanDemo.class);
    context.registerBeanDefinition("beanDemo", definition);
    context.refresh();

    System.out.println(context.getBean(BeanDemo.class));
}

  

 

beanDefinition有factoryMethod屬性和supplier屬性

@Test
public void supplierOrderTest() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(FactoryDemo.class);

    GenericBeanDefinition definition = new GenericBeanDefinition();
    // 設置factoryBean
    definition.setFactoryBeanName("factoryDemo");
    definition.setFactoryMethodName("create");

    definition.setBeanClass(BeanDemo.class);
    context.registerBeanDefinition("beanDemo", definition);
    definition.setInstanceSupplier((Supplier<BeanDemo>) BeanDemo::new);

    context.refresh();
    Assertions.assertNotNull(context.getBean("beanDemo"));
}

 

此時優先執行supplier邏輯;

 

Spring創建對象方式的整理圖

 

 

Spring實例化策略整理

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM