1 spring 简介
spring 是一个开源的,控制反转(IOC), 和面向切面(AOP)的容器框架
使用Spring 的好处
1 降低组件之间的耦合度,实现软件各层之间的解耦
2 可以使用容器提供的众多服务,如:事务管理服务、消息服务等等。当我们使用容器管理
事务时,开发人员就不再需要手工控制事务.也不需处理复杂的事务传播
3 容器提供单例模式支持,开发人员不再需要自己编写实现代码
4 容器提供了AOP技术,利用它很容易实现如权限拦截、运行期监控等功能
5 容器提供的众多辅作类,使用这些类能够加快应用的开发,如: JdbcTemplate、 HibernateTemplate
6 Spring对于主流的应用框架提供了集成支持,如:集成Hibernate、JPA、Struts等,这样更便于应用的开发
Spring 负责管理容器中的所有组件,这些组件称为 bean ,在spring的世界里,一切都是bean
其实使用spring,就是面向bean的编程
组成Spring的模块(组件)都可以单独存在 主要模块如下
1)Spring Core //核心容器
//Supporting utlities
//Bean container
核心容器: 提供Spring 框架的基本功能,核心容器的主要组件是BeanFactory,它是工厂模式的实现
BeanFactory 使和控制反转(IOC) 模式将应用程序的配置和依赖规范与实际的应用程序代码分开
2)Spring Context //上下文的一个配置文件
//Application Context
//Ui Support
//validation
//JNDI EJB supprot and remodeling Mail
Spring 上下文是一个配置文件,向Spring框架提供上下文信息。Spring 上下文包括企业服务,例如
JNDI 、EJB、电子邮件、国际化、校验和调度功能。
3)Spring AOP
//Source-level
//metadata
//AOP infrastructure
通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了Spring 框架中。
所以,可以很容易地使Spring框架管理的任何对象支持AOP 。Spring AOP 模块为基于Spring
的应用程序中的对象提供了事务管理服务。通过使用Spring AOP ,不用依赖EJB 组件,就可以
将声明性事务管理集成到应用程序中。
4)Sping DAO
//Transaction infrastructure
//JDBC support
//DAO support
JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库
供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写
的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的DAO 异常层次结构。
5)Spring ORM
//Hibernate Support
//IBatis support
//JDO Support
Spring 框架插入了若干个ORM 框架,从而提供了ORM的对象关系工具,其中包括JDO 、
Hibernate 和 iBatis SQLMap 。 所有这些都遵从Spring 的通用事务和DAO 异常层次结构。
6) Spring WEB
//WebApplicationContext
//Multipart resolver
//Web Utilites
Web上下文模块建立于应用上下文模块之上,提供了一个适合于Web应用的上下文。另外,
这个模块还提供了一些面向服务支持。例如:实现文件上传的multipart请求,它也提供了
Spring和其它Web框架的集成,比如Struts、WebWork。
7) Spring MVC
//Web Mvc
//framework
//JSP/velocity
//PDF/Export
Spring为构建Web应用提供了一个功能全面的MVC框架。虽然Spring可以很容易地与其它MVC框架集成,
例如Struts,但Spring的MVC框架使用IoC对控制逻辑和业务对象提供了完全的分离。
它也允许你声明性地将请求参数绑定到你的业务对象中,此外,Spring的MVC框架还可以利
用Spring的任何其它服务,例如国际化信息与验证。
Spring带来了复杂的J2EE开发的春天。它的核心是轻量级的IoC容器,它的目标是为J2EE应用提供
了全方位的整合框架,在Spring框架下实现多个子框架的组合,这些子框架之间可以彼此独立,
也可以使用其它的框架方案加以代替,Spring希望为企业应用提供一站式(one-stopshop)的解决方案
2 spring 中的重要概念
1) IOC 控制反转 //inversion of control
应用本身不负责依赖对象的创建,而是把它们的创建交给外部容器 控制权转移到了外部容器,控制权的转移
就叫控制反转
//传统的
class UserServlet
{
private IUserDao dao = new UserDaoImpl() ;
public void doPost(){
dao.getUserById();
}
}
//反转形式的
class UserServlet
{
UserServlet(IUserDao dao){
this.dao=dao;
}
private IUserDao dao;
public void doPost(){
dao.getUserById();
}
}
2) DI 依赖注入 //Dependency Injection
在程序运行期,把依赖对象由外部容器注进来的过程
3) AOP (Aspect Oriented Programming) 面向切面编程 例如Struts2 中拦截器
可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术
3 第一个spring程序
1) 导包
2) 配置文件
附:没有提示的情况
MyEclipse ->File and Editors -XML ->XML Catlog, 点击 add,找到上面的文件 spring-beans-3.1.xsd,
然后 Key type 选 SchemaLoaction,
key 后面加上 spring-beans-3.1.xsd 即可
UserInfo:
private int id;
private String userName;
private String password;
private String note;
..get、set方法,toString方法、无参构造方法
beans.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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean name="userInfo_name" class="com.beans.UserInfo" >
<property name="id" value="100" />
<property name="userName" value="赵强" />
<property name="password" value="123" />
<property name="school" value="沙河农场子弟校" />
</bean>
</beans>
com.test.Test:
public class Test {
public static void main(String[] args) {
//初始化容器
ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
// UserInfo user= (UserInfo)ctx.getBean("userInfo_name");
UserInfo user= ctx.getBean("userInfo_name",UserInfo.class);
// UserInfo user= ctx.getBean(UserInfo.class);
System.out.println(user);
}
}
4 四种实例化bean的方式 (注入方式) 四种依赖对象的注入方式
例子:准备
com.dao.IUserDao(接口) :
package com.dao;
public interface IUserDao {
void addUser();
void delUser();
void updateUser();
}
com.dao.UserDaoImpl:
package com.dao;
public class UserDaoImpl implements IUserDao {
public void addUser() {
System.out.println("addUser方法被调用了");
}
public void delUser() {
System.out.println("delUser方法被调用了");
}
public void updateUser() {
System.out.println("updateUser方法被调用了");
}
}
com.servlet.UserServlet:
public class UserServlet
{
private IUserDao dao; //依赖对象
public void doPost(){
dao.addUser();
dao.delUser();
dao.updateUser();
}
}
com.test.Test:
public static void main(String[] args) {
UserServlet servlet = new UserServlet();
servlet.doPost();
}
1) 使用 setter 方法注入
2) 使用构造函数的方式注入
3) 使用静态工厂注入
4) 使用实例工厂注入
1) 使用 setter 方法注入
public class UserServlet
{
private IUserDao dao; //依赖对象
public void setDao(IUserDao dao) { //要提供一个set方法
this.dao = dao;
}
public void doPost(){
dao.addUser();
dao.delUser();
dao.updateUser();
}
}
配置文件
beans.xml:
<bean name="userServlet_name" class="com.servlet.UserServlet" >
<property name="dao" ref="userDao_name" />
</bean>
<bean name="userDao_name" class="com.dao.UserDaoImpl" />
测试
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
UserServlet servlet=ctx.getBean("userServlet_name",UserServlet.class);
servlet.doPost();
}
附,上面的关联配置,也可以用内部bean的方式
<bean name="userServlet_name" class="com.servlet.UserServlet" >
<property name="dao" >
<bean class="com.dao.UserDaoImpl">
</property>
</bean>
2) 使用构造函数的方式注入
public class UserServlet
{
//希望 Spring 由构造函数注入依赖对象
UserServlet(IUserDao dao){ //提供一个构造函数
this.dao=dao;
}
/*UserServlet(IUserDao dao,UserInfo user,String address){ //提供一个构造函数
this.dao=dao;
System.out.println(user);
System.out.println(address);
}*/
private IUserDao dao; //依赖对象
public void doPost(){
dao.addUser();
dao.delUser();
dao.updateUser();
}
}
beans.xml:
<bean name="userInfo_name" class="com.beans.UserInfo" >
<property name="id" value="100" />
<property name="userName" value="赵强" />
<property name="password" value="123" />
<property name="school" value="沙河农场子弟校" />
</bean>
<bean name="userServlet_name" class="com.servlet.UserServlet" >
<constructor-arg ref="userDao_name" /> //构造函数的顺序也得一致
<constructor-arg ref="userInfo_name" />
<constructor-arg value="江北学院路" />
</bean>
<bean name="userDao_name" class="com.dao.UserDaoImpl" />
3) 静态工厂方法注入
UserServlet:
public class UserServlet
{
private IUserDao dao; //依赖对象
public void doPost(){
dao.addUser();
dao.delUser();
dao.updateUser();
}
public IUserDao getDao() {
return dao;
}
public void setDao(IUserDao dao) {
this.dao = dao;
}
}
//工厂,用来生成dao的实现类
com.dao.UserDaoFactory:
public class UserDaoFactory {
public static IUserDao getUserDaoInstance(){
return new UserDaoImpl();
}
/* public static IUserDao getUserDaoInstanceORCL(){
return new UserDaoImplORCL();
}*/
}
beans.xml:
<bean name="userServlet_name" class="com.servlet.UserServlet" >
<property name="dao" ref="userDao_name" />
</bean>
<bean name="userDao_name" class="com.dao.UserDaoFactory" factory-method="getUserDaoInstance" />
4) 实例工厂方式 略 (和静态差不多,不加static)
工厂 =>
public class UserDaoFactory {
//这个方法不是静态的
public IUserDao createUserDaoInstance(){
return new UserDaoOracleImpl();
}
}
配置文件
<bean name="useServlet_name" class="com.servlet.UserServlet" >
<property name="dao" ref="userDao_name" />
</bean>
<bean name="userDaoFactory_name" class="com.dao.UserDaoFactory" />
<bean name="userDao_name" factory-bean="userDaoFactory_name" factory-method="createUserDaoInstance" />
5 Bean的作用域
用spring管理的bean 是单实例,还是多实例的呢
beans.xml:
<bean name="userServlet_name" class="com.servlet.UserServlet"></bean>
UserServlet:
public void test(){
syso("test");
}
Test:
ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
UserServlet servlet1=ctx.getBean("userServlet_name",UserServlet.class);
UserServlet servlet2=ctx.getBean("userServlet_name",UserServlet.class);
System.out.println(servlet1== servlet2); //true 可以发现,默认情况下,是单实例 ,true 代码是同一块内存空间
bean的作用域
1) singleton 单实例 默认
2) prototype 多实例
3) request
3) session
4) global-session 类似于标准的 HTTP Session作用域,不过它仅仅在基于 portlet 的web应用中才有意义。
1) singleton 单实例 默认
单实例,在容器启动的时候初始化
默认情况下,在容器启动的时候就创建了,如果不想在容器初始化的时候创建,可以 用 lazy-init="true"
<bean name="userServlet_name" class="com.servlet.UserServlet" lazy-init="true" />
如果配置文件中所有的bean都要晚创建 ,也可以写在全局的beans 标标上
<beans
default-lazy-init="true" //用这个配置
xmlns="http://www.springframework.org/schema/beans"
....
</beans>
典型情况下,dao 都会配置成单实例
2) prototype 多实例
多实例, 每次从容器得到的bean都是一个新的对象
<bean name="userServlet_name" class="com.servlet.UserServlet" scope="prototype" />
什么时候用单实例的bean,什么时候用多实例
没有线程问题的时候,用 单实例
例子 单实例引发的线程问题
UserServlet:
public class UserServlet {
public UserInfo user;
}
Test:
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
UserServlet servlet1=ctx.getBean("userServlet_name",UserServlet.class);
servlet1.user=new UserInfo(1,"admin","pwd","Sccc");
UserServlet servlet2=ctx.getBean("userServlet_name",UserServlet.class);
System.out.println(servlet2.user.getUserName()); // 如果配置成单例,这里会输出admin, 如果是多例,会抛空指针异常
System.out.println(servlet1== servlet2);
}