Spring

Spring官方文档

Spring4中文文档

Spring 框架的作用

  • 轻力:spring 是轻量级的,基本的版本大小为2MB
  • 控制反转:spring 通过控制反转实现了松散耦合,对象给出它们的依赖,而不是创建或查找依赖的对象们。
  • AOP:spring 支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
  • 容器:spring 包含并管理应用中对象的生命周期和配置。
  • MVC:spring MVC框架
  • 事务管理:spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务JTA
  • 异常处理:spring 提供方便的API把具体技术相关的异常

Spirng 的组成

spring 由7个模块组成

  • Spring Core:核心容器提供 spring 框架的基本功能。核心容器的主要组件是BeanFactory,它是工厂模式的实现。BeanFactory使用控制反转(IoC)模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
  • Spring Context:spring 上下文是一个配置文件,向spring框架提供上下文信息。spring上下文包括企业服务,例如JNDI、EJB、电子邮件、国际化、校验和调度功能。
  • Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
  • Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
  • Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
  • Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
  • Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。

Spring 容器

Sping的容器可以分为两种类型:

  1. BeanFactory:(org.springframework.beans.factory.BeanFactory接口定义)是最简答的容器,提供了基本的DI支持。最常用的BeanFactory实现就是XmlBeanFactory类,它根据XML文件中的定义加载beans,该容器从XML文件读取配置元数据并用它去创建一个完全配置的系统或应用。
  2. ApplicationContext应用上下文:(org.springframework.context.ApplicationContext)基于BeanFactory之上构建,并提供面向应用的服务。

ApplicationContext通常的实现

  • ClassPathXmlApplicationContext:从类路径下的XML配置文件中加载上下文定义,把应用上下文定义文件当做类资源。
  • FileSystemXmlApplicationContext:读取文件系统下的XML配置文件并加载上下文定义。
  • XmlWebApplicationContext:读取Web应用下的XML配置文件并装载上下文定义。

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

IoC & DI

Inversion of Control, 一般分为两种类型:依赖注入DI(Dependency Injection)和依赖查找(Dependency Lookup).依赖注入应用比较广泛。

Spring IOC扶着创建对象,管理对象(DI),装配对象,配置对象,并且管理这些对象的整个生命周期。

优点:把应用的代码量降到最低。容器测试,最小的代价和最小的侵入性使松散耦合得以实现。IOC容器支持加载服务时的饿汉式初始化和懒加载。

DI依赖注入是IOC的一个方面,是个通常的概念,它有多种解释。这概念是说你不用床架对象,而只需要描述它如何被创建。你不在代码里直接组装你的组件和服务,但是要在配置文件里描述组件需要哪些服务,之后一个IOC容器辅助把他们组装起来。

IOC的注入方式:
1. 构造器依赖注入;
2. Setter方法注入。

如何给spring容器提供配置元数据

XML配置文件
基于注解的配置
基于Java的配置@Configuration, @Bean

beans标签中相关属性

default-init-method
default-destory-method

default-autowire:默认为none,应用于Spring配置文件中的所有Bean,注意这里不是指Spring应用上下文,因为你可以定义多个配置文件

bean标签中的属性:

id
name
class

init-method:Bean实例化后会立刻调用的方法

destory-method:Bean从容器移除和销毁前,会调用的方法

factory-method:运行我们调用一个指定的静态方法,从而代替构造方法来创建一个类的实例。

scope:Bean的作用域,包括singleton(默认),prototype(每次调用都创建一个实例), request,session, global-session(注意spring中的单例bean不是线程安全的)

autowired:自动装配 byName, byType, constructor, autodetect(首先阐释使用constructor自动装配,如果没有发现与构造器相匹配的Bean时,Spring将尝试使用byType自动装配)

Bean的生命周期

Bean的构造
调用setXXX()方法设置Bean的属性
调用BeanNameAwaresetBeanName()
调用BeanFactoryAwaresetBeanFactory()方法
调用BeanPostProcessorpostProcessBeforeInitialization()方法
调用InitializingBeanafterPropertiesSet()方法
调用自定义的初始化方法
调用BeanPostProcessor类的postProcessAfterInitialization()方法
调用DisposableBeandestroy()方法
调用自定义的销毁方法

Spring中注入集合

<list>允许值相同

<set>不允许值相同

<key>键和值都可以为任意类型,key, key-ref, value-ref, value可以任意搭配

XXX键和值都只能是String类型

装配空值

<property name="xxx"><null/></property>

自动装配(autowiring)

有助于减少甚至消除配置和元素,让Spring自动识别如何装配Bean的依赖关系。<context:annotation-config/>

与之对应的是:自动检测(autodiscovery),比自动装配更近了一步,让Spring能够自动识别哪些类需要被配置成SpringBean,从而减少对元素的使用。<context:component-scan>

注解

Spring容器默认禁用注解装配。最简单的开启方式<context:annotation-config/>
Spring支持的几种不同的用于自动装配的注解:

Spring自带的@Autowired注解
JSR-330的@Inject注解
JSR-250的@Resource注解

@Autowired

@Autowired具有强契约特征,其所标注的属性或参数必须是可装配的。如果没有Bean可以装配到@Autowired所标注的属性或参数中,自动装配就会失败,抛出NoSuchBeanDefinitionException.

属性不一定非要装配,null值也是可以接受的。在这种场景下可以通过设置@Autowiredrequired属性为false来配置自动装配是可选的,如:

@Autowired(required=false)
private Object obj;

注意required属性可以用于@Autowired注解所使用的任意地方。但是当使用构造器装配时,只有一个构造器可以将@Autowiredrequired属性设置为true。其他使用@Autowired注解所标注的构造器只能将required属性设置为false。此外,当使用@Autowired标注多个构造器时,Spring就会从所有满足装配条件的构造器中选择入参最多的那个构造器。

可以使用@Qualifier明确指定要装配的Bean.如下:

@Autowired
@Qualifier("objName")
private Object obj;

自定义的限定器

@Target({ElementType.FIELF, ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @Interface SpecialQualifier{}

此时,可以通过自定义的@SpecialQualifier注解来代替@Qualifier来标注,也可以和@Autowired一起使用:

@Autowired
@SpecialQualifier
private Object obj;

此时,Spring会把自动装配的范围缩小到被@SpecialQualifier标注的Bean中。如果被@SpecialQualifier标注的Bean有多个,我们还可以通过自定义的另一个限定器@SpecialQualifier2来进一步缩小范围。

@Autowired优缺点

Spring的@Autowired注解是减少Spring XML配置的一种方式。但是它的类会映入对Spring的特定依赖(即使依赖只是一个注解)。

@Inject

@Autowired注解一样,@Inject可以用来自动装配属性、方法和构造器;与@Autowired不同的是,@Inject没有required属性。因此@Inject注解所标注的依赖关系必须存在,如果不存在,则会抛出异常。

@Named

相对于@Autowired对应的@Qualifier@Inject所对应的是@Named注解。

@Inject
@Named("objName")
private Object obj;

SpEL表达式

语法形式在#{}中使用表达式,如:

<property name="count" value="#{5}"/>

@Value

@Value是一个新的装配注解,可以让我们使用注解装配String类型的值和基本类型的值,如int, boolean。我们可以通过@Value直接标注某个属性,方法或者方法参数,并传入一个String类型的表达式来装配属性,如:

@Value("Eruption")
private String song;

@Value可以配合SpEL表达式一起使用,譬如有些情况下需要读取properties文件中的内容,可以使用:

@Value("#{configProperties['ora_driver']}")

自动检测Bean

<context:component-scan>元素除了完成与<context:annotation-config>一样的工作,还允许Spring自动检测Bean和定义Bean.<context:component-scan>元素会扫描指定的包和其所有子包,如下:

<context:component-scan base-package="project.service" />

为自动检测标注Bean

默认情况下,查找使用构造型(stereotype)注解所标注的类,这些特殊的注解如下:
- @Component:通用的构造型注解,标志此类为Spring组件
- @Controller:标识将该类定义为SpringMVC controller
- @Repository:标识将该类定义为数据仓库
- @Service:标识将该类定义为服务

以@Component为例:

@Component
public class Guitar implements Intrument{}

这里@Component会自动注册Guitar 为Spring Bean,并设置默认的Bean的Id为guitar,首字母大写变小写。注意如果第一个和第二个字母都是大写,默认的Bean的id会有特殊处理。
也可以指定Bean的Id如:

@Component("guitarOne")
public class Guitar implements Intrument{}

AOP

面向切面的编程AOP,是一种编程技术,允许程序模块化横向切割关注点,或横切典型的责任划分,如日志和事务管理。

AOP的核心是切面,它将多个类的通用行为封装成可重用的模块,该模块含有一组API提供横切功能。比如,一个日志模块可以被称作日志的AOP切面。根据需求的不同,一个应用程序可以有若干切面。在SpringAOP中,切面通过带有@Aspect注解的类实现。

关注点是应用中的一个模块的行为,一个关注点可能会被定义成一个我们想实现的一个功能。

横切关注点一个关注点,此关注点是整个应用都会使用的功能,并影响整个应用,比如日志,安全和数据传输,几乎应用的每个模块都需要的功能。因此这些都属于横切关注点。

连接点代表一个应用程序的某个位置,在这个位置我们可以插入一个AOP切面,它实际上是个应用程序执行Spring AOP的位置。

切点是一个或一组连接点,通知将在这些位置执行。可以通过表达式或匹配的方式指明切入点。

引入运行我们在已存在的类中添加新的方法和属性。

AOP通知

通知是个在方法执行前后要做的动作,实际上是程序执行时要通过SpringAOP框架触发的代码

Spring切面可以应用五种类型的通知:

  • before:前置通知,在一个方法执行前被调用。@Before
  • after: 在方法执行之后调用的通知,无论方法执行是否成功。@After
  • after-returning: 仅当方法成功完成后执行的通知。@AfterReturning
  • after-throwing: 在方法抛出异常退出时执行的通知。@AfterThrowing
  • around: 在方法执行之前和之后调用的通知。@Around

基于JDK和CGLIB的代理

  • 如果一个需要被代理的目标对象的类(后面将简单地称它为目标类)没有实现任何接口,那么一个基于CGLIB的代理将被创建。 这是最简单的场景,因为JDK代理是基于接口的,没有接口意味着没有使用JDK进行代理的可能.
  • 如果ProxyFactoryBean的proxyTargetClass属性被设为true,那么一个基于CGLIB的代理将创建。 这样的规定是有意义的,遵循了最小惊讶法则(保证了设定的一致性)。甚至当ProxyFactoryBeanproxyInterfaces属性被设置为一个或者多个全限定接口名, 而proxyTargetClass属性被设置为true仍然将实际使用基于CGLIB的代理。

- 如果ProxyFactoryBeanproxyInterfaces属性被设置为一个或者多个全限定接口名,一个基于JDK的代理将被创建。 被创建的代理将实现所有在proxyInterfaces属性里被说明的接口; 如果目标类实现了全部在proxyInterfaces属性里说明的接口以及一些额外接口,返回的代理将只实现说明的接口而不会实现那些额外接口。

如果ProxyFactoryBean的proxyInterfaces属性没有被设置, 但是目标类实现了一个(或者更多)接口,那么ProxyFactoryBean将自动检测到这个目标类已经实现了至少一个接口, 一个基于JDK的代理将被创建。被实际代理的接口将是目标类所实现的全部接口; 实际上,这和在proxyInterfaces属性中列出目标类实现的每个接口的情况是一样的。 然而,这将显著地减少工作量以及输入错误的可能性。

Spring的事务类型

  1. 编程式事务管理:这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。
  2. 声明式事务管理:这意味着你可以将业务代码和事务管理分离,你只需用注解和XML配置来管理事务。

ACID

  • Atomic原子性:事务是由一个或多个活动所组成的一个工作单元。原子性确保事务中的所有操作全部发生或者全部不发生。
  • Consistent一致性:一旦事务完成,系统必须确保它所建模的业务处于一致的状态
  • Isolated隔离性:事务允许多个用户对象头的数据进行操作,每个用户的操作不会与其他用户纠缠在一起。
  • Durable持久性:一旦事务完成,事务的结果应该持久化,这样就能从任何的系统崩溃中恢复过来。

JDBC事务

如果在应用程序中直接使用JDBC来进行持久化,譬如博主采用的是Mybatis,DataSourceTransactionManager会为你处理事务边界。譬如:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
      destroy-method="close">
      <property name="driverClassName" value="${driver}" />
      <property name="url" value="${url}" />
      <property name="username" value="zzh" />
      <property name="password" value="zzh" />
      <property name="validationQuery" value="SELECT 1"/>
  </bean>
  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="dataSource"/>
  </bean>

JTA事务

如果你的事务需要跨多个事务资源(例如:两个或多个数据库;或者如Sping+ActiveMQ整合需要将ActiveMQ和数据库的事务整合起来),就需要使用JtaTransactionManager:

<bean id="jtaTransactionManager"class="org.springframework.transaction.jta.JtaTransactionManager"/>

JtaTransactionManager将事务管理的职责委托给了一个JTA的实现。JTA规定了应用程序与一个或多个数据源之间协调事务的标准API。transactionManagerName属性指明了要在JNDI上查找的JTA事务管理器。

JtaTransactionManager将事务管理的职责委托给javax.transaction.UserTransaction和javax.transaction.TransactionManager对象。通过UserTransaction.commit()方法来提交事务。类似地,如果事务失败,UserTransaction的rollback()方法将会被调用。

声明式事务

尽管Spring提供了多种声明式事务的机制,但是所有的方式都依赖这五个参数来控制如何管理事务策略。因此,如果要在Spring中声明事务策略,就要理解这些参数。(@Transactional)

传播行为(propagation)

  • ISOLATION_DEFAULT: 使用底层数据库预设的隔离层级
  • ISOLATION_READ_COMMITTED: 允许事务读取其他并行的事务已经送出(Commit)的数据字段,可以防止Dirty read问题
  • ISOLATION_READ_UNCOMMITTED: 允许事务读取其他并行的事务还没送出的数据,会发生Dirty、Nonrepeatable、Phantom read等问题
  • ISOLATION_REPEATABLE_READ: 要求多次读取的数据必须相同,除非事务本身更新数据,可防止Dirty、Nonrepeatable read问题
  • ISOLATION_SERIALIZABLE: 完整的隔离层级,可防止Dirty、Nonrepeatable、Phantom read等问题,会锁定对应的数据表格,因而有效率问题

隔离级别(isolation)

  • PROPAGATION_REQUIRED–支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
  • PROPAGATION_SUPPORTS–支持当前事务,如果当前没有事务,就以非事务方式执行。
  • PROPAGATION_MANDATORY–支持当前事务,如果当前没有事务,就抛出异常。
  • PROPAGATION_REQUIRES_NEW–新建事务,如果当前存在事务,把当前事务挂起。
  • PROPAGATION_NOT_SUPPORTED–以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • PROPAGATION_NEVER–以非事务方式执行,如果当前存在事务,则抛出异常。
  • PROPAGATION_NESTED–如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。

只读(read-only)

如果事务只进行读取的动作,则可以利用底层数据库在只读操作时发生的一些最佳化动作,由于这个动作利用到数据库在只读的事务操作最佳化,因而必须在事务中才有效,也就是说要搭配传播行为PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED来设置。

事务超时(timeout)

有的事务操作可能延续很长一段的时间,事务本身可能关联到数据表的锁定,因而长时间的事务操作会有效率上的问题,对于过长的事务操作,考虑Roll back事务并要求重新操作,而不是无限时的等待事务完成。 可以设置事务超时期间,计时是从事务开始时,所以这个设置必须搭配传播行为PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED来设置。

回滚规则(rollback-for, no-rollback-for)

rollback-for指事务对于那些检查型异常应当回滚而不提交;no-rollback-for指事务对于那些异常应当继续运行而不回滚。默认情况下,Spring声明事务对所有的运行时异常都进行回滚。

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="*" />
    </tx:attributes>
</tx:advice>

SpringMVC

!

核心架构的具体流程:

  1. 首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
  2. DispatcherServlet——>HandlerMapping, HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象,通过这种策略模式,很容易添加新的映射策略;
  3. DispatcherServlet——>HandlerAdapter,HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;
  4. HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名);
  5. ModelAndView的逻辑视图名——> ViewResolver, ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术
  6. View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;
  7. 返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。

DispatcherServlet

SpringMVC的核心是DispatcherServlet,这个Servlet充当SpringMVC的前端控制器。与其他Servlet一样,DispatcherServlet必须在Web应用程序的web.xml文件中进行配置。

<servlet>
    <servlet-name>viewspace</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet        
    </servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

默认情况下,DispatcherServlet在加载时会从一个基于这个Servlet名字的XML文件中加载Spring应用上下文。因为servlet的名字是viewspace,所以配置文件的名称为viewspace-servlet.xml。
接下来,必须申明DispatcherServlet处理那些URL:

<servlet-mapping>
    <servlet-name>viewspace</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

通过将DispatcherServlet映射到/,声明了它会作为默认的servlet并且会处理所有的请求,包括对静态资源的请求。
可以配置:

<mvc:resources mapping="/images/**" location="/images/"
    cache-period="31556926" />
<mvc:resources mapping="/js/**" location="/js/"
    cache-period="31556926" />
<mvc:resources mapping="/css/**" location="/css/"
    cache-period="31556926" />

配置HandlerMapping

Spring自带了多个处理器映射实现:

  • BeanNameUrlHandlerMapping:根据控制器Bean的名字将控制器映射到URL。
  • ControllerBeanNameHandlerMapping:与BeanNameUrlHandlerMapping类似,根据控制器Bean的名字将控制器映射到URL。使用该处理器映射实现,Bean的名字不需要遵循URL的约定。
  • ControllerClassNameHandlerMapping:通过使用控制器的类名作为URL基础将控制器映射到URL。
  • DefaultAnnotationHandlerMapping:将请求映射给使用@RequestingMapping注解的控制器和控制器方法。
  • SimpleUrlHandlerMapping:使用定义在Spring应用上下文的熟悉集合将控制器映射到URL。

使用如上这些处理器映射通常只需在Spring中配置一个Bean。如果没有找到处理器映射Bean,DisapatchServlet将创建并使用BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping。我们一般使用基于注解的控制器类。

<mvc:annotation-driven />
<bean id="defaultAnnotationHandlerMapping"
   class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
</bean>

在构建控制器的时候,我们还需要使用注解将请求参数绑定到控制器的方法参数上进行校验以及信息转换。提供注解驱动的特性。

配置HandlerAdapter

<bean id="annotationMethodHandlerAdapter"
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />

配置视图

在SpringMVC中大龄使用了约定优于配置的开发模式。InternalResourceViewResolver就是一个面向约定的元素。它将逻辑视图名称解析为View对象,而该对象将渲染的任务委托给Web应用程序上下文中的一个模板。

<!-- 配置视图解析器,将ModelAndView及字符串解析为具体的页面 -->
<bean
       class="org.springframework.web.servlet.view.InternalResourceViewResolver">
   <property name="viewClass"
       value="org.springframework.web.servlet.view.JstlView" />
   <property name="prefix" value="/WEB-INF/jsp/" />
   <property name="suffix" value=".jsp" />
</bean>

当DispatcherServlet要求InternalResourceViewResolver解析视图的时候,它将获取一个逻辑视图名称,添加”/WEB-INF/jsp/”前缀和”.jsp”后缀。等待的结果就是渲染输出的JSP路径。在内部,InternalResourceViewResolver接下来会将这个路径传递给View对象,View对象将请求传递给JSP.

Spring 之 SpEL

字面值

#{6}
#{3.14}
#{'hello'}或者#{"hello"}
#{true}和#{false}

Bean

<bean name="student" class="com.lee.Student" />
#{student}
#{student.name}
#{student.say()}
<!-- 判断null值, 使用null-safe存取器 -->
<!-- 如果say()返回null, 则停止toUpperCase() -->
#{student.say()?.toUpperCase()}

操作类

#{T(java.lang.Math).PI}
#{T(java.lang.Math).random()}

运算符

运算符类型运算符
算术运算+, - , *, /, %, ^
关系运算<,>,==,<=,>=,lt,gt,eq,le,ge
逻辑运算and, or, not, |
条件运算?: (ternary), ?: (Elvis)
正则表达式matches

定时任务

spring task,可以将它比作一个轻量级的Quartz,而且使用起来很简单,除spring相关的包外不需要额外的包,而且支持注解和配置文件两种

demo

此处使用最简单的例子

XML方式

package com.lee.spring_test.task;

import java.util.Date;

public class TaskXml {
    public void xmlCronTask() {
        System.out.println(new Date() + ": 敌军还有30秒到达!");
    }
}

applicationContext-task.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:task="http://www.springframework.org/schema/task"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.2.xsd
        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-4.2.xsd">

    <!-- 
        cronExpression的配置说明,具体使用以及参数请百度google
        字段   允许值   允许的特殊字符
        秒    0-59    , - * /
        分    0-59    , - * /
        小时    0-23    , - * /
        日期    1-31    , - * ? / L W C
        月份    1-12 或者 JAN-DEC    , - * /
        星期    1-7 或者 SUN-SAT    , - * ? / L C #
        年(可选)    留空, 1970-2099    , - * / 
        - 区间  
        * 通配符  
        ? 你不想设置那个字段
        下面只例出几个式子

        CRON表达式    含义 
        "0 0 12 * * ?"    每天中午十二点触发 
        "0 15 10 ? * *"    每天早上10:15触发 
        "0 15 10 * * ?"    每天早上10:15触发 
        "0 15 10 * * ? *"    每天早上10:15触发 
        "0 15 10 * * ? 2005"    2005年的每天早上10:15触发 
        "0 * 14 * * ?"    每天从下午2点开始到2点59分每分钟一次触发 
        "0 0/5 14 * * ?"    每天从下午2点开始到2:55分结束每5分钟一次触发 
        "0 0/5 14,18 * * ?"    每天的下午2点至2:55和6点至6点55分两个时间段内每5分钟一次触发 
        "0 0-5 14 * * ?"    每天14:00至14:05每分钟一次触发 
        "0 10,44 14 ? 3 WED"    三月的每周三的14:10和14:44触发 
        "0 15 10 ? * MON-FRI"    每个周一、周二、周三、周四、周五的10:15触发 
     -->
    <bean id="xmlTask" class="com.lee.spring_test.task.TaskXml" />
    <task:scheduled-tasks>
        <task:scheduled ref="xmlTask" method="xmlCronTask"
            cron="0/30 * * * * *" />
    </task:scheduled-tasks>

</beans>

Test.java

package com.lee.spring_test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    }
}

task

注解方式

package com.lee.spring_test.task;

import java.util.Date;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component("task")
public class TaskAnnotation {
    @Scheduled(cron="0/30 * * * * *")
    public void xmlCronTask() {
        System.out.println(new Date() + ": 敌军还有30秒到达!");
    }
}

applicationContext-task.xml

...

<context:component-scan base-package="com.lee.spring_test" />
<task:annotation-driven/>
...

Demo

下载spring包

Download

一, 添加所需jar包

commons-logging-1.3.jar
spring-beans-4.2.5.RELEASE.jar
spring-context-4.2.5.RELEASE.jar
spring-context-support-4.2.5.RELEASE.jar
spring-core-4.2.5.RELEASE.jar
spring-expression-4.2.5.RELEASE.jar
spring-test-4.2.5.RELEASE.jar

二, 编写接口

package com.lee.service;

public interface Hello {
    public void say(String name);   //方法说明
}

三, 编写接口实现类

package com.lee.service.impl;

import org.springframework.stereotype.Service;
import com.lee.service.Hello;

@Service    //注册bean
public class HelloImpl implements Hello {
    @Override
    public void say(String name) {
        System.out.println("Hello " + name);
    }
}

四, 编写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"
    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-3.0.xsd">

    <!-- 使用了注解, 需要告诉spring上下文去哪里找, 并注册到spring上下文中 -->
    <context:component-scan base-package="com.lee" />
    <!-- 
        若不使用注解, 则需要添加以下代码注册bean到spring上下文中
        <bean id="hello" class="com.lee.service.impl.HelloImpl" />
     -->
</beans>

五, 使用JUnit4测试框架测试spring

package com.lee.test.service;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.lee.service.Hello;

@RunWith(SpringJUnit4ClassRunner.class)    //整合spring和JUnit4
@ContextConfiguration(locations="classpath:applicationContext.xml")//声明xml所在
public class HelloTest {

    @Autowired   //自动装载
    private Hello hello;

    @Test
    public void hello() {
        hello.say("Lee");
    }
}

文件格式

文件格式


控制台输出
控制台输出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值