一、Spring 框架概述
Spring 是一个分层的 Java SE/EE full-stack 轻量级开源框架,以 IoC 和 AOP 为内核,具有方便解耦、方便集成优秀框架、降低 Java EE API 使用难度等优点。
Spring 框架因其强大的功能以及卓越的性能而受到众多开发人员的喜爱。它是分层的 Java SE/EE full-stack 轻量级开源框架,以 IoC(Inverse of Control,控制反转)和 AOP(Aspect Oriented Programming,面向切面编程)为内核,使用基本的 JavaBean 完成以前只可能由 EJB 完成的工作,取代了 EJB 臃肿和低效的开发模式。
在实际开发中,通常服务器端采用三层体系架构,分别为表现层(web)、业务逻辑层(service)、持久层(dao)。Spring 对每一层都提供了技术支持,在表现层提供了与 Struts2 框架的整合,在业务逻辑层可以管理事务和记录日志等,在持久层可以整合 Hibernate 和 JdbcTemplate 等技术。
从设计上看,Spring 框架给予了 Java 程序员更高的自由度,对业界的常见问题也提供了良好的解决方案,因此,在开源社区受到了广泛的欢迎,并且被大部分公司作为 Java 项目开发的首选框架。Spring 具有简单、可测试和松耦合等特点,不仅可以用于服务器端的开发,也可以应用于任何 Java 应用的开发中。
Spring 框架的主要优点具体如下:
- 方便解耦,简化开发:Spring 就是一个大工厂,可以将所有对象的创建和依赖关系的维护交给 Spring 管理。避免了硬编码所造成的过度程序耦合,用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
- 方便集成各种优秀框架:Spring 不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如 Struts2、Hibernate、MyBatis 等)的直接支持。
- 降低 Java EE API 的使用难度:Spring 对 Java EE 开发中非常难用的一些 API(JDBC、JavaMail、远程调用等)都提供了封装,使这些 API 应用的难度大大降低。
- 方便程序的测试:Spring 支持 JUnit4,可以通过注解方便地测试 Spring 程序。
- AOP 编程的支持:Spring 提供面向切面编程,可以方便地实现对程序进行权限拦截和运行监控等功能。
- 声明式事务的支持:只需要通过配置就可以完成对事务的管理,而无须手动编程。
二、Spring 框架核心功能
Spring 的核心容器由 beans、core、context 和 expression 模块组成,具体如下:
1. 核心容器
由 beans、core、context 和 expression 模块组成,实现了控制反转和依赖注入,管理 bean 对象之间的依赖关系。
一、Spring-core 模块
Spring-core 是 Spring 框架中的核心模块,提供了许多基础支持和工具类,包括资源管理、依赖注入、AOP、事件处理等功能。在 SSM 框架中使用 Spring-core 可以更加方便地实现这些功能。
二、Spring-beans 模块
Spring-beans 模块是 Spring 框架的核心模块之一,它提供了 IoC 容器的基本实现,即 BeanFactory 和 ApplicationContext。在 Spring 中,所有的对象都被称为 bean,并且由 IoC 容器来管理和创建它们。BeanFactory 是一个根据配置文件或者注解配置来创建并管理 bean 的工厂。它主要负责 bean 的实例化、属性赋值、依赖注入等任务,但是它只有在被调用时才会进行 bean 的初始化和创建,因此它具有延迟加载的特点。而 ApplicationContext 则是 BeanFactory 的子接口,它在 BeanFactory 的基础上增加了更多的功能,如国际化支持、事件机制、AOP 等。与 BeanFactory 不同,ApplicationContext 在容器启动时就完成了 bean 的初始化、依赖注入等操作,因此它没有延迟加载的特点。
三、Spring-context 模块
Spring-context 模块是 Spring 框架的核心模块之一,提供了 Spring 框架必需的基本功能和面向切面编程、IoC 容器、依赖注入等高级特性。它主要包含以下四个方面的功能:
- Spring IoC 容器:它是 Spring 框架的核心组件,负责创建对象并维护对象之间的依赖关系。
- Spring AOP 框架:面向切面编程(AOP)是 Spring 框架的一个重要特性,Spring-context 中提供了 AOP 相关的支持和实现。
- Spring 事件框架:Spring-context 还提供了事件机制,能够让系统中的各个组件之间进行消息传递和通信。
- Spring SPI 支持:SPI 即 Service Provider Interface,是一种 Java 标准化的服务发现机制,Spring-context 提供了对 SPI 的支持。
四、Spring-context-support 模块
Spring-context-support 模块是 Spring 框架的一个支持模块,它提供了一些 Context 相关的实用工具类和 bean 定义读取器。这些工具类可以帮助我们更方便地配置和管理 Spring 应用程序中的 bean。
五、Spring-expression 模块
提供了强大的表达式语言去支持运行时查询和操作对象图。这是对 JSP2.1 规范中规定的统一表达式语言(Unified EL)的扩展。该语言支持设置和获取属性值,属性分配,方法调用,访问数组,集合和索引器的内容,逻辑和算术运算,变量名以及从 Spring 的 IOC 容器中以名称检索对象。它还支持列表投影,选择以及常见的列表聚合。
三、Spring 框架综合应用方法
1. 通过配置 XML 文件实现 AOP
使用 MethodBeforeAdvice、AfterReturningAdvice、MethodInterceptor、ThrowsAdvice 等接口,配置 XML 文件实现 AOP。
在 Spring 框架中,AOP(Aspect Oriented Programming,面向切面编程)可以通过配置 XML 文件来实现。AOP 的核心概念包括目标对象(Target)、代理(Proxy)、连接点(Joinpoint)、切入点(Pointcut)、通知(Advice)和切面(Aspect)。
目标对象是代理的目标,代理是一个类被 AOP 织入增强后产生的结果代理类。连接点是指那些被拦截到的点,在 Spring 中这些点指的是方法。切入点是对哪些 Joinpoint 进行拦截的定义,通知是拦截到 Joinpoint 之后要做的事情,切面是切入点和通知的结合。织入是把增强应用到目标对象来创建新的代理对象的过程,Spring 采用动态代理织入。
以下是通过配置 XML 文件实现 AOP 的步骤:
- 搭建环境,如果是 Maven 项目,可以直接导入一个 spring-mvc web 的包。
- 创建通知类(代理)和实体类。
- 创建 XML 文件,导入 context 和 aop 的命名空间。
- 在 XML 文件中配置 AOP:
-
- 使用<context:component-scan>标签扫描包,找到需要进行 AOP 的类。
-
- 使用<bean>标签定义目标对象和通知类。
-
- 使用<aop:config>标签开始 AOP 的配置。
-
- 使用<aop:pointcut>标签设置切入点表达式,指定要增强的方法。
-
- 使用<aop:aspect>标签配置切面,将通知应用到切入点。
-
- 根据需要选择不同类型的通知,如<aop:before>(前置通知)、<aop:after>(后置通知)、<aop:after-returning>(返回通知)、<aop:after-throwing>(异常通知)和<aop:around>(环绕通知)。
例如:
<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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="JDKProxy.pojo"/>
<bean id="student" class="JDKProxy.pojo.Student"/>
<bean id="studentproxy" class="JDKProxy.pojo.StudentProxy"/>
<aop:config>
<!-- 设置切入点-->
<aop:pointcut id="p" expression="execution(* JDKProxy.pojo.Student.show(..))"/>
<aop:aspect ref="studentproxy">
<aop:before method="before" pointcut-ref="p"/>
</aop:aspect>
<!-- 给学习方法设置好通知-->
<aop:config>
<!-- 设置切入点-->
<aop:pointcut id="study" expression="execution(* JDKProxy.pojo.Student.study(..))"/>
<!-- 切面,把通知设置到切入点去-->
<aop:aspect ref="studentproxy">
<aop:before method="before" pointcut-ref="study"/>
<aop:after method="after" pointcut-ref="study"/>
<aop:after-returning method="afterReturning" pointcut-ref="study"/>
<aop:around method="around" pointcut-ref="study"/>
</aop:aspect>
</aop:config>
<!-- 把通知设置到 play-->
<aop:config>
<aop:pointcut id="play" expression="execution(* JDKProxy.pojo.Student.play())"/>
<!-- 方面,而且还要设置好使用哪里的通知-->
<aop:aspect ref="studentproxy">
<aop:before method="before" pointcut-ref="play"/>
<aop:around method="around" pointcut-ref="play"/>
<aop:after method="after" pointcut-ref="play"/>
<aop:after-returning method="afterReturning" pointcut-ref="play"/>
</aop:aspect>
</aop:config>
</aop:config>
</beans>
通知类示例:
package JDKProxy.pojo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class StudentProxy{
public void before(){
System.out.println("befores.....");
}
public void after(){
System.out.println("after");
}
public void afterReturning(){
System.out.println("afterReturning");
}
public void aferThrowing(){
System.out.println("afterThrowing");
}
public void around(ProceedingJoinPoint point) throws Throwable {
System.out.println("环绕前");
point.proceed();
System.out.println("环绕后");
}
}
通过这种方式,可以在不修改源代码的情况下为目标对象的方法添加增强功能。
2. 用注解的方式实现 AOP
使用 @component、@Reponsitory、@service、@Controller、@aspect 等注解,以及 @AutoWired、@Resource、@Inject 等依赖注入方式实现 AOP。
Spring 框架一般都是基于 AspectJ 实现 AOP 操作。AspectJ 不是 Spring 组成部分,而是独立的 AOP 框架,通常把 AspectJ 和 Spring 框架一起使用进行 AOP 操作。首先需要引入相关依赖,这里不再赘述。
切入点表达式的作用是知道对哪个类里面的哪个方法进行增强。其语法结构为:execution ([权限修饰符] [返回类型] [类全路径] 方法名称)。例如,对com.spring.dao.bookdao类的add方法进行增强,可以使用execution(* com.spring.dao.bookdao.add(…))。其中,第一个*后面有空格,星号表示所有的修饰符(public、private等等),返回类型可以省略不写。如果要对com.spring.dao.bookdao类的所有方法增强,可以使用execution(* com.spring.dao.bookdao.*(…));对com.spring.dao包中的所有类的所有方法增强,可以使用execution(* com.spring.dao.*.*(…))。
用注解实现 AOP 操作的步骤如下:
- 在需要进行 AOP 的类上添加相应的注解:
-
- 在切面类上添加@Aspect注解,表明这是一个切面类。
-
- 在业务逻辑类上根据其作用添加@Component、@Reponsitory、@service、@Controller等注解。
- 使用通知注解和切入点表达式:
-
- 使用@Before注解表示前置通知,在目标方法执行之前执行。
-
- 使用@AfterReturning注解表示后置通知,如果发生异常,此方法不会执行。
-
- 使用@After注解表示最终通知,即不管发生异常与否都会执行。
-
- 使用@AfterThrowing注解表示异常通知,发生异常才会执行。
-
- 使用@Around注解表示环绕通知,执行前执行后都会执行一遍。
-
- 使用@Pointcut注解声明一个公用的切入点表达式,通知行为的注解都可以直接拿来复用。
- 开启 AOP 注解功能:
-
- 如果是注解式开发,需要在配置类上添加@EnableAspectJAutoProxy注解,声明这个配置类使用注解式的 AOP。
例如:
@Component
public class BookDao{
public void add(){
System.out.println("bookdao Add something...");
}
}
@Component
@Aspect
public class BookDaoProxy{
//前置通知
@Before(value = "execution(* com.spring.dao.BookDao.add(..))")
//在BookDao的add方法之前执行
public void before(){
System.out.println("在方法执行之前......");
}
}
测试类:
@Test
public void test1(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
BookDao bookDao = context.getBean("bookDao", BookDao.class);
System.out.println(bookDao);
bookDao.add();
}
AOP 的使用场景包括写日志、事务管理等,就是一些不是业务逻辑代码要做的事就交给 AOP 来完成。
此外,还可以通过设置增强优先级。使用@Order(数字)注解,数字越小优先级越高。例如:
@Component
@Aspect
@Order(1)
public class PersonProxy{}
综上所述,通过注解的方式可以更加简洁地实现 Spring 框架的 AOP 功能。
四、独立开发 Spring 框架步骤
1. 创建 DispatcherServlet
在 web.xml 中注册 springmvc 框架的核心对象 DispatcherServlet,负责接收用户请求并转发给后端控制器。
DispatcherServlet 是前端控制器设计模式的实现,提供 Spring Web MVC 的集中访问点,并且负责职责的分派,与 Spring IOC 容器无缝集成,从而可以获得 Spring 的优势。其主要职责包括文件上传解析、通过 HandlerMapping 将请求映射到处理器、通过 HandlerAdapter 支持多种类型的处理器、通过 ViewReslver 解析逻辑视图名到具体视图实现、本地化解析、渲染具体的视图等,若执行过程中遇到异常将交给 HandlerExecutionResolver 来解析。
其创建过程如下:
- 构造方法先调用父类 FrameworkServlet 的构造方法,再调用自己的构造方法。
- DispatcherServlet 调用基类 HttpServletBean 的 init (),主要获取 servletContext 和 servletConfig 对象。
- HttpServletBean 的 init () 又会调用 FrameworkServlet 的 initServletBean (),主要初始化 Spring 的 webApplicationContext 对象。
- 初始化 WebApplicationContext 后,调用 DispatcherServlet 中的 onRefresh (),onRefresh () 直接调用 initStrategies (),initStrategies () 初始化基本组件,启动整个 Spring MVC 框架。
此外,在 Spring Boot 中,DispatcherServlet 的注册过程如下:DispatcherServletAutoConfiguration$DispatcherServletConfiguration 类中声明了 Bean 方法,会创建 DispatcherServlet 类型的 Bean,然后作为 dispatcherServletRegistration 方法的参数注入到 DispatcherServletRegistrationBean 内部。在创建 web 服务器时,会返回指向 selfInitialize () 方法的引用赋值给函数式接口 ServletContextInitializer,在 TomcatServletWebServerFactory#prepareContext () 中,使用 TomcatStarter 类封装刚才注入的 ServletContextInitializer 接口,添加到 Context 容器的 initializers 中。初始化完成后,进入 tomcat 服务器的启动流程,此时会遍历内部的 initializers,调用每个 ServletContainerInitializer 接口的 onStartup () 方法,而 TomcatStarter 内部的 initializers 会包含 selfInitialize 方法的引用,即会调用 selfInitialize 方法。
2. 创建后端控制器类
使用 @Controller 注解标注,里面的方法使用 @RequestMapping 注解标注。
后端控制器类在 Spring MVC 中起着关键作用。例如在 Spring Boot Web 快速入门中,定义 HelloController 类,使用 @RestController 注解标注,该类中的方法使用 @RequestMapping 注解标注,能够处理特定的请求并返回相应的结果。在 spring-mvc 入门 (二): 后端控制器 (下) 中,后端控制器可以继承 SimpleController 或 MultiActionController,实现不同的功能。如继承 SimpleController 后,可以重写 formBackingObject、initBinder、onBind、onBindAndValidate 等方法来定制控制器的行为。而继承 MultiActionController 可以将多个请求处理方法合并在一个控制器里,通过配置 methodNameResolver 和请求转发的访问路径,可以实现根据不同的请求调用不同的方法。
3. 创建 springmvc 核心配置文件
主要有 Controller 层的注解扫描器和视图解析器,实现 Spring MVC 的核心配置。
Spring 框架的核心配置涉及多个方面,包括依赖注入(DI)、面向切面编程(AOP)等。创建 springmvc 核心配置文件通常包括以下步骤:
- 引入 Spring 依赖:在项目的构建工具(如 Maven、Gradle)配置文件中,添加 Spring 框架的依赖。
- 创建配置文件:创建一个 XML 文件(通常命名为applicationContext.xml),用于定义应用程序中的 bean、依赖关系和其他配置。
- 定义 Bean:在配置文件中使用<bean>元素定义各个组件(Bean),包括类名、属性、构造函数参数等。
- 配置依赖注入:使用<property>元素设置 Bean 之间的依赖关系,实现依赖注入。
- 加载配置文件:在应用程序的启动代码中,加载 Spring 配置文件。
- 获取 Bean:通过应用程序上下文(ApplicationContext)获取需要的 Bean。
- 使用 Bean:使用从容器中获取的 Bean 进行业务操作。
在 Spring MVC 中,核心配置文件主要包含 Controller 层的注解扫描器和视图解析器。注解扫描器主要作用是扫描到被@controller注解标注的类,并创建该类的实例,将该实例放入到 Spring MVC 的容器中。视图解析器负责将控制器所产生的逻辑视图名称转换成实际的视图对象,以便最终在浏览器中呈现给用户。例如,可以使用 InternalResourceViewResolver 作为视图解析器,通过设置 prefix 属性指定视图文件的路径前缀,suffix 属性指定视图文件的后缀名。如果项目既要返回 JSP 页面,又要返回 HTML 页面,可以配置两个解析器,或者重写 InternalResourceView 类的 checkResource 方法来判断资源是否存在,以便在不同的解析器之间进行切换。
五、Spring 框架在独立开发中的难点及解决方案
1. bean 无法注入问题
在独立开发中,bean 无法注入可能会导致程序运行错误。为了解决这个问题,需要确保 bean 已注册、定义正确、依赖已注册、作用域正确。具体可以从以下几个方面进行检查:
- 检查 bean 是否已正确注册到 Spring 容器中。可以查看配置文件或者使用注解的方式确保 bean 被 Spring 容器管理。
- 确认 bean 的定义是否正确。检查类的定义、属性和方法是否符合 Spring 的规范。
- 确保 bean 的依赖关系也在 Spring 容器中注册。如果一个 bean 依赖其他 bean,那么被依赖的 bean 也需要被正确注册。
- 检查 bean 的作用域是否正确。Spring 支持多种作用域,如 singleton(单例)、prototype(原型)等,根据实际需求选择合适的作用域。
2. 循环依赖性问题
循环依赖是 Spring 框架在独立开发中常见的难点之一。以下是几种解决循环依赖问题的方法:
- 使用 @lazy 注解延迟初始化。通过 @lazy 注解,可以推迟 bean 的初始化,直到真正需要使用的时候才进行初始化,从而避免循环依赖问题。
- 使用 factory bean 方法。factory bean 可以在 bean 创建过程中进行一些特殊的处理,通过合理设计 factory bean,可以解决循环依赖问题。
- 考虑使用 aspectj 自动代理。aspectj 自动代理可以在一定程度上解决循环依赖问题,但需要对 aspectj 有一定的了解和配置。
3. 配置错误问题
配置错误可能会导致 Spring 框架在独立开发中出现各种问题。为了解决配置错误问题,可以从以下几个方面进行检查:
- 检查上下文文件。确保上下文文件的拼写和语法正确,配置项的设置符合 Spring 的规范。
- 检查 bean 注册。确认 bean 是否已正确注册到 Spring 容器中,注册的方式是否正确。
- 检查 bean 属性设置。确保 bean 的属性设置正确,依赖关系是否正确配置。
4. 性能问题
在独立开发中,性能问题是需要关注的重点之一。以下是一些解决性能问题的方法:
- 使用性能分析工具识别瓶颈。可以使用性能分析工具,如 JProfiler、VisualVM 等,来识别程序中的性能瓶颈,以便进行针对性的优化。
- 避免创建不必要的 bean。在设计和开发过程中,尽量避免创建不必要的 bean,减少资源的占用。
- 使用缓存。对于频繁访问的数据,可以使用缓存来提高访问速度,减少对数据库等资源的访问。
- 监视内存使用。定期监视程序的内存使用情况,避免出现内存泄漏等问题。
5. 事务管理问题
事务管理是 Spring 框架中的重要功能之一,但在独立开发中也可能会出现一些问题。以下是解决事务管理问题的方法:
- 正确配置事务管理器。根据实际需求选择合适的事务管理器,并进行正确的配置。
- 设置事务传播行为。根据业务逻辑的需要,设置合适的事务传播行为,如 REQUIRED、SUPPORTS、MANDATORY 等。
- 处理事务异常。当事务出现异常时,需要正确处理异常,根据需要进行事务的回滚或提交。
- 提供回滚机制。在事务中,如果出现异常,可以通过设置回滚机制来保证数据的一致性。例如,可以使用 @Transactional 注解的 rollbackFor 属性来指定哪些异常触发事务回滚。
六、独立开发中 Spring 框架的优势
1. 方便解耦,简化开发
将对象的创建和依赖关系的维护交给 Spring 管理,避免了硬编码所造成的过度程序耦合。用户无需再为单例模式类、属性文件解析等底层需求编写代码,可以更专注于上层的应用。Spring 的 IoC(Inverse of Control,控制反转)容器负责管理应用程序中的对象及其依赖关系,通过依赖注入(DI),开发者可以将对象的依赖关系从代码中解耦出来,由 IoC 容器在运行时动态地注入。这降低了代码之间的耦合度,使得代码更加灵活和可测试。
2. AOP 编程的支持
Spring 方便进行面向切面的编程,实现权限拦截和运行监控等功能。在 Spring 框架中,AOP(Aspect Oriented Programming,面向切面编程)通过定义名为 “切面”(aspects)的独立组件来实现这一点,切面中包含了横切逻辑,并且可以在不同的执行点,被动态地 “织入” 到程序中。
Spring AOP 提供了切面(Aspect)、连接点(Join Point)、通知(Advice)、切入点(Pointcut)、引入(Introduction)、目标对象(Target Object)、AOP 代理(AOP Proxy)等功能和优点。切面封装横切逻辑,通知在特定连接点采取动作,切入点匹配连接点的表达式,引入用于给现有的类添加新方法或属性,目标对象被一个或多个切面所通知,AOP 代理实现切面契约。
例如,可以使用 @Aspect 注解标记类为一个切面,通过 @Pointcut 定义切入点表达式,匹配特定的方法,然后使用 @Before、@After、@AfterReturning、@AfterThrowing 和 @Around 等注解表示在匹配的方法执行之前、之后、成功执行之后、抛出异常后以及环绕执行相应的通知方法。
3. 声明事物的支持
Spring 通过配置就可以完成对事务的管理,提高开发效率和质量。Spring 的事务管理分为编程式事务管理和声明式事务管理两种类型。
编程式事务管理是指在代码中显式地管理事务开始、提交或回滚。这种方式提供了对事务的完全控制,但通常会使代码变得复杂并且难以维护。
声明式事务管理是最常用的事务管理方式,它通过配置来管理事务,而不是通过编程的方式。这样可以避免在业务逻辑中混杂事务管理代码,使代码更简洁、更易于维护。可以使用注解配置事务管理,如 @Transactional 注解标记方法或类为事务性,通过设置 propagation(传播行为)、isolation(隔离级别)等属性来控制事务的行为。也可以使用 XML 配置事务管理,通过配置事务管理器和启用事务注解来实现事务管理。
事务管理的核心概念包括事务管理器(Transaction Manager)、事务定义(Transaction Definition)和事务状态(Transaction Status)。事务管理器负责创建和管理事务,事务定义定义了事务的行为特性,如传播行为、隔离级别、只读标志等,事务状态提供有关当前事务的信息,如是否已提交、是否已回滚等。
事务传播行为定义了当一个事务方法被另一个事务方法调用时,如何处理事务边界。Spring 支持多种传播行为,如 REQUIRED(如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务)、REQUIRES_NEW(创建一个新的事务,如果当前存在事务,则挂起当前的事务)等。
事务隔离级别定义了事务之间相互影响的程度,Spring 支持多种隔离级别,如 ISOLATION_DEFAULT(使用底层数据库的默认隔离级别)、ISOLATION_READ_UNCOMMITTED(最低的隔离级别,事务可以看到其他事务未提交的数据)等。
事务回滚是指当发生错误时,撤销事务所做的所有更改。Spring 支持通过异常来控制事务的回滚策略,例如可以使用 @Transactional 注解的 rollbackFor 属性来指定哪些异常触发事务回滚。
4. 方便程序的测试
Spring 支持 JUnit4,可以通过注解方便地测试 Spring 程序。在进行 Spring 开发时,Spring 提供了相关的测试模块,很方便进行配置文件加载,然后进行测试。
可以使用 @RunWith (SpringJUnit4ClassRunner.class) 和 @ContextConfiguration 注解来配置测试类,让测试类在 Spring 容器环境中运行。通过 @Autowired 注解实现自动注入,可以方便地获取需要测试的对象。然后使用 @Test 注解标记测试方法,在测试方法中进行各种测试操作。
例如,在测试类中,可以通过自动注入获取一个服务对象,然后调用服务对象的方法进行测试。如果使用的是 IDE 提供的低版本 JUnit 库可能会出现问题,需要将项目的 JUnit 库移除,下载 JUnit4.9 或以上版本的 jar 包放到项目的 lib 下即可解决。
5. 方便集成各种优秀框架
Spring 降低各种框架的使用难度,提供直接支持。Spring 不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如 Struts2、Hibernate、MyBatis 等)的直接支持。
Spring 可以通过多种方式集成其他框架,例如在 Spring MVC 中,可以通过配置 DispatcherServlet、后端控制器类和 springmvc 核心配置文件来实现与其他框架的集成。在配置文件中,可以使用注解扫描器扫描到被特定注解标注的类,并创建该类的实例,将该实例放入到 Spring MVC 的容器中。同时,可以配置视图解析器,将控制器所产生的逻辑视图名称转换成实际的视图对象,以便最终在浏览器中呈现给用户。
6. 降低 Java EE API 的使用难度
Spring 对难用的 Java EE API 提供封装,降低使用难度。Spring 对 Java EE 开发中非常难用的一些 API(JDBC、JavaMail、远程调用等)都提供了封装,使这些 API 应用的难度大大降低。
例如,在数据库访问方面,Spring 提供了对 JDBC 的抽象层,消除了繁琐的 JDBC 编码和数据库厂商特有的错误代码解析,用于简化 JDBC 操作。在邮件发送方面,Spring 提供了对 JavaMail 的封装,使得发送邮件更加方便。
7. Java 源码是经典学习范例
Spring 的源码设计精妙,是 Java 技术的最佳实践范例。Spring 的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对 Java 设计模式灵活运用以及对 Java 技术的高深造诣。它的源代码无疑是 Java 技术的最佳实践的范例。
Spring 的设计理念和实现方式值得开发者深入学习和研究,通过学习 Spring 的源码,可以更好地理解 Java 设计模式的应用、面向对象编程的思想以及如何构建高质量的软件系统。
七、Spring 框架独立开发案例
1. Spring+Springmvc+Mybatis 框架整合开发入门案例
SSM(Spring+SpringMVC+Mybatis)框架整合开发是一种常见的 Java 企业级应用开发方式,它结合了 Spring 的强大功能、SpringMVC 的优秀表现层处理能力以及 Mybatis 的灵活数据访问能力。以下将介绍 SSM 框架整合开发的业务流程、环境依赖、步骤摘要和具体步骤。
一、业务流程
用户发起请求后,请求首先会被 SpringMVC 的 DispatcherServlet 接收。DispatcherServlet 会根据请求的 URL 查找对应的 Controller 控制器。Controller 根据业务需求调用 Service 层的方法,而 Service 层又可能会调用 Dao 层(Mybatis)的方法来访问数据库。数据库操作完成后,结果会逐层返回,最终由 Controller 将结果以适当的格式返回给用户,可能是 JSON 格式或者视图页面。具体流程如下:
- 前端通过 Ajax 发送请求参数到后端,首先访问 web.xml 文件,也就访问了 spring-mybatis.xml、spring-mvc.xml 文件,这两个 xml 文件正是配置 SSM 框架的控制核心。
- spring-mybatis.xml 配置 MySQL 数据连接参数,配置需要扫描的 Service 层的包、Dao 层的包,在该文件中指向了另一个 mapper-config.xml 文件用于扫描 Dao 层具体的接口。
- spring-mvc.xml 配置了要扫描的 Controller 包,还可用于配置 Controller 层方法返回的视图特性。
- 由配置文件去 Controller 层找对应的处理方法,找到后并将参数注入到相应的方法中。
- 进入 Controller 层的方法内部后,根据需要则去调用 Service 层或直接 Dao 层方法以实现对数据库的访问。
- Service 层或 Dao 层处理完毕将结果返回,返回 JSON 类型数据则需要进行类型转换。
- 前端页面将返回的 JSON 数据进行组织并显示出来。
二、环境依赖
主要依赖以下几个方面的库和组件:
- 数据库相关:mysql-connector-java,用于连接 MySQL 数据库。
- 框架依赖:spring、mybatis、mybatis-spring 等框架的相关 jar 包。
- JSON 处理:gson 等库,用于将数据转换为 JSON 格式返回给前端。
三、步骤摘要
- Dao 层:定义数据库访问接口,并在配置文件中配置扫描路径。
- Service 层:协助 Controller 层处理业务逻辑,可根据需要进行配置和扫描。
- Controller 层:处理前端请求的核心部分,调用 Service 层或直接访问 Dao 层。
- 配置 mapper-config.xml:用于 Mybatis 的具体配置。
- 配置文件:spring-mybatis.xml,配置数据库连接、Service 层和 Dao 层的扫描等。
- 配置文件:spring-mvc.xml,配置 Controller 层的扫描、视图解析器等。
- com.test.QueryTest 类单独测试配置。
- 实现跨域请求的过滤器。
- 配置文件:web.xml,配置监听器、前端控制器等。
- 前端请求页面:index.html。
四、具体步骤
- Dao 层:
-
- Dao 层是数据访问层,负责与数据库进行交互。在 SSM 框架中,Dao 层通常使用 Mybatis 来实现。
-
- 以接口的形式定义数据库操作方法,例如:
package com.dao;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Select;
public interface TestDao {
@Select("select * from tb_test where sex=#{sex} and height>#{height} limit 0,10")
public List<Map<String,Object>> queryInfo(Map<String,Object> mp);
}
- 确保 mybatis-spring 包正确导入到环境依赖中,并且在配置文件中配置 dao 层的扫描路径(spring-mybatis.xml):
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.dao" />
</bean>
- 这里使用 Map 作为参数,则 Map 的 key 必须与注解上的查询语句 “#{}” 中的名字一致,个数一致。
- Service 层:
-
- Service 层用于协助 Controller 层处理业务逻辑,不是必须的,处理较简单时可以直接合并到 Controller 层。
-
- Service 类上必须要注解 @Service,类似的也可用 @Component、@Repository 等。
-
- 必须在配置文件(spring-mybatis.xml)中做如下配置,才能使注解被扫描到:
<context:component-scan base-package="com.service">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service" />
</context:component-scan>
- 例如:
package com.serv;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.dao.TestDao;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@Service
public class TestService {
@Autowired
TestDao testDao;
public String queryService(Map<String,Object> mp) {
List<Map<String,Object>> ob = testDao.queryInfo(mp);
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create();
return gson.toJson(ob);
}
}
- Controller 层:
-
- Controller 层是处理业务的核心,前端请求由此进入处理。
-
- 例如:
package com.controller;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.serv.TestService;
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
TestService testService;
@RequestMapping("/query")
public String query(Map<String,Object> mp) {
return testService.queryService(mp);
}
}
- 配置 mapper-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- Mybatis的具体配置 -->
</configuration>
- 配置文件:spring-mybatis.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">
<context:component-scan base-package="com.service">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service" />
</context:component-scan>
<context:component-scan base-package="com.dao">
<context:include-filter type="annotation" expression="org.apache.ibatis.annotations.Mapper" />
</context:component-scan>
<!-- 配置数据库连接参数 -->
<!-- 具体的数据库连接配置 -->
</beans>
- 配置文件:spring-mvc.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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.controller">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<mvc:resources mapping="/js/" location="/js/**" />
<mvc:resources mapping="/css/" location="/css/**" />
<mvc:resources mapping="/imgs/" location="/imgs/**" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<mvc:annotation-driven />
</beans>
- com.test.QueryTest 类单独测试配置:
-
- 根据具体需求编写测试类,对 SSM 框架的各个部分进行单元测试。
- 实现跨域请求的过滤器:
-
- 在 SSM 框架中,可能需要处理跨域请求。可以通过编写过滤器来实现跨域请求的支持。
-
- 例如:
package com.filter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CORSFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {}
}
- 在 web.xml 中配置过滤器:
<filter>
<filter-name>CORSFilter</filter-name>
<filter-class>com.filter.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CORSFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- 配置文件:web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 配置spring的ContextLoaderListener监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 设置配置文件路径 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 配置前端控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 加载springmvc配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<!-- 启动服务器就创建该servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 解决中文乱码的过滤器 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
- 前端请求页面:index.html:
- 根据业务需求编写前端页面,发送请求并展示返回的数据。
通过以上步骤,可以实现 Spring+SpringMVC+Mybatis 框架的整合开发,构建一个功能强大的企业级应用。
2. springBoot 框架搭建及简单案例
Spring Boot 是一个用于简化 Spring 应用开发的框架,它提供了快速搭建和运行 Spring 应用的方式。以下将介绍 springBoot 的框架搭建步骤,包括导入依赖、创建请求处理类和启动类。
一、导入依赖
在使用 Spring Boot 进行开发时,首先需要在项目的构建工具(如 Maven 或 Gradle)中导入相应的依赖。一般来说,可以通过以下方式导入 Spring Boot 的 Web 依赖:
对于 Maven 项目,可以在 pom.xml 文件中添加以下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
这个依赖包含了 Spring Boot 的核心功能以及与 Web 开发相关的组件,如 Spring MVC、Tomcat 服务器等。此外,根据项目的具体需求,还可以添加其他依赖,如数据库连接驱动、MyBatis 等。
二、创建请求处理类
请求处理类是 Spring Boot 应用中用于处理 HTTP 请求的类。可以使用 @RestController 注解标注该类,表明这是一个 RESTful 风格的控制器。在类中,可以使用 @RequestMapping 注解标注方法,用于映射特定的 URL 路径。例如:
package com.example.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello, Spring Boot!";
}
}
在这个例子中,HelloController 类中的 hello 方法处理对 “/hello” 路径的 GET 请求,并返回 “Hello, Spring Boot!” 字符串。
三、创建启动类
启动类是 Spring Boot 应用的入口点,它负责启动应用程序。可以创建一个带有 @SpringBootApplication 注解的类,并在其中包含一个 main 方法。例如:
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
在 main 方法中,调用 SpringApplication.run 方法来启动应用程序。这个方法会加载应用程序的配置,并启动内置的 Tomcat 服务器(或其他嵌入式服务器)。
通过以上三个步骤,可以快速搭建一个 Spring Boot 应用,并实现简单的 Web 功能。可以根据项目的需求进一步扩展和定制应用程序,如添加数据库访问、业务逻辑处理等。