现在开发比较流行springboot,但很多开发人员都忽略l了springboot是基于spring而衍生的子项目,不懂spring如何玩转springboot?难道就靠几天的培训跟文章就能玩转springboot了么?答案肯定是不行的,要深入了解springboot必须要会spring,基础很重要,重要的话再怎么说都不为过;作者写spring的基础文章和概念性的理解还有一个很重要的目的,那就是为后面的分析源码做准备,如果一下子就上源码,我相信很多人都会被绕进去,都不知道回事,所以老老实实的学习才是技术提升的必经之路。有兴趣的开发人员或者学生可以关注我的sping专栏。
由于之前的文章已经讲过beans包和核心概念就不赘述。spring IOC container 可以容纳一个或者多个beans,beans的是随着 configuration metadata 的提供而创建的,configuration metadata 之前文章也提过,其最原始的配置方式就xml.
这些bean的定义其实就是对应BeanDefinition Object。下面源码一句话;BeanDefinition(接口) 就是 bean的一个实例,其有属性值,构造参数值和更深层次的信息,这些由其具体的实现者提供。
A BeanDefinition describes a bean instance, which has property values,constructor argument values, and further information supplied by concrete implementations.
BeanDefinition 的 元数据举例:
bean的声明周期和作用域(scop,lifecycle callbacks)包限定的类名:通常就是真实类的全类名在container直接的相互协作依赖。在创建对象的时候配置其他信息,比如使用bean管理连接池,限值连接池的大小等。通常元数据就是转为属性:
class (bean全类名)name (bean的名称)scope (作用域)constructor arguments (构造器参数)properties (属性)autowiring mode (自动配置模式)lazy-initialization mode (懒初始化模式)initialization method (bean初始化方法)destruction method (bean摧毁方法)此外还可以通过 ApplicationContext 的实现者(比如使用getBeanFactory()获得DefaultListableBeanFactory)通过registerSingleton方法和registerBeanDefinition方法去配置元数据,但这种方式不常见,通常都是使用xml
每一个bean通常都是有一个或者多个身份,使用bean的别名等,但是container在管理bean时其必须要有唯一标识。通常基于xml配置元数据,<bean> 元素的 id , name 属性通常就代表了一个bean的唯一标识。命名的规则是第一个字母小写后面的字母或者数字使用驼峰比如 userDao , userService 。通常 不指定 bean的名称也是可以,spring container 会自动给bean生成一个唯一标识,但是,如果要按名称引用该bean,则必须通过使用ref元素或 Service Locator 样式查找提供名称。
通常在大型的项目中会使用到别名,比如主系统和子系统集成的时候 一个bean在相同的container中称为fromName,使用别名后就会指向toName,示例如下:
<alias name="fromName" alias="toName"/>bean的实例化方式其实可以分为三种,第一种就是直接使用bean元素,container初始化后,直接拿到bean的实例,这跟平时new 对象没啥区别,但是默认情况下由container的bean实例化后拿到的实例都是单例。第二种就是使用static factory-method,(静态工厂模式)。第三种就是 factory-method (实例工厂模式)。第二种和第三种这两种方式不是很常见,container在初始化的时候会调用fatory-method实例化bean,fatory-method会去工厂中调用创建实例的方法(createInstance)。
区别是否是内部类通常使用 区 分 , 比 如 ‘ c o m . y o u k u 1327. A n i m a l 区分,比如 `com.youku1327. Animal 区分,比如‘com.youku1327.Animal$dog`
示例如下,有使用spring框架开发的人员肯定很熟悉,我们经常使用这种方式实例化bean
<bean id="iocService" class="com.youku1327.ioc.service.IocService"> <!-- additional collaborators and configuration for this bean go here --> </bean>静态工厂 如下,本示例的fatory-method的静态工厂就是其本身(你也可以 new 其他的实例放进静态工厂里面),但是 其声明方法类型必须是static。
/** * @Author lsc * @Description <p> </p> * @Date 2019/10/31 13:55 */ public class StaticBeanService { private static StaticBeanService staticBeanService = new StaticBeanService(); // other properties private StaticBeanService() {} public static StaticBeanService createInstance() { // add your properties return staticBeanService; } }配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- static factory method services --> <bean id="staticBeanService" class="com.youku1327.bean.entity.StaticBeanService" factory-method="createInstance"> </bean> </beans>实例化工厂模式和静态工厂模式很相似,区别在于创建实例的方法有没有使用static关键字而已。本实例的Car其实应该是接口,然后通过具体的实现类(比如兰博基尼Car,宝马car等)实现接口,然后在Carfactory中使用相应的createCarInstance方法,在xml中配置对应的bean即可。简单的实现示例如下:
实体如下:
/** * @Author lsc * @Description <p> </p> * @Date 2019/10/31 14:58 */ public class Car { private String carName; private String color; public String getCarName() { return carName; } public void setCarName(String carName) { this.carName = carName; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } }实例化工厂如下:
/** * @Author lsc * @Description <p> </p> * @Date 2019/10/31 15:00 */ public class CarFactory { private static Car car = new Car(); private CarFactory(){ } public Car createCarInstance(){ return car; } }配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- the factory bean, which contains a method called createInstance() --> <bean id="carFactory" class="com.youku1327.bean.factory.CarFactory"> <!-- inject any dependencies required by this locator bean --> </bean> <!-- the bean to be created via the factory bean --> <bean id="car" factory-bean="carFactory" factory-method="createCarInstance"/> </beans>IOC Container
【本文github源码在公众号文章末尾链接】。