Spring中创建对象的方式整理
在没有使用Spring时,开发者创建对象一般都是使用new/反射创建对象;Spring出来后简化了开发方式,它提供了一个IoC容器的实现,用于帮助开发者以依赖注入的方式管理对象之间的依赖关系,从而将开发者创建对象的所有权转移到IoC容器上,这使得Spring易于整合第三方模块,因此Spring更是一个分层的框架;
对于Spring创建对象的方式创建整理如下:#
方式一:自定义BeanPostProcessor,生成代理对象#
如实现InstantiationAwareBeanPostProcessor接口,其中InstantiationAwareBeanPostProcessor是一个BeanPostProcessor,它可用于处理bean实例创建前后的回调;
测试如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @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(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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 ; } } |
1 2 3 4 5 6 7 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | @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()); } |
1 2 3 4 5 6 7 | @Configuration public class MainConfig10 { @Bean public DemoFactoryBean demoFactoryBean() { return new DemoFactoryBean(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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方法获取实例,此时获取实例不是使用反射;
测试如下:
1 2 3 4 5 6 7 8 9 10 11 12 | @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" )); } |
1 2 3 4 5 6 7 | 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属性#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | @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属性#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @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实例化策略整理#
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
2021-01-10 关于MySQL INT类型长度的疑惑