Spring实际就是将实例化控制反转给了BeanFactory,类都经过BeanFactory(读取xml后)进行实例化。
BeanFactory介绍
使用坐标spring-context
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.7</version>
</dependency>
xml中bean的定义方式
<bean id="userService" name="aaa,bbb" class="com.demo.service.impl.UserServiceImpl" scope="prototype"><!-- name通过方法前的set匹配,ref引用的是配置的bean id --><property name="userDao" ref="userDao"></property>
</bean>
<bean id="userDao" class="com.demo.dao.impl.UserDaoImpl"></bean>
bean id就是getBean中的参数name;name是别名,多个别名用","隔开;class配置的是类的路径名。
当有id时优先id赋值Name;无id有name时配置Name=第一个name参数;只有class时赋值Name=class.
bean中property配置实例化bean后就执行的方法,一般标签中的name和方法名有对应(方法名: setAaa->property name: Aaa),ref是xml中bean的引用。
ioc的两种客户端,ApplicationContext和BeanFactory。
(1)ApplicationContext基于BeanFactory实现,除此之外包含国际化等功能。
(2)ApplicationContext习惯命名xml为ApplicationContext.xml,
(3)ApplicationContext可以使用的客户端类有通过ClassPathXml(项目相对路径)和FileSystemXml(系统路径)两种实现类。BeanFactory通常使用DefaultListableBeanFactory配合XmlBeanDefinitionReader.两者获取Bean都是通过客户端调用getBean方法。
(4)BeanFactory是在getBean时才创建Bean示例,而ApplicationContext在编译后就实例化bean。
scope的两个属性:singleton和prototype,都是针对ApplicationContext而言的,对BeanFactory无效
(1)singleton是在初始化时就加载实例bean到容器,后面每次getBean获取的都是同一个实例
(2)prototype在初始化时不会将实例立即加入到bean到容器,而是在getBean后才实例化bean,且每次实例化都不一样
lazy-init属性是配置bean加载是不是懒加载,true->只有在getBean后才会创建实例,默认是false。
lazy-init=true时,scope取值singleton,变为每次getBean后才实例化,每次获取到的都是一个实例对象;scope取值prototype,还是getBean后才进行实例化,每次加载还是prototype原来的各个创建。
init-method、destroy-method
指定类初始化后、销毁后执行的方法名。
类实现InitializingBean接口、实现afterPropertiesSet后,完整的生命周期顺序:构造函数、bean中配置的property(setXxx方法)参数设置、afterPropertySet(InitializingBean接口的方法)、init-method指定的初始化方法。
Spring中的Bean实例化方式
ApplicationContext默认是通过BeanFactory进行创建,而BeanFactory是通过反射获取构造方法,调用构造方法进而实例化对象。
对于反射+构造方法的方式,分为有参构造和无参构造。对于有参构造函数需要在xml中进行配置。配置方式如下:
<bean id="userService" name="aaa,bbb" class="com.demo.service.impl.UserServiceImpl"><!-- 这里的constructor-arg代表构造实例的参数,不特指构造方法的参数 --><constructor-arg name="name" value="aaa"></constructor-arg><constructor-arg name="age" value="12"></constructor-arg>
</bean>
除了通过默认的BeanFactory实例化外,还可以通过自定义的BeanFactory来进行实例化。分为两种:
(1)静态工厂方法实例化bean:调用指定类的static方法即可。
(2)实例工厂方法实例化bean:实例化xml中配置的类,并调用指定方法进行实例化。
(3)实现FactoryBean规范的延时实例化方式:实现FactoryBean接口,只有在执行getBean时才会执行执行getObject方法获取实例化对象。
自定义实例化BeanFactory的好处:
(1)在创建对象的方法中可以写别的逻辑代码。
(2)对于一些第三方的jar包,可以在自定义的BeanFactory中调用它定义好的方法进行实例化,因为如果还通过xml实例化的话路径会很难找。
自定义BeanFactory的使用方法:
(1)编写一个类,类中写一个方法,方法中包含实例化的语句。如果使用静态工厂,方法就加static;如果使用示例工厂,方法就不用加static.
(2)xml中的配置如下:
静态工厂:只有一个工厂标签,参数配置factory-method指定方法即可。
实例工厂:一个工厂类的实例bean标签;一个工厂标签,参数配置factory-method指定方法、factory-bean指定工厂bean.
FactoryBean规范的工厂:不需要指定factory-method、factory-bean等参数。
<!-- 自定义静态工厂配置,id就是getBean的name参数,factory-method指定类的静态方法 -->
<bean id="userDao1" class="com.demo.factory.MyBeanFactory1" factory-method="userDao"></bean>
<!-- 自定义实例工厂配置,id就是getBean的name参数,factory-bean指定工厂实例方法 --><bean id="userDao2" factory-bean="myBeanFactory2" factory-method="userDao"><!-- 实例化方法的方法参数 --><constructor-arg name="name" value="aaa"></constructor-arg>
</bean>
<!-- 自定义实例工厂实例类,先进行实例化 -->
<bean id="myBeanFactory2" class="com.demo.factory.MyBeanFactory2"></bean>
<!-- 自定义工厂实现FactoryBean接口 -->
<bean id="userDao3" class="com.demo.factory.MyBeanFactory3"></bean>
当需要实例化的bean需要注入数据类型为集合时,如下配置:
<bean id="userService" name="aaa,bbb" class="com.demo.service.impl.UserServiceImpl"><!-- name通过方法前的set匹配,ref引用的是配置的bean id --><property name="userDao" ref="userDao"></property><property name="stringList"><list><value>aaa</value><value>bbb</value></list></property><property name="userDaoList"><list><ref bean="userDaoEle1"></ref><ref bean="userDaoEle2"></ref></list></property><property name="stringSet"><set><value>aaa</value><value>bbb</value></set></property><property name="userDaoSet"><set><ref bean="userDaoEle1"></ref><ref bean="userDaoEle2"></ref></set></property><property name="map"><map><entry key="aaa" value-ref="userDaoEle1"></entry><entry key="bbb" value-ref="userDaoEle2"></entry></map></property><property name="properties"><props><prop key="aaa">aaa1</prop><prop key="bbb">bbb1</prop></props></property>
</bean>
自动装配分为两种:根据类型、根据名称
根据类型(byType):根据bean中指定的class类型。当有多个相同类型但是不同名称的bean时,会报错。
根据名称(byName):根据bean中指定的id.当没有指定名称的bean时,会报错。
profile切换环境:可以定义多个beans标签,指定环境名称,在运行时可以进行切换。
<beans profile="dev"><bean id="userDao3" class="com.demo.dao.impl.UserDaoImpl"></bean>
</beans>
<beans profile="test"><bean id="userDao4" class="com.demo.dao.impl.UserDaoImpl"></bean>
</beans>
切换环境操作:
(1)方法1:ctrl+D指定环境:-Dspring.profiles.active=dev
(2)方法2:java语句
System.setProperty("spring.profiles.active","test");
当项目中有多个配置文件时,可以使用import标签引入指定配置文件,使用其中的bean
<import resource="ApplicaitonContext-user.xml"></import>
alias标签:为bean表亲起别名
<alias name="userDao5" alias="aaa"></alias>
<alias name="userDao5" alias="bbb"></alias>
<alias name="userDao5" alias="ccc"></alias>
自定义命名标签的使用步骤:下面以spring-context为例
引入链接(xmlns:后的名称为自定义的,链接是第三方给定的):xmlns:context="http://www.springframework.org/schema/context"和xsi:schemaLocation中的http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-beans.xsd
使用标签:
<context:annotation-config></context:annotation-config>