一、初识Spring框架
1、Spring框架是什么?
Spring框架是一个分层的JavaEE轻量级开源框架,它以IoC和AOP为内核,使用最基本的JavaBean来完成工作。
2、Spring的优点
1-非侵入式设计:使应用程序代码对框架的依赖最小化。
2-方便解耦、简化开发:将所有对象的创建和依赖关系的维护工作交由Spring容器管理。
3-支持AOP:将一些通用任务,如事务处理,日志记录等集中处理,提高了代码的复用性。
4-支持声明式事务处理:通过配置即可完成事务的处理。
5-方便程序的测试:集成了Junit4,使用注解完成程序的测试
6-方便集成各种优秀框架
7-降低了JavaEE API的使用难度:对一些较难使用的API,如JDBC等进行了封装。
3、Spring框架的体系结构
主要模块介绍:
(1)Beans模块:提供了BeanFactory,是工厂模式的典型实现。
(2)Core核心模块:提供了Spring框架的基本组成部分,包括IoC和DI功能。
(3)Context模块:建立在Beans模块和Core模块的基础之上。它是访问定义和配置任何对象的媒介,其中ApplicationContext接口是上下文模块的焦点。
(4)SpEL模块:Spring3.0后新增的模块,是运行时查询和操作对象图的强大表达式语言。
(5)AOP模块:提供了面向切面编程实现,允许定义方法拦截器和切入点,将代码按照功能进行分离,以降低耦合性。
(6)AspectJ模块:提供了与AspectJ的集成功能。AspectJ是一个功能强大且成熟的面向切面编程(AOP)的框架
(7)Web模块:提供了基本的Web开发集成特性,如多文件上传功能,使用Servlet监听器初始化IoC容器,以及Web应用上下文。
(8)Servlet模块:也成为Spring-webmvc模块,它包含了Spring的MVC和REST Web Service实现的Web应用程序。
(9)JDBC模块:提供了一个JDBC的抽象层,大幅度减少了对数据库操作的编码。
(10)ORM模块:提供了对流行的对象关系映射API。
(11)Transaction模块:提供了支持对实现特殊接口,以及所有POJO类的编程和声明式的事务管理。
(12)Test模块:提供了对单元测试和集成测试的支持。
二、Spring的核心容器
Spring框架的主要功能是通过其核心容器来实现的,Spring框架提供了两种核心容器:BeanFactory和ApplicationContext。
1、BeanFactory
BeanFactory是基础的IoC容器,它提供了完整的IoC服务支持。简单的说,BeanFactory是一个管理Bean的工厂,它主要负责初始化各种Bean,并调用它们的生命周期方法。加载该容器的方法(不常用):
BeanFactory beanFactory=new XmlBeanFactory(new FileSystemResources("F:/applicationContext.xml"));
2、ApplicationContext
ApplicationContext是BeanFactory的子接口,也被称为应用上下文。不仅包含了BeanFactory的所有功能,还添加了对国际化,资源访问、事件传播等方面的支持。创建ApplicationContext接口实例通常采用两种方式:
(1)ClassPathXMLApplicationContext
ClassPathXMLApplicationContext会从类路径classpath中寻找指定的xml配置文件,找到并加载配置文件完成ApplicationContext的初始化工作。
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
(2)FileSystemXmlApplicationContext
FileSystemXmlApplicationContext会使用绝对路径加载配置文件。
ApplicationContext context=new FileSystemXmlApplicationContext("D:/applicationContext.xml");
在单独使用Spring框架时,可采取以上任意一种方式完成ApplicationContext的初始化工作。在web项目中,ApplicationContext容器的初始化工作会交给Web服务器来完成。Web服务器基于ContextLoaderListener来完成ApplicationContext的实例化。此种方式需要在web.xml文件中添加以下代码:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
初始化容器后,可以通过以下两种方法获取容器中的bean:
根据容器中bean的id或name获取
Object getBean(String name);
根据类型获取bean的实例
<T> T getBean(Class<T> requiredType);
三、Spring框架的入门程序
1、项目结构
注意:Spring框架的运行依赖于commons-logging组件。
2、类定义
JavaBean:HelloSpring .java
public class HelloSpring {
//通过Spring框架赋值
private String text;
public HelloSpring() {}
public HelloSpring(String text) {
this.text=text;
}
public void print() {
System.out.println(text);
}
public void setText(String text) {
this.text=text;
}
public String getText() {
return text;
}
}
测试类:HelloTest.java
public class HelloTest {
public static void main(String[] args) {
//初始化AapplicationContext容器
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
//通过类型的方式获取Bean
HelloSpring h1=context.getBean(HelloSpring.class);
h1.print();
//通过bean的id获取Bean
HelloSpring h2=(HelloSpring)context.getBean("helloSpring");
System.out.println(h2.getText());
//判断得到的两个对象是否相同
System.out.println("h1 == h2 :"+(h1 == h2));
}
}
3、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-3.0.xsd">
<!-- id:唯一指定Bean在容器中的名字 class:指定Bean的类型-->
<bean id="helloSpring" class="com.tracker.pojo.HelloSpring">
<!-- 调用setText()方法给属性赋值 ,注意命名规范:name属性值应该是setXXX()中的XXX-->
<property name="text">
<value>Hello,Spring</value>
</property>
</bean>
</beans>
4、控制台输出
从上述例子中可以发现,Spring框架会自动接管配置文件中Bean的创建并为属性赋值,而不用在程序中使用new关键字主动创建Bean和管理。
四、依赖注入(DI)和控制反转(IoC)
1、概念理解
依赖注入(Dependency Injection)与控制反转(Inversion of Control)的含义相同,只不过是从两种角度描述同一个概念。
在传统方式中,一个Java对象(调用者)需要调用另一个Java对象(被调用者,即被依赖对象)时,需要使用“new 被调用者”的方式来创建对象。这种方式会导致调用者与被调用者之间的耦合度增加,不利于后期维护。
在Spring框架中,对象的实例不再由调用者来创建,而是由Spring容器来创建管理。创建对象的控制权由应用代码转移到Spring容器,控制权发生反转,这就是控制反转。
从Spring框架容器的角度来看,它负责将被依赖对象赋值给调用者的成员变量,相当于为调用者注入了其依赖实例,这就是依赖注入。
可以说,IoC是一种设计理念,DI是IoC的具体实现。
2、依赖注入的实现方式
(1)属性setter方法注入
<bean id="helloSpring" class="com.tracker.pojo.HelloSpring">
<!-- 调用setter方法给属性赋值 -->
<property name="text">
<value>Hello,Spring</value>
</property>
</bean>
(2)构造方法注入
<bean id="helloSpring" class="com.tracker.pojo.HelloSpring">
<!-- 调用构造方法给属性赋值 -->
<constructor-arg index="0" value="Hello,Spring!"/>
<!--或: <constructor-arg name="text" value="Hello,Spring!"/>-->
</bean>
3、控制反转的优点
在Spring框架中,bean与bean之间的依赖关系都放在配置文件里组织,而不是写在代码里,将bean的创建和依赖注入交由Spring容器进行管理,大大降低了bean之间的耦合度,方便后期维护。
五、Spring框架中的Bean
1、Bean的配置
在Spring的配置文件中,通过<bean>标签定义一个JavaBean。其属性和子元素如下:
注意:如果在Bean中未指定id或name属性,则Spring会将class值当做id属性使用。
2、Bean的实例化
在Spring中,实例化Bean有三种方式:
(1)方式一:构造器实例化
<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-3.0.xsd">
<bean id="helloSpring" class="com.tracker.pojo.HelloSpring"></bean>
</beans>
(2)方式二:静态工厂方式实例化
public class MyBeanFactory{
public static HelloSpring createBean(){
return new HelloSpring();
}
}
<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-3.0.xsd">
<!--class:指定静态工厂 factory-method:指定创建bean实例的方法-->
<bean id="helloSpring" class="com.tracker.factory.MyBeanFactory"
factory-method="createBean"></bean>
</beans>
(3)方式三:实例工厂方式实例化
public class MyBeanFactory{
public HelloSpring createBean(){
return new HelloSpring();
}
}
<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-3.0.xsd">
<!--配置实例工厂-->
<bean id="myfactory" class="com.tracker.factory.MyBeanFactory"/>
<!--factory-bean:指定工厂实例 factory-method:指定创建bean实例的方法-->
<bean id="helloSpring" factory-bean="myfactory" factory-method="createBean"/>
</beans>
3、Bean的装配方式
Bean的装配可以理解为依赖关系注入,Spring容器常用的三种装配方式:基于XML的装配,基于注解的装配,自动装配。
(1)基于XML的装配
基于XML的装配有两种方式:设值注入、构造注入。
设值注入要求一个Bean必须满足两个要求:1.提供一个默认的无参构造器 2.为需要注入的属性提供对应的setter方法
构造注入要求Bean必须提供有参构造器,使用<constructor-arg>标签注入。
不同类型注入方式:
<bean id="helloSpring" class="com.tracker.pojo.HelloSpring"></bean>
<bean id="bean1" class="com.tracker.pojo.User">
//基本类型、String、Integer等类型注入
<property name="username" value="zhangsan"></property>
//外部Bean注入
<property name="bean1" ref="helloSpring"></property>
//内部Bean注入
<property name="helloBean">
<bean class="com.tracker.pojo.HelloBean">
</property>
//List集合使用<list>,Set集合使用<set>,数组使用<array>
<property name="list">
<list>
<value>Java</value>
<value>Spring</value>
</list>
</property>
//Map类型
<property name="map">
<entry>
<key>
<value>key</value>
</key>
<value>value</value>
//如果键或值是Bean对象,可以把<value>换成<ref>
</entry>
</property>
//注入null值,如果注入空字符串,直接使用<value></value>
<property name="nullValue">
<null/>
</property>
</bean>
提示:如果属性值中包含XML中的特殊字符(&,<,>,",'),则注入时需要进行处理。
有两种方式:1.使用<![CDATA[特殊字符]]> 2.使用特殊字符的实体引用,例如“&”可以用“&”表示
(2)基于注解的装配方式
使用注解定义Bean:
注解名称 | 说明 |
---|---|
@Component | 表示一个Bean组件。泛化概念,可以标注在任何层次上 |
@Repository | 将Dao层的类标识为一个Spring组件 |
@Service | 将Service层的类标识为一个Spring组件 |
@Controller | 将Controller层的类标识为一个Spring组件 |
以上4个注解的作用都相同,被这些注解标注的类会创建一个实例被加入到Spring容器中。开发中常用使用此种方式。
//@Service("userService") 指定Bean的名字
@Service
public class UserServiceImpl{}
使用注解实现依赖注入(基于注解的自动装配):
注解名称 | 说明 | 参数 |
---|---|---|
@Autowired | 用于对Bean的属性变量,属性的Setter方法和构造方法进行标注,以配合对应的注解处理器完成Bean的自动配置工作,默认按照Bean的类型进行装配 | required:指定装配的Bean是否必须,默认:true |
@Resource | 作用与@Autowired一样,默认按照Bean的实例名称进行装配(不写参数),再按照类型进行匹配。 | name:指定Bean的名称 。type:指定Bean的类型 |
@Qualifier | 与@Autowired注解配合使用,会按照Bean的实例名称进行装配,名称由@Qualifier的参数指定 | value:指定Bean的名称,默认:“” |
@Controller
public class UserController{
//@Resource Java提供的注解,不写参数时先按Bean的名称装配,找不到按类型装配
//@Qualifier("userService") 与@Autowired 一起使用,按Bean的名称装配
@Autowired //Spring提供的注解
private UserService userService;
@Autowired
public void setUserService(@Qualifier("userService")UserService userService){}
}
使用注解装配,需要在配置文件中开启Spring的组件扫描功能:
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!--开启组件扫描功能,base-package:指定要扫描的包,有多个包可使用逗号隔开-->
<context:component-scan base-package="com.tracker"/>
</beans>
首先要在配置文件引入context命名空间的声明,开启注解扫描功能后,Spring会扫描指定包中的所有类,以获取Bean的定义信息。
提示:spring4.0以上版本在使用注解装配时,需要向项目中引入Spring AOP的JAR包
(3)基于XML的自动装配方式
在<bean>元素中包含一个autowired属性,可以通过该属性来实现自动装配。
autowired属性值:
属性值 | 说明 |
---|---|
default | 默认。由标签中的default-autowired属性值确定。 |
byName | 根据属性名自动装配。找出Bean的id属性与setter方法匹配的Bean进行自动注入,否则什么也不做 |
byType | 根据属性类型自动装配。找出与依赖属性类型相同的Bean进行注入。如果有多个匹配就抛出异常,如果没有就什么都不做 |
constructor | 与byType的方式类似,应用于构造器参数 |
no | 在默认情况下不使用自动装配,Bean的依赖必须通过ref元素定义 |
<bean id="userDao" class="com.tracker.pojo.UserDaoImpl"></bean>
<bean id="userService" class="com.tracker.pojo.UserServiceImpl" autowire="byName"></bean>
4、Bean的作用域
作用域名称 | 说明 |
---|---|
singleton (单例) | 默认值,该模式下Bean在Spring容器中只有一个实例,,每次获取都返回同一个实例 |
prototype(原型) | 每次获取时,Spring容器都会创建一个新的实例返回 |
request | 再一次Http请求中,容器会返回该Bean的同一个实例,对不同的HTTP请求产生一个新的Bean,且该Bean只在当前HTTP request内有效 |
session | 与request相同,只是作用域提升到Session |
global session | 在一个全局的HTTP Session中,容器会返回该Bean的同一个实例,仅在使用portlet上下文时有效 |
application | 为每一个ServletContext对象创建一个实例,仅在web相关的ApplicationContext中生效 |
websocket | 为每个websocket对象创建一个实例,仅在web相关的ApplicationContext中生效 |
指定Bean的作用域:
<bean id="user" calss="User" scope="prototype"></bean>
@Scope("singleton")
@Service
public class UserServiceImpl{}
5、Bean的生命周期
Spring框架的容器可以管理Singleton作用域的Bean的声明周期,在此作用域下,Spring容器可以精确的知道该Bean何时被创建、何时初始化完成以及何时被销毁、对于prototype作用的Bean,Spring只负责创建,当容器创建了Bean的实例后就交给客户端代码来管理。
Bean的生命周期执行过程:
(1)根据配置情况实例化Bean
(2)利用依赖注入完成Bean中所有的属性值的配置注入
(3)如果Bean实现了BeanNameAware接口,则Spring调用Bean的setBeanName()方法传入当前Bean的id值
(4)如果Bean实现了BeanFactoryAware接口,则Spring调用setBeanFactory()方法传入当前工厂实例的引用
(5)如果Bean实现了ApplicationContextAware接口,则Spring调用setApplicationContext()方法传入当前ApplicationContext实例的引用
(6)如果BeanPostProcesso和Bean关联,则Spring将调用该接口的预初始化方法postProcessBeforeInitialization()对Bean进行加工操作,Spring的AOP就是通过它实现的
(7)如果Bean实现了InitializingBean接口,则Spring将调用afterPropertiesSet()方法。
(8)如果在配置文件中通过init-method属性定义了初始化方法,则调用该初始化方法
(9)如果有BeanPostProcessor和Bean关联,则Spring将调用该接口的初始化方法postProcessAfterInitialization()。此时,Bean已经可以被系统使用了
(10)如果在<bean>中指定了该Bean的作用范围为Singleton,则将该Bean放入SpringIoC缓存池中,将触发Spring对该Bean的生命周期管理。如果指定为prototype,则将该Bean交给调用者。由调用者管理该Bean的生命周期
(11)如果Bean实现了DisposableBean接口,则Spring会调用destory()将Spring中的Bean销毁;可以在配置文件中通过destory-method属性指定Bean的销毁方法