在沒有使用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的factoryMethodName在BeanDefiniton加載時賦值的,如下:
ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod
factoryMethod使用方式:往beanDefinition設置factoryMethod所屬類的beanName和factoryMethodName的屬性;
使用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實例化策略整理