1、Spring简介
Spring框架的主要作用是降低应用开发的复杂性,详细介绍参见百度百科Spring介绍,这里记录一下其中的一段话,
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
轻量——从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。
控制反转——Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。
面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。
框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。
所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。
2、IOC:控制反转
什么是控制反转?传统Javaee编程中,当我们要获取一个对象时,通常通过new关键字来创建类的对象,这是一种主动的获取对象的方法,而在Spring框架中,Spring通过IOC容器来加载对象,将需要加载的所有对象放在容器中,当应用程序需要获取这一对象时,直接从IOC容器中获取。
即原本当我们获取一个对象时,是以主动创建的方式来获取的,现在为我们获取对象时需要依赖于IOC容器对类的加载,需要容器来获取或加载类,从主动转换为被动,这一思想即称为IOC控制反转思想。这其中IOC对类的加载是通过工厂模式+反射+配置文件来完成的。
那么,既然要通过容器来加载类,就需要通过配置文件来实现,下面具体描述IOC入门案例的搭建实现过程:
a、准备Spring框架的开发包,解压,目录分三层,分别为:doc:API和开发规范,libs:jar包和源码,schema:约束
从上面对Spring的描述可以看出,Spring底层的核心容器包括beans、core、context、Expression Language,了解IOC需要首先导入这四部分对应的四个jar包,此外,还需要导入日志包,Spring中默认使用的是common-logging.jar,此外当我们导入了log4j的jar包的时候,common-logging会主动使用log4jar包,也就是说common必须导入,log4j可选择性导入。
b、创建需要被Spring加载的类,在该类的根目录下创建任意名称的xml配置文件,建议的命名格式是:applicationContext.xml,这个xml需要使用的约束头可以在\spring-framework-4.2.4.RELEASE-dist\spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html目录下的最后一个html文件,xsd-configuration.html中找到,对应bean部分,该html还包括了很多其他需要使用的约束头信息。
c、配置xml文件,<bean id="user" class="cn.itcast.domain.User"></bean>
这样就能够实现Spring的控制反转,当我们需要使用User类的对象时,通过
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");这种方式来加载配置文件,再通过context.getBean("user")来获取,即可获取到User对象。此外,也可以通过new FileSystemXmlApplicationContext(String configLocation);的方式,从系统路径中加载配置文件。
IOC的bean标签和管理对象细节
bean标签的各个属性值描述如下:
<!--
1: 基本配置
bean标签: 指定要创建的实体类
id属性: 可以为任意值 但是在整个配置文件中唯一
class属性: 要实例化类的全限定名 反射
-->
<!-- <bean id="user" class="cn.itcast.domain.User"></bean> -->
<!--
2: scope属性: 范围
singleton: 单实例 默认值
如果是单实例,配置文件文件只要一加载 就会创建对象 放在spring容器 (map<id,对象>)
当所有人过来问spring容器要的时候(getBean),所用人用的都是同一个对象
prototype: 多实例
如果是多实例,配置文件加载,不创建对象
当每个人过来getbean的时候,getbean一次创建一次 放在容器中
<bean id="user" class="cn.itcast.domain.User" scope="singleton" ></bean>
<bean id="user" class="cn.itcast.domain.User" scope="prototype" ></bean>
什么时候用默认值singleton(单实例)? 什么时候用prototype(多实例)?
action: prototype
service/dao: singleton
3 了解
singleton的对象什么时候销毁? prototype创建出来的对象什么时候销毁?
singleton的对象当spring容器关闭 对象销毁
prototype的对象 长时间不用自动被垃圾回收机制给回收了
init-method:指定初始化方法
destory-method:指定销毁方法
-->
<!-- <bean id="user" class="cn.itcast.domain.User" scope="prototype" init-method="init" destroy-method="destory"></bean> -->
<!--
3 import:导入外部的配置文件
resource:外部配置文件的地址
web: 所有在web层创建的对象 applicationContext_web.xml
service:所有在service层创建的对象 applicationContext_service.xml
dao:所有在dao层创建的对象 applicationContext_dao.xml
<import resource="applicationContext_web.xml"/>
<import resource="applicationContext_service.xml"/>
<import resource="applicationContext_dao.xml"/>
<import resource="applicationContext_user.xml"/>
-->
此外,Bean有三种创建方式,分别为无参数构造方式、静态工厂方式、实例工厂方式
无参数构造方式:
<!-- 无参构造方式
<bean id="user" class="cn.itcast.domain.User"></bean>
-->
public class User
{
// 构造器
public User()
{
System.out.println("我被创建了...");
}
// public void run()
// {
// System.out.println("run");
// }
//
// // 指定一个方法为初始化方法
// public void init()
// {
// System.out.println("我要初始化了...");
// }
// // 指定一个方法为销毁方法
// public void destory()
// {
// System.out.println("我挂了..66666666");
// }
}
静态工厂方式和实例工厂方式:
<!-- 静态工厂方式(了解)
条件:需要有一个工厂类 在这个工厂类中还需要有一个静态方法
<bean id="user" class="cn.itcast.utils.BeanFactory" factory-method="createUser"/>
-->
<!-- 实例工厂(了解)
条件:需要有一个工厂类 在这个工厂类中还需要有一个普通方法
<bean id="beanFactory" class="cn.itcast.utils.BeanFactory"></bean>
<bean id="user" factory-bean="beanFactory" factory-method="createUser"></bean>
-->
public class BeanFactory
{
// 静态方法---静态工厂
/*public static User createUser()
{
return new User();
}*/
// 普通方法---实例工厂
public User createUser()
{
return new User();
}
}
3、依赖注入DI(Dependency Injection)
什么是依赖注入?就是当IOC容器加载类的时候,这个类中的属性也会被一并加载,这一过程就被称为依赖注入。我们可以通过配置文件的方式,依赖注入的基础是控制反转机制。
依赖注入的几种方式(或者说给类的成员变量赋值的几种方式):
第一种:构造器属性注入(不重要)
<!--
DI的注入方式:
1 构造器的方式
条件:需要有参构造方法
-->
<!-- <bean id="car" class="cn.itcast.serviceImpl.CarImpl">
构造器的方式
name:要赋值的属性名
value:要赋的值 (针对的是基本类型和String类型)
ref: 针对的是对象类型
<constructor-arg name="name" value="BMW"></constructor-arg>
<constructor-arg name="price" value="1000000"></constructor-arg>
</bean> -->
public class CarImpl implements Car
{
private String name;
private double price;
public void setName(String name) {
this.name = name;
}
public void setPrice(double price) {
this.price = price;
}
// 有参构造 --方便di的构造器注入方式
public CarImpl(String name,double price)
{
this.name=name;
this.price=price;
}
@Override
public void run() {
System.out.println("价格:"+price+"钱的"+name+"车跑起来了...");
}
@Override
public String toString() {
return "CarImpl [name=" + name + ", price=" + price + "]";
}
}
第二种:set属性的方式
<!--
DI的注入方式:
2 set属性的方式
条件:属性必须要有set方法
name:要赋值的属性名
value:要赋的值 (针对的是基本类型和String类型)
ref: 针对的是对象类型
指向的是spring中bean的id名
-->
<!-- <bean id="person" class="cn.itcast.serviceImpl.PersonImpl">
set属性的方式
<property name="name" value="jack"></property>
<property name="car" ref="car"></property>
</bean> -->
public class PersonImpl implements Person
{
private String name;
private Car car;
public void setName(String name) {
this.name = name;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "PersonImpl [name=" + name + ", car=" + car + "]";
}
}
第三种:p名称空间的方式:略
此外,有的复杂属性注入方式需要掌握
<!-- DI:复杂属性注入 -->
<bean id="collBean" class="cn.itcast.domain.CollBean">
<property name="ss">
<!-- 数组类型 -->
<list>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</list>
</property>
<property name="ll">
<!-- list类型 -->
<list>
<value>111</value>
<value>222</value>
<ref bean="car"/>
</list>
</property>
<property name="mm">
<!-- map -->
<map>
<entry key="k1" value="aaa"></entry>
<entry key="k2" value="bbbb"></entry>
<entry key="k3" value-ref="car"></entry>
</map>
</property>
<property name="properties">
<!-- properties类型 -->
<props>
<prop key="hibernate.username">root</prop>
<prop key="hibernate.password">1234</prop>
</props>
</property>
</bean>
public class CollBean
{
public CollBean()
{
System.out.println(11111);
}
private String[] ss;
private List ll;
private Map mm;
private Properties properties; //键值对
public void setSs(String[] ss) {
this.ss = ss;
}
public void setLl(List ll) {
this.ll = ll;
}
public void setMm(Map mm) {
this.mm = mm;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "CollBean [ss=" + Arrays.toString(ss) + ", ll=" + ll + ", mm=" + mm + ", properties=" + properties + "]";
}
}