Spring 是一个开源框架,是为了解决企业应用程序开发复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许您选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。
核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。 Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。 Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。 Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。 Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。 Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。 Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
Spring是一种完全面向接口的设计。
Sping的两大核心为:IOC控制反转DI依赖注入[Inversion of Control],AOP面向方面编程。
Spring Framework一个重要的原则就是无侵入性(non-invasiveness); 这个思想指你不应当被迫引入框架特定的类和接口到你的业务/领域模型中。
Spring从简单理解,可以引申为工厂模式的一种封装。
工厂模式主要使用在实现的接口类对象的获取。
类对象的获取途径主要有以下几种:
1.直接用new的形式获取。接口类型 对象名 = new 实现接口的类型(); 缺点:客户端在调用时必须明确知道实现接口的类型,程序之间耦合紧密。
2.使用工厂设计模式。 缺点:一个接口就需要一个工厂,接口多的话,工厂也会多,不易管理。
3.使用反射机制 Class.forName()
4.使用对象克隆 缺点:和1一样,耦合紧密。
Spring包的获取:
1.http://www.springframework.org/ 中下载最新的jar包
2.将下载下来的dist文件夹和lib文件夹中的文件拷贝到工程引用jar路径下
Spring的核心配置:
Spring的xml配置:applicationContext.xml
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="bean的名字" class="类完全路径名"> </bean> </beans>
Spring IoC容器的实例化
ApplicationContext在本地应用中的实例化
// 可同时加载好几个配置 ApplicationContext context = new ClassPathXmlApplicationContext( new String[] {"applicationContext.xml", "daos.xml"}); // 获取的ApplicationContext对象与BeanFactory对象是接口与实现子类的关系 所以直接用context.getBean()方法即可 BeanFactory factory = context;
同时加载多个配置的另一种写法:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <!-- 都是相对于该xml的路径,开头的"/"有与没有都可以 --> <import resource="resources/messageSource.xml"/> <import resource="/resources/themeSource.xml"/> <beans> <bean id="bean的名字" class="类完全路径名"> </bean> </beans>
ApplicationContext在WEB应用中的实例化
1.ContextLoaderListener方式
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
2.ContextLoaderServlet方式
<context-param> <param-name>contextConfigLocation</param-name> <!-- 可以使用搜索符:* 可以加载放在classpath下的xml -> <param-value/WEB-INF/applicationContext-*.xml,classpath*:applicationContext-*.xml</param-value> </context-param> <servlet> <servlet-name>context</servlet-name> <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet>
注入类型一共分三种:
1.构造函数注入
2.属性注入(通过set和get方法)
3.接口注入(相当于将类似于set的方法声明在一个接口中)
Spring对以上前2种的注入有非常棒的支持,而第3种注入本身就很少使用(于通过接口注入需要额外声明一个接口,增加了类的数目,而且它的效果和属性注入并无本质区别,因此我们不提倡这种方式)。
在Spring中,BeanFactory是IoC容器的核心接口。 它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
基于XML配置方式,注入示例:
Simple.java
package sp; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; public class Simple { private String name; private Date d; private int age; private List list; private Map map; private Set set; private String[] array; private SimpleRef simpleRef; public Simple(String name,Date d){ this.name = name; this.d = d; } public Simple(Date d){ this.d = d; } public Simple(String name,int age){ this.name = name; this.age = age; } public String[] getArray() { return array; } public void setArray(String[] array) { this.array = array; } public SimpleRef getSimpleRef() { return simpleRef; } public void setSimpleRef(SimpleRef simpleRef) { this.simpleRef = simpleRef; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getD() { return d; } public void setD(Date d) { this.d = d; } public List getList() { return list; } public void setList(List list) { this.list = list; } public Map getMap() { return map; } public void setMap(Map map) { this.map = map; } public Set getSet() { return set; } public void setSet(Set set) { this.set = set; } }
applicationContext.xml
<?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-2.0.xsd"> <bean id="simple" class="sp.Simple"> <!-- 构造函数注入 自动匹配(当构造函数的参数都是引用类型时) --> <constructor-arg> <bean class="java.util.Date"/> </constructor-arg> <!-- 构造函数注入 索引方式 --> <constructor-arg index="0" value="han"></constructor-arg> <constructor-arg index="1" ref="dateRef"></constructor-arg> <!-- 构造函数注入 类型匹配方式(当构造函数的参数都是基本类型时) --> <constructor-arg type="java.lang.String" value="han"></constructor-arg> <constructor-arg type="int" value="25"></constructor-arg> <!-- List类型属性注入 --> <property name="list"> <list> <value>1</value> <value>2</value> <ref bean="xxxx" /> </list> </property> <!-- Set类型属性注入 --> <property name="set"> <set> <value>1</value> <value>2</value> </set> </property> <!-- Map类型属性注入 --> <property name="map"> <map> <entry key="k1" value="v1"></entry> <entry key="k2" value="v2"></entry> <entry> <key> <value>a ref</value> </key> <ref bean="myDataSource" /> </entry> </map> </property> <!-- 数组类型属性注入 --> <property name="array"> <list> <value>1</value> <value>2</value> </list> </property> <!-- Properties类型注入 --> <property name="adminEmails"> <props> <prop key="administrator">administrator@example.org</prop> <prop key="support">support@example.org</prop> <prop key="development">development@example.org</prop> </props> </property> <!-- 引用类型属性注入 --> <property name="simple" ref="simpleRef"></property> <!-- 引用类型属性注入(另一种写法) --> <property name="simple"> <ref bean="simpleRef" /> </property> </bean> <bean id="simpleRef" class="sp.SimpleRef"></bean> <bean id="dateRef" class="java.util.Date"></bean> </beans>
idref
仅适用于对bean名称即String类型的引用,ref是对bean实例的引用。
ref
1.<ref bean="someBean"/> 在当前容器中查找someBean
2.<ref local="someBean"/> 在当前xml中查找someBean
3.<ref parent="someBean"/> 在父容器中查找someBean
内部bean
<bean id="outer" class="..."> <!-- instead of using a reference to a target bean, simply define the target bean inline --> <property name="target"> <bean class="com.example.Person"> <!-- this is the inner bean --> <property name="name" value="Fiona Apple"/> <property name="age" value="25"/> </bean> </property> </bean>
内部bean中的scope标记及id或name属性将被忽略。内部bean总是匿名的且它们总是prototype模式的。同时将内部bean注入到包含该内部bean之外的bean是不可能的。
空字符串的注入
<bean class="ExampleBean"> <property name="email"> <value/> </property> </bean>
null的注入
<bean class="ExampleBean"> <property name="email"> <null/> </property> </bean>
方法注入
在大部分情况下,容器中的bean都是singleton类型的。如果一个singleton bean要引用另外一个singleton bean,或者一个非singleton bean要引用另外一个非singleton bean时,通常情况下将一个bean定义为另一个bean的property值就可以了。不过对于具有不同生命周期的bean来说这样做就会有问题了,比如在调用一个singleton类型bean A的某个方法时,需要引用另一个非singleton(prototype)类型的bean B,对于bean A来说,容器只会创建一次,这样就没法在需要的时候每次让容器为bean A提供一个新的的bean B实例。
解决方案为:不直接将需要的bean注入,而是定义一个抽象方法,在需要的地方调用该抽象方法进行bean的获取,而该抽象方法在xml中进行配置注入
package fiona.apple; // no more Spring imports! public abstract class CommandManager { public Object process(Object commandState) { // 每次都需要一个新的Command实例 Command command = createCommand(); // set the state on the (hopefully brand new) Command instance command.setState(commandState); return command.execute(); } // okay... but where is the implementation of this method? protected abstract Command createCommand(); }
<!-- a stateful bean deployed as a prototype (non-singleton) --> <bean id="command" class="fiona.apple.AsyncCommand" scope="prototype"> <!-- inject dependencies here as required --> </bean> <!-- commandProcessor uses statefulCommandHelper --> <bean id="commandManager" class="fiona.apple.CommandManager"> <lookup-method name="createCommand" bean="command"/> </bean>
基于XML的元数据是最常用到的配置元数据格式。然而,它并 不是唯一的描述格式。Spring IoC容器在这一点上是 完全开放的。
Spring还提供了基于注解的配置元数据格式。
