文前说明
作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。
本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。
1. 基本概念
-
Spring Framework,是一个开源应用框架,旨在降低应用程序开发的复杂度。
- 轻量级、松散耦合的。
- 具有分层体系结构,允许用户选择组件,同时还为 J2EE 应用程序开发提供了一个有凝聚力的框架。
- 可以集成其他框架,如 Spring MVC、Hibernate、MyBatis 等,所以又称为框架的框架(粘合剂、脚手架)。
1.1 模块介绍
- Spring 由 20 多个模块组成,它们可以分为核心容器(Core Container)、数据访问/集成(Data Access/Integration)、Web、面向切面编程(AOP, Aspect Oriented Programming)、设备(Instrumentation)、消息发送(Messaging)和测试(Test)。

1.1.1 核心容器(Core Container)
- 包含以下模块。
- spring-core 提供依赖注入 IoC 与依赖注入的最基本实现。
-
spring-beans 提供 Bean 工厂与 Bean 的装配。
- 提供对 Factory 模式的经典实现来消除对程序性单例模式的需要,并真正地允许从程序逻辑中分离出依赖关系和配置。
-
spring-context 提供 spring 的 context 上下文,即 IoC 容器。
- 提供了用一种框架风格地方式来访问对象,有些像 JNDI 注册表。
- 还增加了国际化(I18N),事件传播,资源装载,以及透明创建上下文,例如通过 servlet 容器,以及对大量 JavaEE 特性的支持,如 EJB、JMX,核心接口是
ApplicationContext
。
-
spring-expression 提供 spring 表达式语言,提供了在运行期间查询和操作对象图的强大能力。
- 支持访问和修改属性值,方法调用。
- 支持访问及修改数组、容器和索引器,命名变量。
- 支持算数和逻辑运算。
- 支持从 spring 容器获取 Bean。
- 支持列表投影、选择和一般的列表聚合等。
- spring-context-support 为集成第三方库(如定时器 Quartz)提供支持。
- 因为 spring-core 依赖 commons-logging,而其他模块都依赖 spring-core,所以整个 spring 框架都依赖 commons-logging,如果有自己的日志实现,如 log4j,可以排除对 commons-logging 的依赖,没有日志实现而排除了 commons-logging 依赖,编译会报错。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.18.RELEASE</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
1.1.2 数据访问/集成(Data Access/Integration)
- 包含以下模块。
-
spring-jdbc 提供 JDBC 的支持。
- 是 Spring 对 JDBC 数据访问的封装,提供了一个 JDBC 抽象层,消除了冗长代码。
-
spring-tx 提供事务控制。
- 支持编程和声明性事务管理。
- spring-orm 对象关系映射,集成 ORM 框架。
-
spring-oxm 对象 XML 映射。
- 目的在于 Java 对象(POJO)和 XML 文档之间来回转换。
-
spring-jdbc 提供 JDBC 的支持。
1.1.3 Web
- 包含以下模块。
- spring-web 提供基础 web 功能,如文件上传,使用 servlet listeners 初始化 IoC 容器等。
- spring-webmvc 提供 MVC 实现(SpringMVC)。
- spring-webmvc-portlet 提供基于 portlet 的 MVC 实现。
- spring-websocket 为 web 应用提供的高效通信工具。
1.1.4 AOP
- 包含以下模块。
- spring-aop 将面向方面的编程功能集成到了 Spring 框架中。
- spring-aspects 该模块为与 AspectJ 的集成提供支持。
- spring-Instrumentation 该层为类检测和类加载器实现提供支持。
1.1.5 其他
- 包含以下模块。
-
spring-jms Java 消息服务。
- 用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
- spring-test 该模块为使用 JUnit 和 TestNG 进行测试提供支持。
- spring-messaging 该模块为 STOMP 提供支持。它还支持注解编程模型,该模型用于从 WebSocket 客户端路由和处理 STOMP 消息。
-
spring-jms Java 消息服务。
1.2 优势
- DI :Dependency Injection(DI) 方法,使得构造器和 JavaBean、properties 文件中的依赖关系一目了然。
- 轻量级:与 EJB 容器相比,IoC 容器更加趋向于 轻量级。IoC 容器在有限的内存和 CPU 资源的情况下,进行应用程序的开发和发布十分有利。
- 面向切面编程(AOP): Spring 支持面向 切面编程,同时把应用的业务逻辑与系统的服务分离开来。
- 集成主流框架:Spring 集成了已有的技术栈,比如 ORM 框架、Logging 日志框架、J2EE、Quartz 和 JDK Timer ,以及其他视图技术。
- 模块化:Spring 框架按照模块的形式组织。由包和类的命名,可以看出其所属的模块,开发者仅仅需要选用需要的模块即可。
- 便捷的测试:要测试一项用 Spring 开发的应用程序十分简单,因为 测试 相关的环境代码已经囊括在框架中,利用 JavaBean 形式的 POJO 类,可以很方便的利用依赖注入写入测试数据。
- Web 框架:Spring 的 Web 框架是一个精心设计的 Web MVC 框架,为开发者在 Web 框架的选择上提供了一个除了主流框架比如 Struts 以外的有力选项。
- 事务管理:Spring 提供一个便捷的事务管理接口,适用于小型的本地事物处理(比如在单 DB 的环境下)和复杂的共同事物处理(比如利用 JTA 的复杂 DB 环境)。
- 异常处理:Spring 提供一个方便的 API ,将特定技术的异常(由 JDBC, Hibernate, 或 JDO 抛出)转化为一致的、Unchecked 异常。
1.3 设计模式
- Spring 框架中使用到了大量的设计模式。
- 代理模式 在 AOP 和 remoting 中被使用的比较多。
- 单例模式 在 Spring 配置文件中定义的 Bean 默认为单例模式。
-
模板方法 用于解决代码重复的问题。比如
RestTemplate
、JmsTemplate
、JdbcTemplate
。 -
前端控制器 Spring 提供了
DispatcherServlet
来对请求进行分发。 - 视图帮助(View Helper)Spring 提供了一系列的 JSP 标签,高效宏来辅助将分散的代码整合在视图里。
-
依赖注入 贯穿于
BeanFactory
和ApplicationContext
接口的核心理念。 -
工厂模式
BeanFactory
用来创建对象的实例。
2. Spring Ioc
- Spring 框架的核心是 Spring IoC 容器。容器创建 Bean 对象,将它们装配在一起,配置并管理它们的完整生命周期。
- Spring 容器使用依赖注入管理组成应用程序的 Bean 对象。
- 容器通过读取提供的配置元数据 Bean Definition 来接收对象进行实例化,配置和组装的指令。
- 该配置元数据 Bean Definition 可以通过 XML,Java 注解或 Java Config 代码提供。
- Spring 中的 IoC 的实现原理,是 工厂模式 加 反射机制。
2.1 依赖注入
- DI(Dependency Injection)即 依赖注入,组件之间依赖关系由容器在运行期决定。由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。
- IoC 和 DI 是 同一个概念的不同角度描述。
- 依赖注入 明确描述了 被注入对象依赖 IoC 容器配置依赖对象。
2.2 依赖注入方式
- IoC Service Provider 为被注入对象提供被依赖对象有几种方式:构造方法注入、stter 方法注入 和 接口注入。
构造器注入(Constructor Injection)
- 被注入的对象通过在其构造方法中声明依赖对象的参数列表,让外部知道它需要哪些依赖对象。
- 构造器注入方式比较直观,对象构造完毕后就可以直接使用。
public class UserRegister {
private UserDao userDao = null;//由容器通过构造函数注入的实例对象
public UserRegister(UserDao userDao){
this.userDao = userDao;
}
}
setter 方法注入(Setter Injection)
- 对于 JavaBean 对象而言,一般都是通过 getter 和 setter 方法来访问和设置对象的属性。所以,当前对象只需要为其所依赖的对象提供相对应的 setter 方法,就可以通过该方法将相应的依赖对象设置到被注入对象中。
- 相比于构造器注入,setter 方式注入会显得比较宽松灵活,它可以在任何时候进行注入(在使用依赖对象之前)
public class UserRegister {
private UserDao userDao = null;//该对象实例由容器注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
接口方式注入(Interface Injection)
- 需要被依赖的对象实现不必要的接口,带有侵入性。
public interface InjectUserDao {
public void setUserDao(UserDao userDao);
}
public class UserRegister implements InjectUserDao{
private UserDao userDao = null;//该对象实例由容器注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
2.4 Spring Ioc 容器类型
- Spring 提供了两种 IoC 容器,分别是
BeanFactory
、ApplicationContext
。
BeanFactory
- 像一个包含 Bean 集合的工厂类,会在客户端要求时实例化 Bean 对象。
-
BeanFactory
最常用的是XmlBeanFactory
。可以根据 XML 文件中定义的内容,创建相应的 Bean。
ApplicationContext
-
ApplicationContext
接口扩展了BeanFactory
接口,它在BeanFactory
基础上提供了一些额外的功能。
扩展 | 说明 |
---|---|
MessageSource | 管理 message ,实现国际化等功能。 |
ApplicationEventPublisher | 事件发布。 |
ResourcePatternResolver | 多资源加载。 |
EnvironmentCapable | 系统 Environment (profile + Properties)相关。 |
Lifecycle | 管理生命周期。 |
Closable | 关闭,释放资源 |
InitializingBean | 自定义初始化。 |
BeanNameAware | 设置 beanName 的 Aware 接口。 |
-
ApplicationContext
会自动初始化非懒加载的 Bean 对象。更详细介绍查看 【Spring 笔记】ApplicationContext 相关整理
2.4.1 Spring 事件
- Spring 的
ApplicationContext
提供了支持事件和代码中监听器的功能。- 可以创建 Bean 用于监听在
ApplicationContext
中发布的事件。如果一个 Bean 实现了ApplicationListener
接口,当一个ApplicationEvent
被发布以后,Bean 会自动被通知。
- 可以创建 Bean 用于监听在
public class AllApplicationEventListener implements ApplicationListener<ApplicationEvent> {
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
// process event
}
}
- Spring 提供了以下五种标准的事件。
-
上下文更新事件(ContextRefreshedEvent):该事件会在
ApplicationContext
被初始化或者更新时发布。也可以在调用ConfigurableApplicationContext
接口中的refresh()
方法时被触发。 -
上下文开始事件(ContextStartedEvent):当容器调用
ConfigurableApplicationContext
的start()
方法开始/重新开始容器时触发该事件。 -
上下文停止事件(ContextStoppedEvent):当容器调用
ConfigurableApplicationContext
的stop()
方法停止容器时触发该事件。 -
上下文关闭事件(ContextClosedEvent):当
ApplicationContext
被关闭时触发该事件。容器被关闭时,其管理的所有单例 Bean 都被销毁。 - 请求处理事件(RequestHandledEvent):在 Web 应用中,当一个 HTTP 请求(request)结束触发该事件。
-
上下文更新事件(ContextRefreshedEvent):该事件会在
- 还可以通过扩展
ApplicationEvent
类开发 自定义 的事件。 - 自定义的事件类。
public class CustomApplicationEvent extends ApplicationEvent{
public CustomApplicationEvent(Object source, final String msg) {
super(source);
}
}
- 监听该事件需要创建监听器。
public class CustomEventListener implements ApplicationListener<CustomApplicationEvent> {
@Override
public void onApplicationEvent(CustomApplicationEvent applicationEvent) {
// handle event
}
}
- 通过
ApplicationContext
接口publishEvent()
方法发布自定义事件。
// 创建 CustomApplicationEvent 事件
CustomApplicationEvent customEvent = new CustomApplicationEvent(applicationContext, "Test message");
// 发布事件
applicationContext.publishEvent(customEvent);
3. Spring Bean
- Bean 由 Spring IoC 容器实例化,配置,装配和管理。
- Bean 是基于用户提供给 IoC 容器的配置元数据 Bean Definition 创建。
3.1 Bean 的配置方式
- Spring Framework 提供了三种方式。
XML 配置文件
- Bean 所需的依赖项和服务在 XML 格式的配置文件中指定。
- 这些配置文件通常包含许多 bean 定义和特定于应用程序的配置选项。
- 它们通常以 bean 标签开头。
<bean id="studentBean" class="org.edureka.firstSpring.StudentBean">
<property name="name" value="Edureka"></property>
</bean>
注解配置
- 可以通过在相关的类,方法或字段声明上使用注解,将 Bean 配置为组件类本身,而不是使用 XML 来描述 Bean 装配。
- 默认情况下,Spring 容器中未打开注解装配,需要在使用它之前在 Spring 配置文件中启用。
<beans>
<context:annotation-config/>
<!-- bean definitions go here -->
</beans>
- 自动扫描使注解生效。
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--自动扫描包和子包下的所有类注解-->
<context:component-scan base-package="com.test.spring" />
</beans>
Java Config 配置
- Spring 的 Java 配置通过使用 @Bean 和 @Configuration 实现。
- @Bean 注解扮演与 <bean /> 元素相同的角色。
- @Configuration 类允许通过简单地调用同一个类中的其他 @Bean 方法来定义 Bean 间依赖关系。
@Configuration
public class StudentConfig {
@Bean
public StudentBean myStudent() {
return new StudentBean();
}
}
3.2 Bean Scope 类型
- Spring Bean 支持 5 种 Scope。
scope | 说明 |
---|---|
Singleton | 每个 Spring IoC 容器仅有一个单 Bean 实例。默认 |
Prototype | 每次请求都会产生一个新的实例。 |
Request | 每一次 HTTP 请求都会产生一个新的 Bean 实例,并且该 Bean 仅在当前 HTTP 请求内有效。 |
Session | 每一个的 Session 都会产生一个新的 Bean 实例,同时该 Bean 仅在当前 HTTP Session 内有效。 |
Application | 每一个 Web Application 都会产生一个新的 Bean ,同时该 Bean 仅在当前 Web Application 内有效。 |
- 仅当用户使用支持 Web 的
ApplicationContext
时,最后三个才可用。 - 可以使用
@Scope("prototype")
注解配置。
3.3 Bean 的生命周期
- Spring Bean 的 初始化 流程。
- 实例化 Bean 对象(详细可查看 【Spring 笔记】BeanDefinition 装载与注册相关整理)。
- Spring 容器根据配置中的 Bean Definition(定义)中实例化 Bean 对象。
- Spring 使用依赖注入填充所有属性,如 Bean 中所定义的配置。
-
Aware
相关的属性,注入到 Bean 对象(详细可查看 【Spring 笔记】Aware 接口相关整理)。- 如果 Bean 实现
BeanNameAware
接口,则工厂通过传递 Bean 的 beanName 来调用setBeanName()
方法。 - 如果 Bean 实现
BeanFactoryAware
接口,工厂通过传递自身的实例来调用setBeanFactory()
方法。
- 如果 Bean 实现
- 调用相应的方法,进一步初始化 Bean 对象。
- 如果存在与 Bean 关联的任何
BeanPostProcessor
,则调用preProcessBeforeInitialization()
方法(详细可查看 【Spring 笔记】BeanPostProcessor 相关整理)。 - 如果 Bean 实现
InitializingBean
接口,则会调用afterPropertiesSet()
方法(详细可查看 【Spring 笔记】InitializingBean 和 init-method 相关整理)。 - 如果为 Bean 指定了 init 方法(例如 <bean /> 的 init-method 属性),调用该方法。
- 如果存在与 Bean 关联的任何
BeanPostProcessor
,则调用postProcessAfterInitialization()
方法。
- 如果存在与 Bean 关联的任何
- 实例化 Bean 对象(详细可查看 【Spring 笔记】BeanDefinition 装载与注册相关整理)。
- Spring Bean 的 销毁 流程。
- 如果 Bean 实现
DisposableBean
接口,当 Spring 容器关闭时,会调用destroy()
方法。 - 如果为 bean 指定了 destroy 方法(例如 <bean /> 的 destroy-method 属性),那么调用该方法。
- 如果 Bean 实现
- 初始化使用
@PostConstruct
注解。 - 销毁 使用
@PreDestroy
注解。
3.4 内部 Bean
- 只有将 Bean 仅用作另一个 Bean 的属性时,才能将 Bean 声明为内部 Bean。
- 为了定义 Bean,Spring 提供基于 XML 的配置元数据在 <property>或 <constructor-arg> 中提供了 <bean>元素的使用。
- 内部 Bean 总是 匿名 的,并且它们总是作为 原型 Prototype。
<!-- bean.xml -->
<bean id="StudentBean" class="com.test.Student">
<property name="person">
<!-- inner bean -->
<bean class="com.test.Person">
<property name="name" value=“test"></property>
<property name="address" value="sichuan"></property>
</bean>
</property>
</bean>
3.5 Spring 装配
- 当 Bean 在 Spring 容器中组合在一起时,它被称为装配或 Bean 装配。
- Spring 容器需要知道 Bean 以及容器应该如何使用依赖注入来将 Bean 绑定在一起,同时装配 Bean 。
- 装配和 DI 依赖注入实际是一个东西。
3.5.1 自动装配方式
- Spring 容器能够自动装配 Bean,可以通过检查
BeanFactory
的内容让 Spring 自动解析 Bean 的协作者。 - 自动装配的不同模式。
- no(默认设置)表示没有自动装配,应使用显式 Bean 引用进行装配。
- byName 根据 Bean 的名称注入对象依赖项。它匹配并装配其属性与 XML 文件中由相同名称定义的 Bean 。
- byType 根据类型注入对象依赖项。如果属性的类型与 XML 文件中的一个 Bean 类型匹配,则匹配并装配属性。
- 构造函数 通过调用类的构造函数来注入依赖项。它有大量的参数。
- autodetect 首先容器尝试通过构造函数使用 autowire 装配,如果不能,则尝试通过 byType 自动装配。
- 自动装配的局限性。
- 可以使用 <constructor-arg> 和 <property> 设置指定依赖项,这将覆盖自动装配。
- 简单属性(如原数据类型,字符串和类)无法自动装配。
3.6. 延迟加载
- 默认情况下,容器启动之后会将所有作用域为单例的 Bean 都创建好,但是有的业务场景并不需要提前都创建好。此时,可以在 Bean 中设置
lzay-init = "true"
。- 当容器启动之后,作用域为单例的 Bean ,就不在创建。
- 在获得该 Bean 时,才真正创建加载。
3.7 Spring Bean 的循环依赖
4. Spring 注解
4.1 基于注解的容器配置
- 不使用 XML 来描述 Bean 装配,开发人员通过在相关的类,方法或字段声明上使用注解将配置移动到组件类本身。可以作为 XML 设置的替代方案。
- Spring 的 Java 配置是通过使用 @Bean 和 @Configuration 来实现。
- @Bean 注解,扮演与 <bean /> 元素相同的角色。
- @Configuration 注解的类,允许通过简单地调用同一个类中的其他 @Bean 方法来定义 Bean 间依赖关系。
@Configuration
public class StudentConfig {
@Bean
public StudentBean myStudent() {
return new StudentBean();
}
}
4.2 Spring 中启动注解装配
- 默认情况下,Spring 容器中未打开注解装配。要使用基于注解装配,必须通过配置
<context:annotation-config />
元素在 Spring 配置文件中启用。 - Spring Boot 在默认情况下已经开启。
@Component, @Controller, @Repository, @Service 区别
注解 | 说明 |
---|---|
@Component | 将 Java 类标记为 Bean。是任何 Spring 管理组件的通用构造型。 |
@Controller | 它将一个类标记为 Spring Web MVC 控制器。 |
@Service | 是组件注解的特化。不会对 @Component 注解提供任何其他行为。在服务层类中使用 @Service 而不是 @Component ,可以更好的方式指定了意图。 |
@Repository | 具有类似用途和功能的 @Component 注解的特化。它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException。 |
@Required 注解
- 应用于 Bean 属性 setter 方法。
- 仅指示必须在配置时使用 Bean 定义中的显式属性值或使用自动装配填充受影响的 Bean 属性。
- 如果尚未填充受影响的 Bean 属性,则容器将抛出
BeanInitializationException
异常。
@Autowired 注解
- 可以更准确地控制应该在何处以及如何进行自动装配。
- 此注解用于在 setter 方法,构造函数,具有任意名称或多个参数的属性或方法上自动装配 Bean。
- 默认情况下,它是类型驱动的注入。
@Qualifier 注解
- 当创建多个相同类型的 Bean ,并希望仅使用属性装配其中一个 Bean 时,可以使用 @Qualifier 注解和 @Autowired 通过指定 ID 应该装配哪个确切的 Bean 来消除歧义。
5. Spring AOP
- AOP(Aspect-Oriented Programming),即 面向切面编程,与
OOP(Object-Oriented Programming,面向对象编程)相辅相成, 提供了与 OOP 不同的抽象软件结构的视角。- 在 OOP 中,以类(Class)作为基本单元。
- 在 AOP 中,以切面(Aspect)作为基本单元。
5.1 AOP 的相关概念
- JoinPoint 连接点,程序运行中的一些时间点,一个方法的执行,或者一个异常的处理。在 Spring AOP 中,JoinPoint 总是方法的执行点。
- PointCut 切点,是匹配 JoinPoint 的条件。
- Advice 通知,特定 JoinPoint 处的 Aspect 所采取的动作。Spring AOP 使用一个 Advice 作为拦截器,在 JoinPoint 周围维护一系列的拦截器。
- Aspect 由 PointCut 和 Advice 组成。既包含了横切逻辑的定义,也包括了连接点的定义。Spring AOP 是负责实施切面的框架,将切面所定义的横切逻辑编织到切面所指定的连接点中。
- Target 织入 Advice 的目标对象。目标对象也被称为 Advised Object 。因为 Spring AOP 使用运行时代理的方式来实现 Aspect ,因此 Advised Object 总是一个代理对象(Proxied Object)。Advised Object 指的不是原来的对象,而是织入 Advice 后所产生的代理对象。
- Weaving 编织,为了创建一个 Advice 对象而链接一个 Aspect 和其它应用类型或对象,称为编织(Weaving)。在 Spring AOP 中,编织在运行时执行,即动态代理。
- 在 Spring AOP 中,有两种方式配置 AOP 切面。
- 基于 XML 方式的切面实现。
- 基于 注解 方式的切面实现。
- 详细说明可以查看 【Spring 笔记】AOP 基础相关整理
5.2 AOP 的实现方式
静态代理
- 指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强。
- 编译时编织(特殊编译器实现)。
- 类加载时编织(特殊的类加载器实现)。
动态代理
- 运行时在内存中临时生成 AOP 动态代理类,因此也被称为运行时增强。目前 Spring 中使用了两种动态代理库。
- JDK 动态代理,JDK 动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK 动态代理的核心是
InvocationHandler
接口和Proxy
类。 - CGLIB 动态代理,如果目标类没有实现接口,那么 Spring AOP 会选择使用 CGLIB 来动态代理目标类。Spring 也支持配置,强制使用 CGLIB 动态代理。
- JDK 动态代理,JDK 动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK 动态代理的核心是
5.3 Spring AOP 和 AspectJ AOP 区别
- 代理方式不同。
- Spring AOP 基于动态代理方式实现。
- AspectJ AOP 基于静态代理方式实现。
- PointCut 支持力度不同。
- Spring AOP 仅支持方法级别的 PointCut 。
- AspectJ AOP 提供了完全的 AOP 支持,还支持属性级别的 PointCut。
5.4 切入点表达式
5.4.1 execution
- 语法:execution(修饰符 返回值 包.类.方法名(参数) throws异常)
修饰符(一般省略)
修饰符 | 说明 |
---|---|
public | 公共方法 |
* | 任意 |
返回值(不能省略)
返回值 | 说明 |
---|---|
void | 返回没有值 |
String | 返回值字符串 |
* | 任意 |
包
表达式 | 说明 |
---|---|
com.spring.test | 固定包。 |
com.spring.test..service | test 包下面任意子包。例如:com.spring.test.staff.service |
com.spring.test.. | test 包下面的所有子包(含自己)。 |
com.spring.test..service.. | test 包下面任意子包,固定目录 service,service 目录任意包。 |
类
表达式 | 说明 |
---|---|
UserServiceImpl | 指定类。 |
Impl | 以 Impl 结尾。 |
User | 以 User 开头。 |
* | 任意 |
方法名(不能省略)
表达式 | 说明 |
---|---|
addUser | 固定方法。 |
add* | 以 add 开头。 |
*Do | 以 Do 结尾。 |
* | 任意 |
参数
表达式 | 说明 |
---|---|
() | 无参 |
(int) | 一个整型 |
(int ,int) | 两个 |
(..) | 参数任意 |
throws(可省略,一般不写)
5.5 通知类型
通知类型 | 说明 |
---|---|
before | 前置通知(应用:各种校验)在方法执行前执行,如果通知抛出异常,阻止方法运行。 |
afterReturning | 后置通知(应用:常规数据处理)方法正常返回后执行,如果方法中抛出异常,通知无法执行。必须在方法执行后才执行,所以可以获得方法的返回值。 |
around | 环绕通知(应用:可以做任何事情)方法执行前后分别执行,可以阻止方法的执行,必须手动执行目标方法。 |
afterThrowing | 抛出异常通知(应用:包装异常信息)方法抛出异常后执行,如果方法没有抛出异常,无法执行。 |
after | 最终通知(应用:清理现场)方法执行完毕后执行,无论方法中是否出现异常。 |
6. Spring Transaction
- 事务是对一系列的数据库操作(比如插入多条数据)进行统一的提交或回滚操作,如果插入成功,那么一起成功,如果中间有一条出现异常,那么回滚之前的所有操作。
- 这样可以防止出现脏数据,防止数据库数据出现问题。
6.1 事务特性
- 原子性(Atomicity):一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。
- 一致性(Consistency):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设 约束、触发器、级联回滚 等。
- 隔离性(Isolation):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
- 持久性(Durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
6.2 Spring 事务类型
- 目前 Spring 提供两种类型的事务管理。
- 声明式事务:通过使用注解或基于 XML 的配置事务,从而事务管理与业务代码分离。
- 编程式事务:通过编码的方式实现事务管理,需要在代码中显式的调用事务的获得、提交、回滚。它提供极大的灵活性,但维护起来非常困难。
XML 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
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.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--配置数据源-->
<bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///db_transaction"/>
<property name="user" value="root"/>
<property name="password" value="123456"/>
</bean>
<!--配置 dao
继承了 JdbcDaoSupport,直接注入数据源
-->
<bean id="AccountDao" class="com.test.spring.d_tx.c_auto.dao.AccountDaoImpl">
<property name="dataSource" ref="DataSource"/>
</bean>
<!--service -->
<bean id="AccountService" class="com.test.spring.d_tx.c_auto.service.AccountServiceImpl">
<property name="accountDao" ref="AccountDao"/>
</bean>
<!--tx manager-->
<bean id="TransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="DataSource"/>
</bean>
<!--配置通知-->
<tx:advice id="Advice" transaction-manager="TransactionManager">
<tx:attributes>
<!--配置 要使用事务的 方法名,传播途径,隔离级别 -->
<tx:method name="transfer" isolation="DEFAULT" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!--应用通知-->
<aop:advisor advice-ref="Advice" pointcut="execution(* com.test.spring.d_tx.c_auto.service..*.*(..))" />
</aop:config>
<!--
自动扫描事务注解
-->
<tx:annotation-driven transaction-manager="TransactionManager" />
</beans>
注解配置
@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(String outer, String inner, Integer money) {
accountDao.out(outer, money);
// int i = 1 / 0;
accountDao.in(inner, money);
}
}
6.3 Spring 事务集成
- Spring 事务的管理是通过
PlatformTransactionManager
进行管理。
// PlatformTransactionManager.java
public interface PlatformTransactionManager {
// 根据事务定义 TransactionDefinition ,获得 TransactionStatus 。
TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
// 根据情况,提交事务
void commit(TransactionStatus status) throws TransactionException;
// 根据情况,回滚事务
void rollback(TransactionStatus status) throws TransactionException;
}
-
PlatformTransactionManager
是负责事务管理的接口,分别负责事务的获得、提交、回滚。-
getTransaction()
方法,根据事务定义TransactionDefinition
,获得TransactionStatus
,TransactionStatus
中不仅包含事务属性,还包含事务的其它信息,例如是否只读、是否为新创建的事务等。 -
commit()
方法,根据TransactionStatus
情况提交事务。 -
rollback()
方法,根据TransactionStatus
情况回滚事务。
-
-
AbstractPlatformTransactionManager
,基于模板方法模式,实现事务整体逻辑的骨架,抽象doCommit()
、doRollback()
等方法交由子类实现。

实现类 | 说明 |
---|---|
HibernateTransactionManager | 和 Hibernate5 的事务管理做集成。 |
DataSourceTransactionManager | 和 JDBC 的事务管理做集成。所以,它也适用于 MyBatis、Spring JDBC 等等。 |
JpaTransactionManager | 和 JPA 的事务管理做集成。 |
JtaTransactionManager | 和 JTA 的事务管理做集成。 |
- 比较常见的 XML 方式来配置的事务管理器,使用的是
DataSourceTransactionManager
。
<!-- 事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
@Transactional 注解
属性 | 类型 | 描述 |
---|---|---|
value | String | 可选的限定描述符,指定使用的事务管理器。 |
propagation | enum: Propagation | 可选的事务传播行为设置。 |
isolation | enum: Isolation | 可选的事务隔离级别设置。 |
readOnly | boolean | 读写或只读事务,默认读写。 |
timeout | int (in seconds granularity) | 事务超时时间设置。 |
rollbackFor | Class 对象数组,必须继承自 Throwable | 导致事务回滚的异常类数组。 |
rollbackForClassName | 类名数组,必须继承自 Throwable | 导致事务回滚的异常类名字数组。 |
noRollbackFor | Class对象数组,必须继承自 Throwable | 不会导致事务回滚的异常类数组。 |
noRollbackForClassName | 类名数组,必须继承自 Throwable | 不会导致事务回滚的异常类名字数组。 |
- 一般情况下直接使用 @Transactional 的所有属性默认值即可。
- @Transactional 可以作用于接口、接口方法、类以及类方法上。该类的所有 public 方法将都具有该类型的事务属性,同时也可以在方法级别使用该标注来覆盖类级别的定义。
- 可以作用于接口、接口方法、类以及类方法上,只有在使用基于接口的代理时它才会生效。
- 应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,将被忽略,也不会抛出任何异常。
- @Transactional 注解的属性,会解析成
TransactionDefinition
对象,即事务定义。
public interface TransactionDefinition {
int getPropagationBehavior(); // 事务的传播行为
int getIsolationLevel(); // 事务的隔离级别
int getTimeout(); // 事务的超时时间
boolean isReadOnly(); // 事务是否只读
@Nullable
String getName(); // 事务的名字
}
6.4 事务隔离级别
-
TransactionDefinition
接口中,定义了四种隔离级别。
// TransactionDefinition.java
/**
* 【Spring 独有】使用后端数据库默认的隔离级别
*
* MySQL 默认采用的 REPEATABLE_READ隔离级别
* Oracle 默认采用的 READ_COMMITTED隔离级别
*/
int ISOLATION_DEFAULT = -1;
/**
* 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
*/
int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
/**
* 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
*/
int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
/**
* 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
*/
int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
/**
* 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
*
* 但是这将严重影响程序的性能。通常情况下也不会用到该级别。
*/
int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
6.5 事务传播级别
- 事务的传播行为,指的是当前带有事务配置的方法,需要怎么处理事务。
-
TransactionDefinition
接口中,定义了三类七种传播级别。
// TransactionDefinition.java
// ========== 支持当前事务的情况 ==========
/**
* 如果当前存在事务,则使用该事务。
* 如果当前没有事务,则创建一个新的事务。
*/
int PROPAGATION_REQUIRED = 0;
/**
* 如果当前存在事务,则使用该事务。
* 如果当前没有事务,则以非事务的方式继续运行。
*/
int PROPAGATION_SUPPORTS = 1;
/**
* 如果当前存在事务,则使用该事务。
* 如果当前没有事务,则抛出异常。
*/
int PROPAGATION_MANDATORY = 2;
// ========== 不支持当前事务的情况 ==========
/**
* 创建一个新的事务。
* 如果当前存在事务,则把当前事务挂起。
*/
int PROPAGATION_REQUIRES_NEW = 3;
/**
* 以非事务方式运行。
* 如果当前存在事务,则把当前事务挂起。
*/
int PROPAGATION_NOT_SUPPORTED = 4;
/**
* 以非事务方式运行。
* 如果当前存在事务,则抛出异常。
*/
int PROPAGATION_NEVER = 5;
// ========== 其他情况 ==========
/**
* 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行。
* 如果当前没有事务,则等价于 {@link TransactionDefinition#PROPAGATION_REQUIRED}
*/
int PROPAGATION_NESTED = 6;
- 绝大数场景只用 PROPAGATION_REQUIRED 传播级别。
- 前面的六种事务传播行为是 Spring 从 EJB 中引入的,他们共享相同的概念。而 PROPAGATION_NESTED 是 Spring 所特有的。
- 以 PROPAGATION_NESTED 启动的事务内嵌于外部事务中(如果存在外部事务的话),此时,内嵌事务并不是一个独立的事务,它依赖于外部事务的存在,只有通过外部的事务提交,才能引起内部事务的提交,嵌套的子事务不能单独提交。
6.6 事务超时属性
- 指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。
- 在
TransactionDefinition
中以 int 的值来表示超时时间,其单位是秒。
6.7 事务只读属性
- 对事务性资源进行只读操作或者是读写操作。
- 所谓事务性资源就是指那些被事务管理的资源,比如数据源、JMS 资源,以及自定义的事务性资源等。
- 如果确定只对事务性资源进行只读操作,那么可以将事务标志为只读的,以提高事务处理的性能。
6.8 事务回滚规则
- 回滚规则,定义了哪些异常会导致事务回滚。
- 默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚(这一行为与 EJB 的回滚行为是一致的)。
- 可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。
- 事务的回滚规则,并不是数据库事务规范中的名词,而是 Spring 自身所定义的。
6.9 TransactionStatus
- 记录事务的状态,不仅仅包含事务本身,还包含事务的其它信息。
// TransactionStatus.java
public interface TransactionStatus extends SavepointManager, Flushable {
/**
* 是否是新创建的事务
*/
boolean isNewTransaction();
/**
* 是否有 Savepoint
*
* 在 {@link TransactionDefinition#PROPAGATION_NESTED} 传播级别使用。
*/
boolean hasSavepoint();
/**
* 设置为只回滚
*/
void setRollbackOnly();
/**
* 是否为只回滚
*/
boolean isRollbackOnly();
/**
* 执行 flush 操作
*/
@Override
void flush();
/**
* 是否事务已经完成
*/
boolean isCompleted();
}
- 在
TransactionStatus
的实现类DefaultTransactionStatus
中,有个 Object transaction 属性,表示事务对象。 -
isNewTransaction()
方法表示是否是新创建的事务。
7. Spring Data Access
7.1 JDBCTemplate
- Spring 提供用于操作 JDBC 工具类。
代码设置数据源
//1 创建数据源(连接池) dbcp
BasicDataSource dataSource = new BasicDataSource();
// 基本属性项
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/spring_day02");
dataSource.setUsername("root");
dataSource.setPassword("1234");
//2 创建模板
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
//3 通过 API 操作
jdbcTemplate.update("insert into t_user(username,password) values(?,?);", "test","123456");
DBCP 配置设置数据源
<!--配置数据源-->
<bean id="DataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///myusers"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!--配置模版-->
<bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="DataSource" />
</bean>
<!--配置 dao-->
<bean id="UserDao" class="com.ittianyu.spring.c_jdbc_template.dao.UserDao">
<property name="jdbcTemplate" ref="JdbcTemplate"/>
</bean>
C3P0 配置设置数据源
<!--配置数据源-->
<bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///myusers"/>
<property name="user" value="root"/>
<property name="password" value="123456"/>
</bean>
<!--配置模版-->
<bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="DataSource" />
</bean>
<!--配置 dao-->
<bean id="UserDao" class="com.ittianyu.spring.c_jdbc_template.dao.UserDao">
<property name="jdbcTemplate" ref="JdbcTemplate"/>
</bean>
配置 properties
- properties 配置文件。
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///myusers
jdbc.user=root
jdbc.password=123456
- Spring 配置文件。
<!--导入 properties-->
<context:property-placeholder location="classpath:com/test/spring/c_jdbc_template/d_properties_config/c3p0.properties" />
<!--配置数据源-->
<bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
7.2 JdbcDaoSupport
-
Dao
继承JdbcDaoSupport
后,继承了设置数据源的方法。
public final void setDataSource(DataSource dataSource)
- 会自动创建
JdbcTemplate
。
public class UserDao extends JdbcDaoSupport{
public void add(User user) {
String sql = "insert into user (username, password, nick) VALUES (?, ?, ?);";
Object[] args = new Object[]{user.getUsername(), user.getPassword(), user.getNick()};
getJdbcTemplate().update(sql, args);
}
}
- Spring 配置只需要给 dao 注入数据源即可。
<!--导入 properties-->
<context:property-placeholder location="classpath:com/test/spring/c_jdbc_template/d_properties_config/c3p0.properties" />
<!--配置数据源-->
<bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--配置 dao
继承了 JdbcDaoSupport,直接注入数据源
-->
<bean id="UserDao" class="com.ittianyu.spring.c_jdbc_template.c_jdbc_dao_support.UserDao">
<property name="dataSource" ref="DataSource"/>
</bean>
8. 整合
8.1 Junit
- 需要导入 spring-test 包。
- 让 Junit 通知 Spring 加载配置文件。
- 让 Spring 容器自动进行注入。
配置方式
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:com/test/spring/junit/applicationContext.xml")
public class TestClass {
@Autowired
private AccountService accountService;
@Test
public void test() {
accountService.transfer("zs", "ls", 100);
}
}
- @ContextConfiguration 用于指定配置的位置。
- @Autowired 指定需要注入的对象。
8.2 Web
- 需要导入 spring-web 包。
配置方式
- 在 web.xml 中配置 spring listener。
<?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_3_1.xsd"
version="3.1">
<!-- 修改默认的配置文件位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:com/test/spring/web/applicationContext.xml</param-value>
</context-param>
<!--配置 spring -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
手动获取 Spring 容器
// 方式一,直接 map 中获取
ApplicationContext applicationContext1 = (ApplicationContext) getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
// 方式二,通过工具类获取
ApplicationContext applicationContext2 = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
AccountService accountService = applicationContext2.getBean("AccountService", AccountService.class);
accountService.transfer("zs", "ls", 100);
8.3 Hibernate
- 不再使用 hibernate.cfg.xml,使用 Spring datasource 取代。
jdbc.properties
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/ee19_crm
jdbc.user=root
jdbc.password=123456
applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<import resource="classpath:spring/applicationContext-post.xml"/>
<!--import jdbc info-->
<context:property-placeholder location="classpath:jdbc.properties" />
<!--data source-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--session factory-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL57Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.connection.url">jdbc:mysql://localhost:3306/ee19_crm</prop>
<prop key="hibernate.connection.driver_class">com.mysql.jdbc.Driver</prop>
</props>
</property>
<property name="mappingLocations">
<list>
<value>classpath:com/spring/test/classes/bean/TestClass.hbm.xml</value>
</list>
</property>
</bean>
<!--tx-->
<bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="add*"/>
<tx:method name="update*"/>
<tx:method name="delete*"/>
<tx:method name="login"/>
<tx:method name="query*" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.spring.test..service..*(..))"/>
</aop:config>
</beans>
Dao
-
Dao
继承HibernateDaoSupport
。
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
@Override
public void save(User user) {
this.getHibernateTemplate().save(user);
}
}
8.4 Struts2
- Spring 中配置
Service
时,bean 的 id 必须和Action
类中 service 的 set 名字一致。
配置
<bean id="testService" class="com.spring.test.service.impl.TestServiceImpl">
<property name="testDao" ref="testDao"/>
</bean>
TestAction
public void setTestService(TestService testService) {
this.testService = testService;
}
网友评论