SpringIOC-Bean配置及源码
创建bean:
1.默认构造函数
spring.xml <bean class="com.test.spring.HelloSpring"></bean>
HelloSpring.java HelloSpring() {}
2.指定构造函数
<bean class="com.test.spring.HelloSpring">
<constructor-arg index="0" value="zhangsan"></constructor-arg>
<constructor-arg name="age" value="1"></constructor-arg>
</bean>
public HelloSpring(String name, int age) {}
3.静态工厂方法 factory-method="build"。场景:A/B测试
spring.xml
<bean class="com.test.spring.HelloSpring" factory-method="build">
<constructor-arg name="type" value="A"></constructor-arg>
</bean>
HelloSpring.java
public static HelloSpring build(String type) {
if("A".equals(type)) {
return new HelloSpring("张三",1);
}else if("B".equals(type)){
return new HelloSpring("李四",2);
}else {
throw new IllegalArgumentException("type must be A OR B");
}
}
4.FactoryBean创建。创建的可能并不是类本身的对象,场景:SqlSessionFactory。
<bean id="driver" class="com.test.spring.FactoryBeanSpring">
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306"></property>
</bean>
class FactoryBeanSpring implements FactoryBean{
private String jdbcUrl;
public Object getObject() throws Exception {
return DriverManager.getDriver(jdbcUrl);
}
public Class getObjectType() {
return java.sql.Driver.class;
}
public boolean isSingleton() {
return true;
}
}
依赖注入:
HelloSpring的成员变量:WorldSpring
1.set方法注入
<bean class="com.test.spring.HelloSpring" >
<property name="worldSpring" ref="world" />
</bean>
<bean id="world" class="com.test.spring.WorldSpring" ></bean>
2.构造方法注入
<bean class="com.test.spring.HelloSpring" >
<constructor-arg name="worldSpring">
<bean class="com.test.spring.WorldSpring" />
</constructor-arg>
</bean>
3.自动注入:byName、byType。默认是byName
<bean class="com.test.spring.HelloSpring" autowire="byName" />
<bean id="worldSpring" class="com.test.spring.WorldSpring" />
4.方法注入: lookup-method。场景:一个单例bean依赖一个多例bean.该操作基于动态代理技术。也可以通过实现BeanFactoryAware接口来获取BeanFactory实例,从而直接调用getBean()方法获取新实例.
<bean class="com.test.spring.LookupMethodSpring" >
<lookup-method name="getHello" ></lookup-method>
</bean>
public abstract class LookupMethodSpring {
public abstract HelloSpring getHello();
public void sayHello() {
getHello().sayHello();
}
}
基本特性:
1.作用范围
scope=prototype多例
scope=singleton 单例。单例对象会缓存于IOC容器,在DefaultSingletonBeanRegistry对象中。
2.生命周期
创建
初始化 init-method
销毁 destory-method applicationContext关闭时会进行销毁
3.加载机制
设置lazy-init,默认为false。
true 懒加载,延迟加载。容器启动会很快
false 非懒加载,创建即加载。容器启动时能更快的发现错误。
创建、读取bean:
1.关键类
BeanDefinition:bean定义类。bean信息都保存在该类对象中,与xml bean一对一关系
继承 AttributeAccessor、BeanMetadataElement。AttributeAccessor.getAttribute()、BeanMetadataElement.getSource()
BeanDefinitionRegistry:Bean注册器类,id注册,name是设置别名。
id作为当前bean的存储key注册到BeanDefinitionRegistry注册器中
name作为别名key注册到AliasRegistry注册器
BeanDefinitionReader:Bean定义读取类。
BeanDefinitionReader读取xml,load BeanDefinition装载bean定义,注册到BeanDefinitionRegistry
BeanFactory:bean工厂,创建bean。
getBean(String)
基于ID或name 获取一个Bean
<T> T getBean(Class<T> requiredType)
基于Bean的类别获取一个Bean(如果出现多个该类的实例,将会报错。但可以指定 primary=“true” 调整优先级来解决该错误 )
Object getBean(String name, Object... args)
基于名称获取一个Bean,并覆盖默认的构造参数
boolean isTypeMatch(String name, Class<?> typeToMatch)
指定Bean与指定Class 是否匹配
BeanFactory
BeanFactory是最顶层的一个接口类,它定义了IOC容器的基本功能规范。
子类ListableBeanFactory:表示这些 Bean 是可列表的,定义了 Bean 的集合;
子类HierarchicalBeanFactory:表示的是这些 Bean 是有继承关系,定义了Bean 之间的关系;
子类AutowireCapableBeanFactory:定义 Bean 的自动装配规则,定义了Bean 行为。
最终的默认实现类是 DefaultListableBeanFactory,实现了以上所有的接口。
BeanDefinition
Bean对象在Spring实现中是以BeanDefinition来描述的
BeanDefinitionReader
Bean 的解析主要就是对 Spring 配置文件的解析
2.模拟BeanDefinitionRegistry装载过程
//创建一个简单注册器
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
//创建bean定义读取器
BeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
// 创建资源读取器、获取资源
DefaultResourceLoader loader = new DefaultResourceLoader();
Resource resource = loader.getResource("spring.xml");
// 装载Bean的定义
reader.loadBeanDefinitions(resource);
//通过别名获取
registry.getAliases("h1");
//通过id获取
registry.getBeanDefinition("h1");
System.out.println(Arrays.toString(registry.getBeanDefinitionNames()));
3.模拟
代码:
//注册中心 DefaultListableBeanFactory registry = new DefaultListableBeanFactory(); //读取器 XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry); //读取资源 //装载构建bean的定义 reader.loadBeanDefinitions("spring.xml"); registry.getBean("h1"); System.out.println(Arrays.toString(registry.getBeanDefinitionNames())); 分析: 1.DefaultListableBeanFactory既实现了BeanDefinitionRegistry,又实现了BeanFactory。 2.构造函数处打断点,查看调用过程:从下往上看 at com.test.spring.HelloSpring.<init>(HelloSpring.java:12) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(NativeConstructorAccessorImpl.java:-1) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) BeanUtils.instantiateClass(BeanUtils.java:200) SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87) AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1312) AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1214) AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) AbstractBeanFactory$$Lambda$5.1846406218.getObject(Unknown Source:-1) DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) - locked <0x58a> (a java.util.concurrent.ConcurrentHashMap) AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) //先从单例缓存中获取。DefaultListableBeanFactory实现了BeanDefinitionRegistry,所以这里调用的是DefaultSingletonBeanRegistry的getSingleton(String beanName)方法,从singletonObjects(ConcurrentHashMap)中取 Object sharedInstance = this.getSingleton(beanName); //DefaultSingletonBeanRegistry.getSingleton(beanName); //如果值不为空,进入下面 bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);//查看是不是FactoryBean创建自定义bean //如果为空,进入下面,从parentBeanFactory里去获取,类似于classLoader里的双亲委派? BeanFactory parentBeanFactory = this.getParentBeanFactory(); parentBeanFactory.getBean(nameToLookup, args); //如果还是为空 //如果是单例 if (mbd.isSingleton()){sharedInstance = this.getSingleton(beanName, objectFactory);} //DefaultSingletonBeanRegistry.getSingleton(String beanName, ObjectFactory objectFactory) //DefaultSingletonBeanRegistry.getSingleton(String beanName, ObjectFactory objectFactory) //第一步 加锁 //判断是否为空,双重检测 this.beforeSingletonCreation(beanName);//检测这个bean是否正在被创建 singletonFactory.getObject();//这个地方往回调,实际上调用的是AbstractBeanFactory.doGetBean的189行,这里传过来objectFactory。 //AbstractBeanFactory.doGetBean的189行 this.createBean(beanName, mbd, args);//AbstractAutowireCapableBeanFactory.doCreateBean(); this.afterSingletonCreation(beanName); this.addSingleton(beanName, singletonObject); //如果是多例 if (mbd.isPrototype()) { this.beforePrototypeCreation(beanName); //写锁 prototypeInstance = this.createBean(beanName, mbd, args); this.afterPrototypeCreation(beanName);//去锁 } AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) at com.test.spring.BeanFactoryTest.main(BeanFactoryTest.java:23)
Tips:
1.ctrl+alt+u查看类和子类(实现类)的结构图
2.ApplicationContext与BeanFactory的区别
是Spring的两大核心接口,都可以当做Spring的容器
3.createBean方法里,实际调用的是
AbstractAutowireCapableBeanFactory.doCreateBean
doCreateBean源码