Spring
什么是Spring
Spring是以IoC控制反转和AOP面向切面编程为内核,使用简单的JavaBean来完成以前只可能由EJB完成的工作,取代了EJB臃肿的开发方式。
Spring的优点
- 非侵入性式设计
- 方便解耦,简化开发
- 支持AOP
- 支持声明式事务处理
- 方便程序的测试
- 方便集成各种优秀框架
Spring的体系结构
Core Container(核心容器)
主要由Beans模块,Core模块,Context模块,Context-support模块和SpEL(spring表达式语言)模块组成。
Beans模块
提供了BeanFactory,是工厂模式的经典实现,Spring将管理对象称为Bean。
Core核心模块
提供了Spring框架的基本组成部分,包括IoC和DI功能(注解驱动)
Context上下文模块
建立在Core和Beans模块的基础之上,它是访问定义和配置的任何对象的媒介。其中ApplicationContext接口是上下文模块的焦点
Context-support模块
提供了对第三方库嵌入Spring应用的集成支持,比如缓存、邮件服务、任务调度和模板引擎
SpEL模块
是Spring3.0后新增的模块,它提供了Spring Expression Language支持,是运行时查询和操作对象图的强大的表达式语言。
Data Access/Intergation(数据访问/集成)
数据访问/集成层包括JDBC、ORM、OXM、JMS和Transfaction模块,具体介绍如下。
JDBC模块
提供了一个JDBC的抽象层,大幅度减少了在开发过程中对数据库操作的编码
ORM模块
对流行的对象关系映射包括API,包括JPA、JDO和Hibernate提供了集成层
OXM模块
提供了一个支持对象/XML映射的抽象层实现
JMS模块
指Java消息传递服务,包含使用和产生信息的特性
Web
Spring的Web层包括WebSocket、Servlet、Web和Portlet模块,具体介绍如下。
WebSocket模块
Spring4.0后新增的模块,提供了WebSocket和SockJS的实现,以及对STOMP的支持。
Servlet模块
也称为Spring-webmvc模块,包含了Spring的模型-视图-控制器(MVC)和REST Web Services实现的Web应用程序。
Web模块
提供了基本的Web开发集成特性,例如:多文件上传功能,使用Servlet监听器来初始化IoC容器以及Web应用上下文。
Portlet模块
提供了在Portlet环境中使用MVC实现,类似于Servlet模块的功能。
其他模块
Test模块
提供了对单元测试和集成测试的支持
Aspect模块
提供了与AspectJ的集成功能,AspectJ是一个成熟的面向切面编程框架
AOP模块
提供了面向切面编程实现,允许定义方法拦截器和切入点,将代码按照功能进行分离,以降低耦合性。
Instrumentation模块
提供了类工具的支持和类加载器的实现,可以在特定的应用服务器中使用
Messaging模块
Spring4.0后新增的模块,它提供了对消息传递体系结构和协议的支持
Spring的核心容器
Spring提供了两种核心容器,分别为BeanFactory和ApplicationContext
Beanfactory
BeanFactory由org.springframework.beans.factory.BeanFactory接口定义,是基础类型的IoC容器。提供了完整的IoC服务支持。BeanFactory就是一个管理Bean的工厂,它主要负责初始化各种Bean,并调用它们的生命周期方法。
BeanFactory接口提供了几个实现类,其中最常用的是org.springframework.beans.factory.xml.XmlBeanFactory,该类会根据XML配置文件中的定义来装配Bean
创建BeanFactory实例时,需要提供Spring所管理容器的详细配置信息,这些信息通常采用XML文件形式来管理,其加载配置信息的语法如下:
BeanFactory beanFactory=
new XmlBeanFactory(new FileSystemResource("D:/applicationContext.xml"));
但这种形式并不常用
ApplicationContext
ApplicationContext是BeanFactory的子接口,也被称为应用上下文,是另一种常用的Spring核心容器。它由org.springframework.context.AppliactionContext定义,不仅包含了BeanFactory的所有功能。
创建ApplicationContext接口实例
,通常采用两种方法
通过ClassPathXmlApplicationContext创建
ClassPathXmlApplicationContext会从类路径classpath中寻找指定的XML配置文件,找到并装载完成ApplicationContext的实例化工作,其使用语法如下。
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext(String configlocation);
上述代码中,configlocation参数用于指定Spring配置文件的名称和位置。如果其值为“applicationContext.xml”,则Spring会去类路径中查找名称为applicationContext.xml的配置文件。
通过FileSystemXmlApplicationContext创建
FileSystemXmlApplicationContext会从指定的文件系统路径(绝对路径)中寻找指定的XML配置文件,找到并装载完成ApplicationContext的实例化工作,使用语法如下:
ApplicationContext applicationContext =
new FileSystemXmlApplicationContext(String configLocation);
与ClassPathXmlApplicationContext有所不同的是,在读取了Spring 文件时,FileSystemXmlApplicationContext不再从类路径中读取配置文件,而是通过参数指定配置文件的位置,例如“D:/workspaces/applicationContext.xml”。如果在参数中写的不是绝对路径,那么方法调用的时候,会默认用绝对路径来找。这种采用绝对路径的方式,会导致,程序灵活性变差,所以这种方法一般不推荐使用。
在使用Spring框架时,可以通过实例化其中任何一个类来创建ApplicationContext容器。通常在Java项目中,会采用``通过ClassPathXmlApplicationContext类来实例化ApplicationContext容器的方式
,而在Web项目中
,ApplicationContext容器的实例化工作会交由Web服务器来完成。Web服务器实例化ApplicationContext容器时,通常使用基于ContextLoaderListener
实现的方式,此种方式只需要在web.xml文件中添加如下代码。
<!-- 指定Spring配置文件的位置,多个配置文件时,以逗号分隔-->
<context-param>
<param-name>contextConfigLocation</param-name>
<!-- Spring将加载spring目录下的applicationContext.xml文件-->
<param-value>
classpath:spring/applicationContext.xml
</param-value>
</context-param>
<!--指定以ContextLoaderListener方式启动Spring容器-->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
创建Spring容器后,就可以获取Spring容器中的Bean。Spring获取Bean的实例通常采用以下两种方法。
- Object getBean(String name):根据容器中Bean的id或name来获取指定的Bean,获取之后需要进行强制类型转换。
- T getBean(Class requiredType): 根据类的类型来获取Bean的实例。由于此方法为泛型方法,因此在获取Bean之后不需要进行强制类型转换。
Bonus
在实际开发中,通常优先选择使用ApplicationContext,而只有在系统资源较少的时候,才考虑使用BeanFactory。
调用时通常遵循
(类型转换)applicationContext.getBean()
实际演示
- 首先创建Web项目并在lib下添加这五个包
-
然后在src下创建一个名为"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" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <bean id = "UserDao" class="com.itheima.ioc.UserDaoImpl"/> </beans>
-
创建一个com.itheima.ioc 的包并在包里创建接口UserDao,然后在接口中定义一个方法
package com.itheima.ioc; public interface UserDao { public void say(); }
-
在com.itheima.ioc包下创建一个实现UserDao接口的实现类UserDaoImpl,该类需要实现接口中say()方法。
package com.itheima.ioc; public class UserDaoImpl implements UserDao{ @Override public void say() { System.out.println("Hello"); } }
-
创建测试类TestIoC并在类中编写main()方法。在main()方法中,需要初始化Spring容器,并加载配置文件,然后通过Spring容器获取userDao实例(即Java对象),最后调用实例化的方法
package com.itheima.ioc; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestIoC { public static void main(String[] args) { //1.初始化spring容器,加载配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //2.通过容器获取userDao实例 UserDao userDao = (UserDao) applicationContext.getBean("UserDao"); //3.调用实例中的say()方法 userDao.say(); } }
输出结果为:
在main()方法中,并没有通过new关键字来创建UserDao接口的实现对象,而是通过Spring容器来获取的实现类对象,这就是Spring IoC容器的工作机制。
依赖注入(DI)
依赖注入的概念
当某个对象需要需要调用另一个Java对象(即依赖对象)时,在传统模式下,调用者通常会采取“new 被调用者”的代码来创建对象,这种方式会导致调用者与被调用者之间的耦合性增加,不利于后期项目的升级和维护
在使用spring框架之后,对象的实例不再有调用者来创建,而是由Spring容器来创建,Spring容器会负责控制程序之间的关系,而不是由调用者的程序代码直接控制。
这样,控制权由应用代码转移到了Spring容器,控制权发生了反转,这就是控制反转。
依赖注入的实现方式
实现方式一般有两种,分别为属性setter方法注入,构造方法注入
setter方法注入
-
首先在com.itheima.ioc 包中,创建接口UserService,在接口中编写一个say()方法
package com.itheima.ioc; public interface UserService { public void say(); }
-
在com.itheima.ioc 包中,创建UserService 接口的实现类UserServiceImpl ,在类中声明userDao属性,并添加属性的setter方法
package com.itheima.ioc; public class UserServiceImpl implements UserService { // 声明UserDao属性 private UserDao userDao; // 添加UserDao属性的setter方法,用于实现依赖注入 public void setUserDao(UserDao userdao) { this.userDao = userdao; } // 实现的接口中的方法 @Override public void say() { // 调用userDao中的say()方法,并执行输出语句 this.userDao.say(); System.out.println("service hello"); } }
-
在配置文件applicationContext.xml 中,创建一个 id 为 userService 的Bean,该Bean用于实例化UserServiceImpl 类的信息,并将 userDao 的实例注入到了 userService 中,其代码如下所示
<?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"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<bean id="userDao" class="com.itheima.ioc.UserDaoImpl" />
<bean id= "userService" class= "com.itheima.ioc.UserServiceImpl">
<!-- 将id为userDao的Bean实例注入到userService实例中 -->
<property name="userDao" ref = "userDao"></property>
</bean>
</beans>
上述代码中,是的子元素,它用于调用Bean实例中的setUserDao()方法完成属性赋值,从而实现依赖注入。其name
属性表示Bean 实例中的相应属性名, ref
用于指定其属性值
- 在com.itheima.ioc包中,创建测试类TestDI,来对程序进行测试,编辑后如下所示
package com.itheima.ioc;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestDI {
public static void main(String[] args){
//1.初始化spring容器,加载配置文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
//2.通过容器获取UserService实例
UserService userService =
(UserService) applicationContext.getBean("userService");
userService.say();
}
}
执行程序之后,控制台输出结果为
这里需要注意,注意,注意,注意
使用setter方法进行注入的时候,在对xml文件里面bean对象赋值的时候,编程格式为:
<bean>
<property name="" ref="">
</property>
</bean>
一定不要忘了下面的
总结
实现spring的bean注入的一般步骤
-
首先在xml文件中创建对应类的bean对象,书写的格式为
<bean id="bean对象的名字" class="对应实现类的路径">
-
创建Java文件,首先初始化spring 容器,加载配置文件,采用的方法一般是使用“ClassPathXmlApplicationContext+“xml文件名的方式”,这样的好处在于是从类路径中读取文件,比起FileSystemXmlApplicationContext 通过绝对路径查找的方式查找会显得更加的灵活
-
第二步是通过容器获取类的实例,主要是通过 applicationContext.getBean(“bean的id”) 的方式
-
最后是调用实例中的方法。