spring 复习笔记

Spring 框架提供约 20 个模块,可以根据应用程序的要求来使用

spring

1. 核心容器:
核心容器由核心,Bean,上下文和表达式语言模块组成,它们的细节如下:

核心模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。

Bean 模块提供 BeanFactory,它是一个工厂模式的复杂实现。

上下文模块建立在由核心和 Bean 模块提供的坚实基础上,它是访问定义和配置的任何对象的媒介。ApplicationContext 接口是上下文模块的重点。

表达式语言模块在运行时提供了查询和操作一个对象图的强大的表达式语言。


2. 数据访问/集成:
数据访问/集成层包括 JDBC,ORM,OXM,JMS 和事务处理模块,它们的细节如下:

JDBC 模块提供了删除冗余的 JDBC 相关编码的 JDBC 抽象层。

ORM 模块为流行的对象关系映射 API,包括 JPA,JDO,Hibernate 和 iBatis,提供了集成层。

OXM 模块提供了抽象层,它支持对 JAXB,Castor,XMLBeans,JiBX 和 XStream 的对象/XML 映射实现。

Java 消息服务 JMS 模块包含生产和消费的信息的功能。

事务模块为实现特殊接口的类及所有的 POJO 支持编程式和声明式事务管理。

3. Web:
Web 层由 Web,Web-MVC,Web-Socket 和 Web-Portlet 组成,它们的细节如下:

Web 模块提供了基本的面向 web 的集成功能,例如多个文件上传的功能和使用 servlet 监听器和面向 web 应用程序的上下文来初始化 IoC 容器。

Web-MVC 模块包含 Spring 的模型-视图-控制器(MVC),实现了 web 应用程序。

Web-Socket 模块为 WebSocket-based 提供了支持,而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式。

Web-Portlet 模块提供了在 portlet 环境中实现 MVC,并且反映了 Web-Servlet 模块的功能。

4. 其他:
还有其他一些重要的模块,像 AOP,Aspects,Instrumentation,Web 和测试模块,它们的细节如下:

AOP 模块提供了面向方面的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,它实现了应该分离的功能。

Aspects 模块提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。

Instrumentation 模块在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。

Messaging 模块为 STOMP 提供了支持作为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。

测试模块支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试。

这篇笔记主要用来记录 核心容器:


IoC 容器

Spring 容器是 Spring 框架的核心。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。这些对象被称为 Spring Beans,

Spring 提供了以下两种不同类型的容器。

1 Spring BeanFactory 容器:
它是最简单的容器,给 DI 提供了基本的支持,它用 org.springframework.beans.factory.BeanFactory 接口来定义。BeanFactory 或者相关的接口,如 BeanFactoryAware,InitializingBean,DisposableBean,在 Spring 中仍然存在具有大量的与 Spring 整合的第三方框架的反向兼容性的目的。

2 Spring ApplicationContext 容器:
该容器添加了更多的企业特定的功能,例如从一个属性文件中解析文本信息的能力,发布应用程序事件给感兴趣的事件监听器的能力。该容器是由 org.springframework.context.ApplicationContext 接口定义。

建议:
在资源宝贵的移动设备或者基于 applet 的应用当中, BeanFactory 会被优先选择。否则,一般使用的是 ApplicationContext,除非你有更好的理由选择 BeanFactory。

最常被使用的 ApplicationContext 接口实现:

FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你需要提供给构造器 XML 文件的完整路径

ClassPathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你不需要提供 XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量即可,因为,容器会从 CLASSPATH 中搜索 bean 配置文件。

WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean。

一个简单的示例:

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new FileSystemXmlApplicationContext
            ("C:/Users/ZARA/workspace/HelloSpring/src/Beans.xml");
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
   }
}

在主程序当中,我们需要注意以下两点:

第一步生成工厂对象。加载完指定路径下 bean 配置文件后,利用框架提供的 FileSystemXmlApplicationContext API 去生成工厂 bean。FileSystemXmlApplicationContext 负责生成和初始化所有的对象,比如,所有在 XML bean 配置文件中的 bean。

第二步利用第一步生成的上下文中的 getBean() 方法得到所需要的 bean。 这个方法通过配置文件中的 bean ID 来返回一个真正的对象。一旦得到这个对象,就可以利用这个对象来调用任何方法。


Bean 定义

被称作 bean 的对象是构成应用程序的支柱也是由 Spring IoC 容器管理的。bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。这些 bean 是由用容器提供的配置元数据创建的,例如,已经在先前章节看到的,在 XML 的表单中的 定义。

bean 定义包含称为配置元数据的信息,下述容器也需要知道配置元数据:

  • 如何创建一个 bean
  • bean 的生命周期的详细信息
  • bean 的依赖关系

上述所有的配置元数据转换成一组构成每个 bean 定义的下列属性。

属性描述
class这个属性是强制性的,并且指定用来创建 bean 的 bean 类。
name这个属性指定唯一的 bean 标识符。在基于 XML 的配置元数据中,你可以使用 ID 和/或 name 属性来指定 bean 标识符。
scope这个属性指定由特定的 bean 定义创建的对象的作用域,它将会在 bean 作用域的章节中进行讨论。
constructor-arg它是用来注入依赖关系的,并会在接下来的章节中进行讨论。
properties它是用来注入依赖关系的,并会在接下来的章节中进行讨论。
autowiring mode它是用来注入依赖关系的,并会在接下来的章节中进行讨论。
lazy-initialization mode延迟初始化的 bean 告诉 IoC 容器在它第一次被请求时,而不是在启动时去创建一个 bean 实例。
initialization 方法在 bean 的所有必需的属性被容器设置之后,调用回调方法。它将会在 bean 的生命周期章节中进行讨论。
destruction 方法当包含该 bean 的容器被销毁时,使用回调方法。它将会在 bean 的生命周期章节中进行讨论。

Spring 配置元数据
Spring IoC 容器完全由实际编写的配置元数据的格式解耦。有下面三个重要的方法把配置元数据提供给 Spring 容器:

  • 基于 XML 的配置文件。
  • 基于注解的配置
  • 基于 Java 的配置

你已经看到了如何把基于 XML 的配置元数据提供给容器,但是让我们看看另一个基于 XML 配置文件的例子,这个配置文件中有不同的 bean 定义,包括延迟初始化,初始化方法和销毁方法的:


Bean 的作用域

Spring 框架支持以下五个作用域,如果你使用 web-aware ApplicationContext 时,其中最下面三个只在 web-aware Spring ApplicationContext 的上下文中有效。

作用域描述
singleton该作用域将 bean 的定义的限制在每一个 Spring IoC 容器中的一个单一实例(默认)。
prototype该作用域将单一 bean 的定义限制在任意数量的对象实例。
request该作用域将 bean 的定义限制为 HTTP 请求。
session该作用域将 bean 的定义限制为 HTTP 会话。
global-session该作用域将 bean 的定义限制为全局 HTTP 会话。

singleton 作用域
如果作用域设置为 singleton,那么 Spring IoC 容器刚好创建一个由该 bean 定义的对象的实例。该单一实例将存储在这种单例 bean 的高速缓存中,以及针对该 bean 的所有后续的请求和引用都返回缓存对象。

默认作用域是始终是 singleton,但是当仅仅需要 bean 的一个实例时,你可以在 bean 的配置文件中设置作用域的属性为 singleton

prototype 作用域
如果作用域设置为 prototype,那么每次特定的 bean 发出请求时 Spring IoC 容器就创建对象的新的 Bean 实例。一般说来,满状态的 bean 使用 prototype 作用域和没有状态的 bean 使用 singleton 作用域。


Bean 的生命周期

初始化回调

  • 实现InitializingBean 接口
  • 在基于 XML 的配置元数据的情况下,你可以使用 init-method 属性来指定带有 void 无参数方法的名称

销毁回调

  • 实现DisposableBean 接口
  • 在基于 XML 的配置元数据的情况下,你可以使用 destroy-method 属性来指定带有 void 无参数方法的名称

如果在非 web 应用程序环境中使用 Spring 的 IoC 容器;例如在丰富的客户端桌面环境中;那么在 JVM 中你要注册关闭 hook。这样做可以确保正常关闭,为了让所有的资源都被释放,可以在单个 beans 上调用 destroy 方法。

context.registerShutdownHook();

建议你不要使用 InitializingBean 或者 DisposableBean 的回调方法,因为 XML 配置在命名方法上提供了极大的灵活性。

默认的初始化和销毁方法
如果你有太多具有相同名称的初始化或者销毁方法的 Bean,那么你不需要在每一个 bean 上声明初始化方法和销毁方法。框架使用 元素中的 default-init-method 和 default-destroy-method 属性提供了灵活地配置这种情况


Spring——Bean 后置处理器

BeanPostProcessor 接口定义回调方法,你可以实现该方法来提供自己的实例化逻辑,依赖解析逻辑等。你也可以在 Spring 容器通过插入一个或多个 BeanPostProcessor 的实现来完成实例化,配置和初始化一个bean之后实现一些自定义逻辑回调方法。

你可以配置多个 BeanPostProcesso r接口,通过设置 BeanPostProcessor 实现的 Ordered 接口提供的 order 属性来控制这些 BeanPostProcessor 接口的执行顺序

BeanPostProcessor 可以对 bean(或对象)实例进行操作,这意味着 Spring IoC 容器实例化一个 bean 实例,然后 BeanPostProcessor 接口进行它们的工作。

ApplicationContext 会自动检测由 BeanPostProcessor 接口的实现定义的 bean,注册这些 bean 为后置处理器,然后通过在容器中创建 bean,在适当的时候调用它。

输出结果:

BeforeInitialization : life2
LifeCycle2->InitializingBean
AfterInitialization : life2
Your Message : life
LifeCycle2->DisposableBean

Bean 定义继承

bean 定义可以包含很多的配置信息,包括构造函数的参数,属性值,容器的具体信息例如初始化方法,静态工厂方法名,等等。

子 bean 的定义继承父定义的配置数据。子定义可以根据需要重写一些值,或者添加其他值。

Spring Bean 定义的继承与 Java 类的继承无关,但是继承的概念是一样的。你可以定义一个父 bean 的定义作为模板和其他子 bean 就可以从父 bean 中继承所需的配置。

当你使用基于 XML 的配置元数据时,通过使用父属性,指定父 bean 作为该属性的值来表明子 bean 的定义。

Bean 定义模板
你可以创建一个 Bean 定义模板,不需要花太多功夫它就可以被其他子 bean 定义使用。在定义一个 Bean 定义模板时,你不应该指定类的属性,而应该指定带 true 值的抽象属性


依赖注入

普通方式的注入

  • 基于构造函数的依赖注入
<constructor-arg ref="spellChecker"/>
  • 基于设值函数的依赖注入
<property name="spellChecker" ref="spellChecker"/>

注入内部 Beans

<bean id="outerBean" class="...">
      <property name="target">
         <bean id="innerBean" class="..."/>
      </property>
</bean>

注入集合

<list>  它有助于连线,如注入一列值,允许重复。
<set>   它有助于连线一组值,但不能重复。
<map>   它可以用来注入名称-值对的集合,其中名称和值可以是任何类型。
<props> 它可以用来注入名称-值对的集合,其中名称和值都是字符串类型。

Beans 自动装配

Spring 容器可以在不使用 和 元素的情况下自动装配相互协作的 bean 之间的关系,这有助于减少编写一个大的基于 Spring 的应用程序的 XML 配置的数量。

自动装配模式
下列自动装配模式,它们可用于指示 Spring 容器为来使用自动装配进行依赖注入。你可以使用 元素的 autowire 属性为一个 bean 定义指定自动装配模式。

模式描述
no这是默认的设置,它意味着没有自动装配,你应该使用显式的bean引用来连线。你不用为了连线做特殊的事。在依赖注入章节你已经看到这个了。
byName由属性名自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byName。然后尝试匹配,并且将它的属性与在配置文件中被定义为相同名称的 beans 的属性进行连接。
byType由属性数据类型自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byType。然后如果它的类型匹配配置文件中的一个确切的 bean 名称,它将尝试匹配和连接属性的类型。如果存在不止一个这样的 bean,则一个致命的异常将会被抛出。
constructor类似于 byType,但该类型适用于构造函数参数类型。如果在容器中没有一个构造函数参数类型的 bean,则一个致命错误将会发生。
autodetectSpring首先尝试通过 constructor 使用自动装配来连接,如果它不执行,Spring 尝试通过 byType 来自动装配。

自动装配的局限性
当自动装配始终在同一个项目中使用时,它的效果最好。如果通常不使用自动装配,它可能会使开发人员混淆的使用它来连接只有一个或两个 bean 定义。不过,自动装配可以显著减少需要指定的属性或构造器参数,但你应该在使用它们之前考虑到自动装配的局限性和缺点。

限制描述
重写的可能性你可以使用总是重写自动装配的 设置来指定依赖关系。
原始数据类型你不能自动装配所谓的简单类型包括基本类型,字符串和类。
混乱的本质自动装配不如显式装配精确,所以如果可能的话尽可能使用显式装配。

基于注解的配置

从 Spring 2.5 开始就可以使用注解来配置依赖注入。而不是采用 XML 来描述一个 bean 连线,你可以使用相关类,方法或字段声明的注解,将 bean 配置移动到组件类本身。

在 XML 注入之前进行注解注入,因此后者的配置将通过两种方式的属性连线被前者重写。

注解连线在默认情况下在 Spring 容器中不打开。因此,在可以使用基于注解的连线之前,我们将需要在我们的 Spring 配置文件中启用它。所以如果你想在 Spring 应用程序中使用的任何注解,可以考虑到下面的配置文件。

<context:annotation-config/>

一旦 被配置后,你就可以开始注解你的代码,表明 Spring 应该自动连接值到属性,方法和构造函数。让我们来看看几个重要的注解,并且了解它们是如何工作的:

@Required
@Required 注解应用于 bean 属性的 setter 方法。

@Autowired
@Autowired 注解可以应用到 bean 属性的 setter 方法,非 setter 方法,构造函数和属性。

@Qualifier
通过指定确切的将被连线的 bean,@Autowired@Qualifier 注解可以用来删除混乱

JSR-250 Annotations
Spring 支持 JSR-250 的基础的注解,其中包括了 @Resource@PostConstruct@PreDestroy 注解。

@Required

@Required 注释应用于 bean 属性的 setter 方法,它表明受影响的 bean 属性在配置时必须放在 XML 配置文件中,否则容器就会抛出一个 BeanInitializationException 异常。下面显示的是一个使用 @Required 注释的示例。

@Autowired

@Autowired 注释对在哪里和如何完成自动连接提供了更多的细微的控制。

@Autowired 注释可以在 setter 方法中被用于自动连接 bean,就像 @Autowired 注释,容器,一个属性或者任意命名的可能带有多个参数的方法。

Setter 方法中的 @Autowired
你可以在 XML 文件中的 setter 方法中使用 @Autowired 注释来除去 元素。当 Spring遇到一个在 setter 方法中使用的 @Autowired 注释,它会在方法中视图执行 byType 自动连接。

@Qualifier

当你创建多个具有相同类型的 bean 时,并且想要用一个属性只为它们其中的一个进行装配,在这种情况下,你可以使用 @Qualifier 注释和 @Autowired 注释通过指定哪一个真正的 bean 将会被装配来消除混乱。下面显示的是使用 @Qualifier 注释的一个示例。

JSR-250 注释

Spring还使用基于 JSR-250 注释,它包括 @PostConstruct@PreDestroy@Resource 注释。因为你已经有了其他的选择,尽管这些注释并不是真正所需要的,但是关于它们仍然让我给出一个简短的介绍。

@PostConstruct@PreDestroy 注释:
为了定义一个 bean 的安装和卸载,我们使用 init-method 和/或 destroy-method 参数简单的声明一下 。init-method 属性指定了一个方法,该方法在 bean 的实例化阶段会立即被调用。同样地,destroy-method 指定了一个方法,该方法只在一个 bean 从容器中删除之前被调用。

你可以使用 @PostConstruct 注释作为初始化回调函数的一个替代,@PreDestroy 注释作为销毁回调函数的一个替代,其解释如下示例所示。

@Resource 注释:
你可以在字段中或者 setter 方法中使用 @Resource 注释,它和在 Java EE 5 中的运作是一样的。@Resource 注释使用一个 ‘name’ 属性,该属性以一个 bean 名称的形式被注入。你可以说,它遵循 by-name 自动连接语义

基于 Java 的配置

@Configuration 和 @Bean 注解
带有 @Configuration 的注解类表示这个类可以使用 Spring IoC 容器作为 bean 定义的来源。@Bean 注解告诉 Spring,一个带有 @Bean 的注解方法将返回一个对象,该对象应该被注册为在 Spring 应用程序上下文中的 bean。

@Import 注解:
@import 注解允许从另一个配置类中加载 @Bean 定义。

指定 Bean 的范围:
默认范围是单实例,但是你可以重写带有 @Scope 注解的该方法

一个简单的示例:

@Configuration
public class Configer {

    @Bean
    public Bean1 getBean1(){
        return new Bean1();
    }

}


@Configuration
@Import(Configer.class)
public class ConfigChilder {

    @Bean
    public Bean2 getBean2(){
        return new Bean2();
    }

}

public class MainApp {


    public static void main(String[] args) {
        @SuppressWarnings("resource")
        ApplicationContext applicationContext =   new AnnotationConfigApplicationContext(ConfigChilder.class);
        Bean1 bean1 = applicationContext.getBean(Bean1.class);
        bean1.setMessage1("hello");
        bean1.getMessage1();
        Bean2 bean2 = applicationContext.getBean(Bean2.class);
        bean2.setMessage1("hello-bean2");
        bean2.getMessage1();
    }

}

Spring 中的事件处理

当加载 beans 时,ApplicationContext 发布某些类型的事件。例如,当上下文启动时,ContextStartedEvent 发布,当上下文停止时,ContextStoppedEvent 发布。

通过 ApplicationEvent 类和 ApplicationListener 接口来提供在 ApplicationContext 中处理事件。如果一个 bean 实现 ApplicationListener,那么每次 ApplicationEvent 被发布到 ApplicationContext 上,那个 bean 会被通知。

Spring 提供了以下的标准事件:

  • ContextRefreshedEvent
    ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在 ConfigurableApplicationContext 接口中使用 refresh() 方法来发生。

  • ContextStartedEvent
    当使用 ConfigurableApplicationContext 接口中的 start() 方法启动 ApplicationContext 时,该事件被发布。你可以调查你的数据库,或者你可以在接受到这个事件后重启任何停止的应用程序。

  • ContextStoppedEvent
    当使用 ConfigurableApplicationContext 接口中的 stop() 方法停止 ApplicationContext 时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作。

  • ContextClosedEvent
    当使用 ConfigurableApplicationContext 接口中的 close() 方法关闭 ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启。

  • RequestHandledEvent
    这是一个 web-specific 事件,告诉所有 bean HTTP 请求已经被服务。

一个简单的示例

public class CStartEventHandler 
   implements ApplicationListener<ContextStartedEvent>{
   public void onApplicationEvent(ContextStartedEvent event) {
      System.out.println("ContextStartedEvent Received");
   }
}


public class MainApp {
   public static void main(String[] args) {
      ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      // Let us raise a start event.
      context.start();
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
      // Let us raise a stop event.
      context.stop();
   }
}

打印结果:
ContextStartedEvent Received
Your Message : msg
ContextStoppedEvent Received


AOP

分为注解 和 xml配置,这次主要使用注解

在Spring中启用AspectJ注解支持
* 要在Spring应用中使用AspectJ注解,必须在classpath下包含AspectJ类库:aopalliance.jar、aspectj.weaver.jar和spring-aspects.jar
* 将aop Schema添加到根元素中。
* 要在Spring IOC容器中启用AspectJ注解支持,只要早bean配置文件中定义一个空的XML元素
* 当Spring IOC容器侦测到bean配置文件中的元素时,会自动为与AspectJ切面匹配的bean创建代理

用AspectJ注解声明切面
* 要在Spring中声明AspectJ切面,只需要在IOC容器中将切面声明为bean实例。当在Spring IOC容器中初始化AspectJ切面之后,Spring IOC容器就会为那些与AspectJ切面相匹配的bean创建代理
* 在AspectJ注解中,切面只是一个带有@AspectJ注解的Java类
* 通知是标注有某种注解的简单的Java方法

AspectJ支持5种类型的通知注解:
* @Before:前置通知,在方法执行之前返回
* @After:后置通知,在方法执行后执行
* @AfterRunning:返回通知,在方法返回结果之后执行
* @AfterThrowing:异常通知,在方法抛出异常之后
* @Around:环绕通知,围绕着方法执行

利用方法签名编写AspectJ切入点表达式

最典型的切入点表达式时根据方法的签名来匹配各种方法:
* -execution * com.yl.spring.aop.ArithmeticCalculator.(..):匹配ArithmeticCalculator中声明的所有方法,第一个代表任意修饰符及任意返回值,第二个*代表任意方法,..匹配任意数量的参数。若目标类与接口与切面在同一个包中,可以省略包名。
* -execution public * ArithmeticCalculator.*(..):匹配ArithmeticCalculator接口的所有公有方法
* -execution public double ArithmeticCalculator.*(..):匹配ArithmeticCalculator中返回double类型数值的方法
* -execution public double ArithmeticCalculator.*(double, ..):匹配第一个参数为double类型的方法,..匹配任意数量任意类型的参数
* -execution public double ArithmeticCalculator.*(double, double):匹配参数类型为double,double类型的方法

一个基于aspectj 注解的示例:

pom.xml配置文档:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>${aspectjrt.version}</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>${aspectjrt.version}</version>
</dependency>
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2</version>
</dependency>

xml配置文档:

<!-- 开启注解 -->
<context:annotation-config />
<!-- 自动扫描 -->
<context:component-scan base-package="cn.sunxyz.spring.aop" />
<!-- 启动 AspectJ 支持 -->
<aop:aspectj-autoproxy />

基于注解的类:

@Component
@Aspect
public class MyAdvice {

    @Pointcut("execution(* cn.sunxyz.spring.aop.*.*(..))") // expression
    private void businessService() {
    }

    // 在一个方法执行之前,执行通知。
    @Before("businessService()")
    public void doBeforeTask() {
        System.out.println("doBeforeTask.");
    }

    // 在一个方法执行之后,不考虑其结果,执行通知。
    @After("businessService()")
    public void doAfterTask() {
        System.out.println("doAfterTask.");
    }

    // 在一个方法执行之后,只有在方法成功完成时,才能执行通知。
    @AfterReturning(pointcut = "businessService()", returning = "retVal")
    public void doAfterReturnningTask(JoinPoint joinPoint, Object retVal) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("doAfterReturnningTask " + methodName + " return with " + retVal);
    }

    // 在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知
    @AfterThrowing(pointcut = "businessService()", throwing = "ex")
    public void doAfterThrowingTask(JoinPoint joinPoint, Exception ex) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("doAfterThrowingTask " + methodName + " occurs exception: " + ex);
    }

    // 在建议方法调用之前和之后,执行通知。
    @Around("businessService()")
    public Object doAroundTask(ProceedingJoinPoint jpoint) {
        Object result = null;
        String methodName = jpoint.getSignature().getName();
        // 执行目标方法
        try {
            // 前置通知
            System.out.println("The method " + methodName + " begins with " + Arrays.asList(jpoint.getArgs()));
            result = jpoint.proceed();
            // 返回通知
            System.out.println("The method " + methodName + " ends with " + Arrays.asList(jpoint.getArgs()));
        } catch (Throwable e) {
            // 异常通知
            System.out.println("The method " + methodName + " occurs expection : " + e);
            throw new RuntimeException(e);
        }
        // 后置通知
        System.out.println("The method " + methodName + " ends");
        return result;

    }
}

事务

事务的概念可以描述为具有以下四个关键属性说成是 ACID:
* 原子性:事务应该当作一个单独单元的操作,这意味着整个序列操作要么是成功,要么是失败的。
* 一致性:这表示数据库的引用完整性的一致性,表中唯一的主键等。
* 隔离性:可能同时处理很多有相同的数据集的事务,每个事务应该与其他事务隔离,以防止数据损坏。
* 持久性:一个事务一旦完成全部操作后,这个事务的结果必须是永久性的,不能因系统故障而从数据库中删除。

隔离级别:
* TransactionDefinition.ISOLATION_DEFAULT 这是默认的隔离级别。
* TransactionDefinition.ISOLATION_READ_COMMITTED 表明能够阻止误读;可以发生不可重复读和虚读。
* TransactionDefinition.ISOLATION_READ_UNCOMMITTED 表明可以发生误读、不可重复读和虚读。
* TransactionDefinition.ISOLATION_REPEATABLE_READ 表明能够阻止误读和不可重复读;可以发生虚读。
* TransactionDefinition.ISOLATION_SERIALIZABLE 表明能够阻止误读、不可重复读和虚读。

传播类型:
* TransactionDefinition.PROPAGATION_MANDATORY 支持当前事务;如果不存在当前事务,则抛出一个异常。
* TransactionDefinition.PROPAGATION_NESTED 如果存在当前事务,则在一个嵌套的事务中执行。
* TransactionDefinition.PROPAGATION_NEVER 不支持当前事务;如果存在当前事务,则抛出一个异常。
* TransactionDefinition.PROPAGATION_NOT_SUPPORTED 不支持当前事务;而总是执行非事务性。
* TransactionDefinition.PROPAGATION_REQUIRED 支持当前事务;如果不存在事务,则创建一个新的事务。
* TransactionDefinition.PROPAGATION_REQUIRES_NEW 创建一个新事务,如果存在一个事务,则把当前事务挂起。
* TransactionDefinition.PROPAGATION_SUPPORTS 支持当前事务;如果不存在,则执行非事务性。
* TransactionDefinition.TIMEOUT_DEFAULT 使用默认超时的底层事务系统,或者如果不支持超时则没有。

相关介绍:


参考:
* Spring 教程
* Spring 事务管理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值