Spring 是企业级应用中的一个软件开发框架(Framework),一个半成品。最大优势是更好实现资源的整合。例如整合JDBC,MyBatis,Hibernate等框架资源以更好的简化应用软件开发,降低软件开发周期。
Spring 最初的目标就是要整合一切优秀资源,然后对外提供一个统一的服务,其具体架构(Spring 4.0)如下:
Spring 中的核心组件:
1) IOC 组件(控制反转容器):对象创建,对象存储,对象依赖管理。
2) DATA 组件(整合JDBC,MyBatis,JPA,....)
3) MVC 组件(重点解决与表示层通讯问题)
4) AOP 组件(重点解决对象功能扩展问题)
1.1. Spring IOC 概述
Spring 中有一个核心容器,这个容器我们通常称之为IOC(Inversion of Control)容器,这个容器最核心功能就是控制反转.这个容器负责对象的创建,
对象的存储(map),对象的管理(依赖查找,依赖注入)。
总结:
1) 核心服务(整合资源)
2) 核心特性 (IOC-面向对象,AOP-面向切面,Cloud-面向微服务)
3) 核心目的(更好的对系统进行粒度控制,对象管理,功能扩展)
1. Spring 框架中Bean对象基础应用
在软件应用中由Spring管理的所有对象都称之为Bean.我们自己创建的类假如需要由spring管理,首先对这个类进行配置,常用配置方式有两种,一种基于xml进行配置,一种基于注解进行配置.
a.基于xml方式对象Bean对象进行配置时,首先需要在spring的核心配置文件中
使用bean标签对bean类型进行声明,借助id或name属性指定的bean的一个
标识.通过class属性指定bean的具体类型(必须写全类名);
1.1. Bean 对象的构建
Spring 中Bean对象的构建,提供了如下两种方式:
1) 直接通过构造方法
2) 通过工厂的实例方法(调用FactoryBean的getObject方法)
代码实现: 直接通过构造函数
<!-- 直接通过类的构建方法构建对象(重点) -->
<bean id="helloService" class="beans.HelloService"/>
1.1. Bean 对象的作用域
在Spring容器中管理的Bean对象,可以在声明时通过scope属性或
相关注解指定其作用域,最常用是singleton,prototype.其含义如下
1) singleton (这个作用域标识的对象具备全局唯一性):系统默认
2) prototype(这个作用域标识的对象每次获取都会创建新的对象)
<bean id="helloService"
class="beans.HelloService"
scope="singleton"/>
1.1. Bean 对象的生命周期
在Spring框架应用中,所有的的Bean对象都有生命周期,所谓Bean对象的生命周期是指Bean对象的创建,初始化,服务,销毁的这个过程.
在spring配置文件中可以通过Init-method,destory-method属性指定bean的生命周期方法.例如:
<bean id="helloService"
class="beans.HelloService"
scope="prototype"
init-method="init"
destroy-method="destory"/>
在Spring应用由Spring创建的对象是否由spring销毁,还取决于Bean对象的作用域的配置.例如
1) singleton作用域的对象可以在容器关闭时销毁(会调用对象的销毁资源的方法)
2) prototype作用域的对象可以由容器创建对象,初始化对象,但不负责销毁.
一般是资源提供者对象,例如连接池对象可能会写生命周期方法
Bean 对象的延迟加载
在spring框架应用,容器初始化时候,默认会构建所有由spring管理的Bean对象.但假如这些对象长时间不使用还占用着内存就会造成一定的资源浪费.为了解决这个问题,spring中提供了一种延迟加载机制.通过这种机制来提高系统资源的有效使用.
Spring中的延迟加载需要通过bean元素中lazy-init属性或beans元素的default-lazy-init="true"属性进行设置.两者应用的不同点:
1) lazy-init: 应用在bean标签中用于指定这个bean的加载策略.
2) default-lazy-init:应用在beans标签中用于指定所有bean的加载策略.
例如:
<bean id="helloService" class="beans.HelloService" scope="singleton" lazy-init="true"/>
Spring 框架中依赖注(DI)基础应用
1.1. 直接量值的注入
Spring 直接量值的注入指的是通过Spring IOC为对象的8种封装类以及String类型的属性注入值。
配置OpenDataSource类并通过set方法为对象属性赋值。
<bean id="dataSource" class="beans.OpenDataSource">
<property name="driverClassName" value="com.jdbc.mysql.Driver"/>
<property name="url" value="jdbc:mysql:///test"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
当然假如对象提供了对应的构造方法也可以通过构造方法为属性注入值,例如
<bean id="openDataSource02" class="beans.OpenDataSource">
<!-- 默认按照构造方法参数顺序注入值
说明:配置时有几个constructor-arg就是
要调用带及格参数的构造函数
-->
<constructor-arg value="com.mysql.jdbc.Driver"/>
<constructor-arg value="jdbc:mysql:///test"/>
<constructor-arg value="root"/>
<constructor-arg value="123456"/>
</bean>
说明:依赖注入时可以将配置信息提取到properties文件中,然后通过spring表达式#{id.key}的方式提取数据。
在类路径下定义一个configs.properties文件,内容如下
jdbcDriver= com.mysql.jdbc.Driver
jdbcUrl= jdbc:mysql:///test
jdbcUser= root
jdbcPassword=123456
在spring的配置文件中configs.properties文件
<util:properties id="cfg" location="classpath:configs.properties"/>
在bean中为属性注入值时使用spring 表达式
<bean id="dataSource" class="beans.OpenDataSource">
<property name="driverClassName" value="#{cfg.jdbcDriver}"/>
<property name="url" value="#{cfg.jdbcUrl}"/>
<property name="username" value="#{cfg.username}"/>
<property name="password" value="#{cfg.password}"/>
</bean>
其中#为spring表达式特殊标记,{}为表达式内容,cfg为util:properties 标签中定义的id. username、password为配置文件等号左边的key
Spring 配置文件中为对象属性注入值。
<bean id="collection" class="beans.CollectionObject">
<property name="list">
<list>
<value>A</value>
<value>B</value>
</list>
</property>
<property name="map">
<map>
<entry key="k1" value="100" />
<entry key="k2" value="300" />
</map>
</property>
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
类的设计
package com.jt.common.utils;
/**生产者对象(负责向容器放数据)*/
public class Producer {//IOC(工厂,容器)
/**生产者关联一个容器对象(目的是要向此容器放数据)*/
private Container container;
public void setContainer(Container container) {
this.container = container;
}
public Container getContainer() {
return container;
}
}
类的基本配置
…
<bean id="producer" class="com.jt.common.utils.Producer">
<!-- 借助ref属性从容器中获取一个id为container
的对象然后赋值给Producer的container属性 -->
<property name="Container" ref="container"/>
</bean>
…
单元测试
public class TestProducer01 extends TestBase{
@Test
public void testProducer(){
//1.获取生产者对象
Producer pro=ctx.getBean("producer",Producer.class);
Assert.assertNotEquals(null, pro);
//2.获取生产者关联的容器对象
Container container=pro.getContainer();
Assert.assertNotEquals(null, container);
//3.向容器放数据
container.getMap().put("mysql", 100);
container.getList().add("皮皮霞");
}
}