Spring是一个基于IOC和AOP的结构J2EE系统的框架,对象的生命周期由Spring来管理
IOC(Inversion Of Control):控制反转
DI(Dependency Inject): 依赖注入
AOP(Aspect Oriented Program):面向切面编程(实现周边功能,比如性能统计,日志,事务管理等)
方法:
新建对象的set和get方法
新建bean configuration … - applicationContext.xml、并在这个xml配置文件(SpringIOC容器)中使用Bean创建对象并且给对象及其属性赋值
<bean id="id(唯一)" class="包名.类名">
<property name="属性名" value="属性值" />
<property name="属性名" ref="属性映射(对应对象的id值)" />
</bean>
然后通过主函数中 ApplicationContext取出对象
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
类 实例名 = (类名) context.getBean("id");
三种依赖注入方式:set方法注入(同上)、构造方法注入( < constructor-arg value(ref)=“value” type=“type” index=“0” name=“属性名”>< /constructor-arg>)、p命名空间注入(引入p命名空间、简单类型:p:属性名=“属性值”、引用类型(除了String外):p:属性名-ref=“引用的id”)
IOC容器赋值:如果是简单类型(8个基本+String),value; 如果是对象类型,ref=“需要引用的id值”,因此实现了对象与对象之间的依赖关系、赋值null< property name=“name” > < null/>< /property>、赋值空值< property name=“name” > < value>< /value> < /property>、集合类型赋值proprety中使用< set> < list> < array>等,可以混着用。注意< map> 中使用< entry> < key>< value>
value与< value>注入方式的区别:value必须使用双引号,不能使用type属性,只能采用实体引用处理特殊符号,后者可以使用标记处理特殊符号
自动装配:bean中的autowire只适用于ref类型,autowire=“byName|byType|constructor|no”、实现全局自动装配default-autowire=“byName|by…”、注解形式的自动装配@Autowired、默认是byType、 @Qualifier(“id”)、改为byName
使用注解:
ApplicationContext中增加扫描包
< context:component-scan base-package="包名">
</ context:component-scan>
对应包中加入注解:@Component(“id”)细化:(dao层注解:@Repository)(service层注解:@Service)(控制器层注解:@Controller)
使用注解实现声明式事务:实现数据库的事务
配置:配置数据库相关、配置事务管理器txManager、增加对事务的支持;使用:方法明前增加注解@Transactional并增加其属性和方法
AOP:前置通知、后置通知、环绕通知、异常通知
实现方式:实现类、实现接口、注解、配置
接口形式AOP:实现接口并重写方法(前置MethodBeforeAdvice)(后置AfterReturningAdvice)(环绕MethodInterceptor)(异常ThrowsAdvice)、 ApplicationContext中加入业务类方法的对象和通知类方法的对象、增加配置:
< aop:config>
<!-- 切入点(连接线的一端:业务类的具体方法) -->
< aop:pointcut expression="execution(public * 业务类名.方法名(参数类型))" id="poioncut"/>
<!-- (连接线的另一端:通知类) -->
< aop:advisor advice-ref="通知类名" pointcut-ref="poioncut" />
</aop:config>
环绕通知:可以获取目标方法的全部控制权,目标方法的一切信息可以通过invocation参数获取到,底层是通过拦截器实现的、环绕通知类实现MethodInterceptor接口和invoke方法, result = invocation.proceed() ;中result获得返回值,invocation.proceed()实现业务类方法执行,try中实现前置通知和后置通知、catch中捕获异常并实现异常通知
注解形式AOP:@Component引入注解识别@Aspect修饰类形成通知类 @Before(pointcut=“execution(public * 业务类名.方法名(参数类型))”)修饰方法形成通知前置方法、后置@AfterReturning(returning=“returningValue”)、异常@AfterThrowing(throwing=“e”)、环绕@Around、方法中的参数可以使用JoinPoint jp、返回值参数Object returningValue、返回异常参数NullPointerException e、环绕通知中参数使用ProceedingJoinPoint jp
配置:增加扫描包、开启AOP注解代理< aop:aspectj-autoproxy>< /aop:aspectj-autoproxy>
配置形式AOP:写通知类logSchema及其通知方法,并将通知类和业务类加入到IOC容器中,applicationContext配置:
<aop:config>
<!-- 切入点(连接线的一端:业务类的具体方法) -->
<aop:pointcut expression="" id="pcShema"/>
<!-- 原方法(连接线的另一端:通知类)<aop:advisor advice-ref="logSchea" pointcut-ref="pcShema" />-->
<!-- schema方式 -->
<aop:aspect ref="logSchema">
<!-- 连接线:连接业务和通知before -->
<aop:before method="before" pointcut-ref="pcShema"/>
<!-- 连接线:连接业务和通知afterReturning -->
<aop:after-returning method="afterReturning" returning="returnValue" pointcut-ref="pcShema"/>
<!-- 连接线:连接业务和通知Exception -->
<aop:after-throwing method="Exception" pointcut-ref="pcShema" throwing="e"/>
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pcShema" />
</aop:aspect>
</aop:config>
WEB项目整合Spring:
IOC初始化:当服务启动时(tomcat),通过监听器将SpringIOC容器初始化一次(该监听器 spring-web.jar已经提供)web.xml配置、推荐方法:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext.xml,
<!--.默认约定的位置:WEB-INF/applicationContext.xml-->
classpath:applicationContext-*.xml
</param-value>
</context-param>
将applicationContext分层:cotroller、service、dao并分别实例化和依赖注入
实现Web容器和IOC容器的整合(手动方式):从IOC容器中求出实例对象、一般在servlet初始化中实现
public void init() throws ServletException {
//ApplicationContext context= new ClassPathXmlApplicationContext("applicationContext-Service");
ApplicationContext context=WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
studentService=(IStudentService)context.getBean("studentService");
<!--类 实例名 = (类名) context.getBean("id");-->
}
最后完善web项目
注解形式存放bean:
(配置类)必须有@Configuration注解
//存bean
@bean
//取bean
ApplicationContext context = new AnnotationConfigApplicationContext(配置类.class) ;
三层组件:(@Controller、@Service、@Repository -> @Component)+配置文件或者注解扫描器@component-scan(只对三层组件负责)、扫描器指定规则(FilterType(ANNOTATION,ASSIGNABLE_TYPE,CUSTOM))
非三层组件(转换器): @Bean+方法的返回值、@import(直接编写到@Import中且id值是全类名、——自定义ImportSelector接口的实现类,通过selectimports方法实现(方法的返回值就是要纳入IoC容器的Bean),并且告知程序自己编写的实现类@Import({Orange.class,MyImportSelector.class})、——编写ImportBeanDefinitionRegistrar接口的实现类,重写方法
@Import({Orange.class,MyImportSelector.class,ImportBeanDefinitionRegistrar.class})并且告知程序自己编写的实现类)、FactoryBean(工厂Bean、准备bean实现类和重写方法,注册bean注册到@Bean中)
bean的作用域:scope(singleton)单例默认值、@scope(prototype)多实例(singleton:容器在初始化时,就会创建对象(唯一的一个),支持延迟加载@Lazy、prototype:容器在初始化时,不创建对象;只是在每次使用时创建对象)
条件注解:可以让某一个Bean在某些条件下加入Ioc容器,其他情况下不加入容器,通过实现condition接口
Bean的生命周期:创建(new …)、初始化(赋初值)、 …、销毁
@Bean+返回值方式
@Bean(value="stu",initMethod = "myInit",destroyMethod = "myDestroy")
三层组件功能性注解方式:将响应组件加入@Component(value="")注解、 给初始化方法加@PostConstruct、给销毁方法加@PreDestroy
三次组件接口方法:InitializingBean初始化、DisposableBean 销毁并实现其中的方法
接口BeanPostProcessor:拦截了所有中容器的Bean,并且可以进行bean的初始化 、销毁
BeanFactoryPostProcessor:bean被实例化之前
BeanDefinitionRegistryPostProcessor:bean被加载之前
具体顺序:BeanDefinitionRegistryPostProcessor(a) ->加载bean->BeanFactoryPostProcessor(b)->实例化bean->BeanPostProcessor
自动装配
@Autowired根据类型自动注入、结合@Qualifier("")根据名字注入、默认值@primary、@Autowired(required=false)修改未匹配为null
三层组件:如果@Autowired在属性前标注则不调用set方式;如果标注在set前面则调用set方式;不能放在方法的参数前
Bean+返回值:@Autowired可以在方法的参数前(也可以省略)、方法前(如果只有一个有参构造方法则@Autowired也可以省略)
@Resource根据名字自动注入,没有名字然后根据类型
@Inject默认根据类型匹配(引入jar包)
底层组件:实现Aware的子接口,从而获取到开发的组件对象,对对象进行操作
环境切换:bean前@Profile说明条件注入
激活
1.运行环境中设置参数-Dspring.profiles.active=@Profile环境名
2.硬编码:IoC容器在使用时必须refresh(),需要设置保存点|配置类的编写处
//注解方式
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext() ;
ConfigurableEnvironment environment = (ConfigurableEnvironment)context.getEnvironment();
environment.setActiveProfiles("@Profile环境名");
//保存点
context.register(配置类名.class);
context.refresh();
监听器:可以监听事件,监听的对象必须是ApplicationEvent自身或其子类/子接口
1.监听类实现ApplicationEvent接口
2.监听类注解形式申明是监听方法
@Component
public class MyListener {
//本方法是一个监听方法
@EventListener(classes = {
ApplicationEvent.class})
public void myListenerMethod(ApplicationEvent event){
System.out.println("--0000000--------"+event);
}
}
SpringMVC构建Web应用程序的全功能MVC模块
配置与使用:
JSP发出请求
将Servlet的访问通过web.xml配置文件拦截请求,交给SpringMVC处理、快速创建:alt+/ dispatcherServlet
<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--默认路径/WEB-INF/springDispatcherServlet-servlet.xml-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
springmvc.xml中配置扫描包和视图解析器(用于解析返回值地址并通过请求转发实现页面跳转)
<!--配置视图解析器(InternalResourceViewResolver) -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--view-name会被视图解析器加上前缀和后缀 -->
控制器中添加注解@controller(实现扫描包扫描)@RequestMapping(映射匹配类、类之前)、@RequestMapping(value,method,params)(映射匹配方法、方法之前)(可以增加个属性和约束条件对请求参数进行约束)、@PathVariable获取动态参数
REST风格:GET :查、POST :增、DELETE :删、PUT :改
springmvc实现给普通浏览器增加 put|delete请求方式 :put|post请求方式的步骤:
1.web.xml增加HiddenHttpMethodFilte过滤器
<filter>
<filter-name>HiddenHttpMethodFilte</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilte</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2.表单提交必须是post方法且通过隐藏域的value值设置实际的请求方式DELETE|PUT (< input type=“hidden” name="_method" value=“DELETE”/>)
3.控制器实现提交方式约束匹配、参数获取和功能执行
处理数据模型:跳转时需要带数据和页面(ModelAndView、ModelMap、Map、Model -数据放在了request作用域)
ModelAndView:
public ModelAndView testModelAndView() {
ModelAndView mv = new ModelAndView("jsp");
mv.addObject("属性名", 属性值或对象);
return mv;}
ModelMap:
public String testModelMap(ModelMap mm) {
mm.put("属性名", 属性值或对象);
return "jsp";}
Map:
public String testMap(Map<String,Object> m) {
m.put("属性名", 属性值或对象);
return "jsp";}
Model:
public String testMode(Model model) {
model.addAttribute("属性名", 属性值或对象);
return "jsp";}
@SessionAttributes(value\type):实现将数据放在request中的同时也将数据放在session中
@ModelAttribute:通过@ModelAttribute修饰的方法,会在每次请求前先执行;并且该方法的参数map.put()可以将对象放入即将查询的参数中,可以进行属性值的修改
视图的顶级接口:Views
视图解析器的顶级接口:ViewsResolver
国际化:针对不同地区、不同国家进行不同的显示 (创建资源文件、配置springmvc.xml并加载资源文件、通过jstl使用国际化)
<!--加载国际化资源文件-->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n"></property>
</bean>
请求方法改变:return “redirect:/views/success.jsp”;
直接跳转(不通过控制器):< mvc:view-controller path=“handle/a” view-name=“success” /> < mvc:annotation-driven> mvc:annotation-driven>
静态资源访问:(MVC交给Servlet处理)加入配置:
<!--该注解会让springmvc:接收一个请求,并且该请求没有对应@requestmapping时,将该请求交给服务器默认的servlet去处理(直接访问)-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<mvc:annotation-driven></mvc:annotation-driven>
类型转换:Spring自带一些常见的类型转换器、自定义类型转换器MyConverter(编写自定义类型转换类并引入接口Converter、配置将MyConverter加入到springmvc中、测试转换器)@RequestParam(“name”)是触发转换器的桥梁
格式化:springMVC配置数据格式化注解所依赖的bean+通过注解使用@DateTimeFormat(pattern=“yyyy-MM-dd”)@NumberFormat(parttern="###,#") 、错误消息处理(参数BindingResult result返回前面参数的错误信息,可以放在map里面传递到前端打印)、数据检验:JSR303和Hibernate Validator(jar包+配置(自动加载一个LocalValidatorFactoryBean类)+注解(给校验的对象前增加@Valid))
JSON:@ResponseBod修饰的方法,会将该方法的返回值以一个json数组的形式返回给前台
文件上传:配置MultipartResolver将其加入springIOC容器(可以设置属性)、处理方法中(参数@RequestParam(“file”) MultipartFile file获取前端传过来的文件数据)根据IO方法写输入输出流
拦截器:原理和过滤器原理相同(编写拦截器实现HandlerInterceptor接口、处理请求响应和渲染过程+将自己写的拦截器配置到springmvc中(< mvc:interceptor>))
异常处理:如果一个方法用于处理异常,并且只处理当前类中的异常:@ExceptionHandler({Exception.class});如果一个方法用于处理异常,并且处理所有类中的异常: 类前加@ControllerAdvice、 处理异常的方法前加@ExceptionHandler;自定义异常显示页面@ResponseStatus;
通过配置实现的异常处理:SimpleMappingExceptionResolver
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 如果发生异常,异常对象会被保存在 exceptionAttribute的value值中;并且会放入request域中;异常变量的默认值是exception-->
<!--<property name="exceptionAttribute" value="exception"></property>-->
<property name="exceptionMappings">
<props>
<!-- 相当于catch(ArithmeticException exception){
跳转:error页面 } -->
<prop key="java.lang.ArithmeticException">error</prop>
<prop key="java.lang.NullPointerException">error</prop>
</props>
</property>
</bean>
Mybatis可以简化JDBC操作和实现数据的持久化
ORM:Object Relational Mapping开发人员 像操作对象一样操作数据库表
SqlSessionFactory -> SqlSession ->StudentMapper ->CRUD
配置与使用
引入mybatis-jar包和数据库jar包
配置mybatis
conf.xml:配置数据库信息和需要加载的映射文件(运行环境默认是development、可以通过build的第二参数指定数据库环境)
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!--如果使用的事务方式为jdbc,则需要手工commit提交,即session.commit()-->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
表 - 类
映射文件xxMapper.xml :增删改查标签< select>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog" parameterType="int>
<!--parameterType:输入参数的类型,resultType:返回类型、输入参数parameterType 和输出参数resultType,在形式上都只能有一个、如果输入参数:是简单类型(8个基本类型+String)是可以使用任何占位符,#{
xxxx}、如果是对象类型,则必须是对象的属性#{
属性名}-->
select * from Blog where id = #{
id}
</select>
</mapper>
测试类
session.selectOne(“需要查询的SQL的namespace.id”,“SQL的参数值”)
public static void main(String[] args) throws IOException {
//加载MyBatis配置文件(为了访问数据库)
Reader reader = Resources.getResourceAsReader("conf.xml") ;
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader) ;
//session - connection
SqlSession session = sessionFactory.openSession() ;
String statement = "org.lanqiao.entity.personMapper.queryPersonById" ;
Student person = session.selectOne( statement,1 ) ;
System.out.println(person);
session.close();
mapper动态代理方式CRUD:省略掉statement,即根据约定直接可以定位出SQL语句
配置环境:mybatis.jar/ojdbc.jar、conf.xml、mapper.xml
新建类和方法实现接口必须遵循以下约定:
1.方法名和mapper.xml文件中标签的id值相同
2.方法的输入参数和mapper.xml文件中标签的parameterType类型一致 (如果mapper.xml的标签中没有parameterType,则说明方法没有输入参数)
3.方法的返回值和mapper.xml文件中标签的resultType类型一致(无论查询结果是一个还是多个(student、List< Student>),在mapper.xml标签中的resultType中只写 一个(Student);如果没有resultType,则说明方法的返回值为void)
4.namespace的值就是接口的全类名( 接口 - mapper.xml 一 一对应)
5.测试中使用
T t = session.getMapper(接口.class) ;
返回类 返回值 = t.接口中的方法(参数) ;//接口中的方法->SQL语句
StudentMapper studentMapper = session.getMapper(StudentMapper.class) ;
studentMapper.方法();
6.优化:将配置信息单独放入db.properties文件中然后再动态引入、MyBatis全局参数在conf.xml中设置、设置别名
类型转换器(自定义):实现java类型和jdbc类型的相互转化
1.创建转换器:实现TypeHandler接口或者继承BaseTypeHandler
2.配置conf.xml< typeHandlers>和mapper.xml与类对应(resultMap可以实现类型转换和属性-字段的映射关系)
输入参数:parameterType(简单类型:8个基本类型+String、.对象类型)、取值方法(#{}、${}都可以获取对象值和嵌套类型对象)(不同之处:简单类型的标识符、#{}会给String类型加上单引号、#{}可以防止sql注入)、参数类型为HashMap(用map中key的值匹配占位符#{stuAge},如果匹配成功就用map的value替换占位符)、参数为多个数据(可以使用[arg3, arg2, arg1, arg0, param3, param4, param1, param2]、在接口中通过@Param(“sNo”) 指定sql中参数的名字)
输出参数:resultType、resultMap(实体类的属性、数据表的字段: 类型、名字不同时、除此之外:实体类属性和数据字段不匹配时可以使用resultType+HashMap)、(输出类型为简单类型、对象类型、集合类型(resultType依然写集合的元素类型)、hashmap类型(本身是一个集合,可以存放多个元素))
输出参数为Hashmap
//根据@MapKey("stuNo")知道 Map的key是stuNo
@MapKey("STUNO") //oracle的元数据(字段名、表名 )都是大写
HashMap<Integer,Student> queryStudentsByHashMap();
//程序根据select的返回值 知道map的value就是 Student ,
<select id="queryStudentsByHashMap" resultType="HashMap">
select stuNo ,stuName ,stuAge from student
</select>
储存过程:数据库新建储存过程、Mapper中使用CALL调用存储过程(通过statementType="CALLABLE"设置SQL的执行方式是存储过程、存储过程的输入参数需要通过HashMap来指定)、使用过程(通过hashmap的put方法传入输入参数的值、通过hashmap的Get方法获取输出参数的值。)
动态sql语句:where-if(只能处理第一个有效的and)
<select id="queryStuByNOrAWishSQLTag" parameterType="student" resultType="student" >
select stuno,stuname,stuage from student
<where>
<!-- <if test="student有stuname属性 且不为null"> -->
<if test="stuName !=null and stuName!='' ">
and stuname = #{
stuName}
</if>
<if test="stuAge !=null and stuAge!=0 ">
and stuage = #{
stuAge}
</if>
</where>
</select>
foreach:< foreach>迭代的类型:数组、对象数组、集合、属性(包括属性类)、(简单类型的数组:在mapper.xml中必须用array代替该数组、集合类型的数组:必须用list代替该集合、对象数组:必须用object代替该集合、使用时用对象.属性)
<select id="queryStudentsWithNosInGrade" parameterType="grade" resultType="student">
select * from student
<where>
<if test="stuNos!=null and stuNos.size>0">
<foreach collection="stuNos" open=" and stuno in (" close=")"
item="stuNo" separator=",">
#{
stuNo}
<!--此时stuNo为对象的属性,本身是一个集合-->
</foreach>
</if>
</where>
</select>
refid:(提取并引用sql语句)
trim:增删改中有效使用
//添加where并处理拼接sql中开头或结尾的第一个和最后一个and
<trim prefix="where" prefixOverrides="and" suffixOverrides="and">
关联查询:一对一(业务扩展类核心:用resultType指定类的属性包含多表查询的所有字段、resultMap:通过属性成员建立起对应关系,对象成员使用 association映射、javaType指定该属性的类型(一对一:association,一对多:collection))一对多:resultMap:通过属性成员建立起对应关系,对象成员使用 collection映射、ofType指定该属性中元素的类型
日志:通过日志信息,详细的阅读mybatis执行情况
log4j.jar包、开启日志conf.xml、编写配置日志输出文件log4j.properties
<settings>
<!-- 开启日志,并指定使用的具体日志 -->
<setting name="logImpl" value="LOG4J"/>
</settings>
延迟加载:实现部分查找和懒加载
开启延迟加载conf.xml、配置mapper.xml(查询对象的sql是通过select属性指定的关联mapper,并且通过column指定外键名)、如果增加了mapper.xml,要修改conf.xml配置文件(将新增的mapper.xml加载进去)
<settings>
<!-- 开启延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 关闭立即加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
查询缓存:
一级缓存:MyBatis默认开启一级缓存,如果用同样SqlSession对象查询相同的数据,则只会在第一次查询时向数据库发送SQL语句,并将查询的结果 放入到SQLSESSION中(作为缓存在);后续再次查询该同样的对象时,则直接从缓存中查询该对象即可(即省略了数据库的访问)、commit语句会清理数据库缓存
二级缓存:只要产生的Mapper对象来自于同一namespace,则这些对象共享二级缓存
conf.xml中配置二级缓存< setting name=“cacheEnabled” value=“true”/>
mapper.xml中声明开启 < cache/>
Mapper的对应类、对应类的父类和级联属性都要需要实现序列化接口Serializable
触发将对象写入二级缓存的时机为SqlSession对象的close()方法
禁用二级缓存:select标签中 useCache=“false”
清理二级缓存:select标签中 flushCache="true"或者 其他操作的commit(),不能用查询的commit();
ehcache二级缓存整合:jar包、编写ehcache配置文件 Ehcache.xml、Mapper.xml中开启
<cache type="org.mybatis.caches.ehcache.EhcacheCache">
<property name="maxElementsInMemory" value="2000"/>
<property name="maxElementsOnDisk" value="3000"/>
</cache>
逆向工程:表、类、接口、mapper.xml四者密切相关,根据表生成其他三个
jar包:mybatis-generator-core.jar、mybatis.jar、ojdbc.jar
逆向工程的配置文件generator.xml
执行
public static void main(String[] args) throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException {
//配置文件
File file = new File("src/generator.xml") ;
List<String> warnings = new ArrayList<>();
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(file);
DefaultShellCallback callBack = new DefaultShellCallback(true);
//逆向工程的核心类
MyBatisGenerator generator = new MyBatisGenerator(config, callBack,warnings );
generator.generate(null);
}
增加conf.xml和db.properties文件
使用query by CriteriaQBC
数据库版本切换
conf.xml切换environment并配置Provider别名
<!-- 配置数据库支持类-->
<databaseIdProvider type="DB_VENDOR">
<property name="MySQL" value="mysql" />
<property name="Oracle" value="oracle" />
</databaseIdProvider>
mapper.xml写不同数据SQL语句,配置databaseId=“Provider别名”
<select id="queryStudentByNoWithONGL" parameterType="student" resultType="student" databaseId="oracle">
注解方式
将sql语句写在接口的方法上@Select("")
将接口的全类名写入< mapper>,或者批量写入
<mappers>
<!--以下可以将com.yanqun.mapper 包中的注解接口和xml全部一次性引入 -->
<package name="com.yanqun.mapper" />
</mappers>
增删改返回值可以是void、Integer、Long、Boolean,都不需要在mapper.xml中设置返回值类型
事务提交
//手动提交:
sessionFactory.openSession();
session.commit();
//自动提交:每个dml语句 自动提交
sessionFactory.openSession(true);
自增语句
//mysql设置自增数据为Integer类型的null,设置返回的自增数据,实现回写
useGeneratedKeys="true" keyProperty="number"
//oracle通过序列模拟实现(before和after方式)
鉴别器 : 对查询结果进行分支处理: 如果是a年级则真名,如果b年级显示昵称,由于字段不一致需要在resultMap中写
<discriminator javaType="string" column="gname">
<case value="a" resultType="com.yanqun.entity.Student" >
<result column="sname" property="stuName"/>
</case>
<case value="b" resultType="student">
<result column="nickname" property="stuName"/>
</case>
</discriminator>
架构分析
接口层:广义接口(增删改查)
数据处理层:参数处理,sql解析与执行,处理结果
框架支撑层:事务管理,缓存机制,连接池管理
引导层:XML配置,注解方式
源码分析
获取SqlSessionFactory对象
(通过parseConfiguration()在configuration标签设置了properties、settings、environments等属性标签)(所有的配置信息放在Configuration对象中)(解析所有的Mapper.xml文件(分析其中的增删改查标签)成MappedStatement对象并放在Configuration中)(SqlSessionFactory对象 ->DefaultSqlSessionFactory ->Configuration ->包含了一切配置信息)
获取SqlSession对象
(根据不同的类型execType,产生不同的 Executorconfiguration.newExecutor(tx, execType) ->SimpleExecutor、通过装饰模式将刚才产生的executor包装成一个更加强大的executor:executor = (Executor) interceptorChain.pluginAll(executor)、返回DefaultSqlSession(configuration,executor,事务))
(SqlSession ->openSession()->openSessionFromDataSource()->DefaultSqlSession对象->执行SQL)
获取XxxMapper对象
(代理接口中的方法、mapper.xml中的< select>等标签)(SqlSession(configuration,executor,事务)、代理接口的对象(MapperInterface)、methodCache(存放查询缓存,底层是CurrentHashMap))
执行< select>等标签中定义的SQL语句
(MyBatis底层在执行CRUD时 可能会涉及到四个处理器:处理对象ParameterHandler的处理器:StatementHandler、处理参数的处理器:ParameterHandler、类转化器处理器:TypeHandler、处理结果集的处理器:ResultSetHandler)(动态代理:MapperProxy对象、执行增删改查->MapperProxy/invoke()–>InvocationHandler :JDK动态代理接口)(实际调用增删改查的方法:mapperMethod.execute(sqlSession,args) )(处理增删改查方法的参数:method.convertArgsToSqlCommandParam(args))(boundSql :将我们写的SQL和参数值进行了拼接后的对象,即最终能被真正执行的SQL)(通过Executor执行sql语句、底层执行方法:PreparedStatement的execute())
自定义插件
四大核心对象:都涉及到了拦截器用于增强并且包含了该增强操作
StatementHandler、ParameterHandler、ResultSetHandler、Executor
步骤
编写拦截器
//目標方法target
Object target = invocation.getTarget();
//目标对象target的包装后的产物MetaObject
MetaObject metaObject = SystemMetaObject.forObject(target);
//metaObject.getValue获取参数
Object value = metaObject.getValue("parameterHandler.parameterObject");
//metaObject.setValue设置参数
metaObject.setValue("parameterHandler.parameterObject",2);
//放行
Object proceed = invocation.proceed();
return proceed;
编写签名注解
@Intercepts({
//@Signature(type = StatementHandler.class , method ="query",args = {Statement.class, ResultHandler.class})
@Signature(type = StatementHandler.class , method ="parameterize",args = {
Statement.class})
})
conf.xml配置
<plugins>
<plugin interceptor="com.yanqun.my.interceptors.MyInterceptor">
<property name="name" value="zs"/>
<property name="age" value="23"/>
</plugin>
</plugins>
批量操作:预编译一次sessionFactory.openSession(ExecutorType.BATCH)、不推荐拼接SQL方式
分页插件:PageHelper
引入jar(jsqlparser-0.9.5.jar、pagehelper-5.1.8.jar)
配置conf.xml插件
执行PageHelper.startPage(当前页, 每页数据)
使用页面信息(PageInfo、Page对象)
插件:Mybatis-Plus、通用Mapper
Maven是一个基于Java平台的自动化构建工具–将java、js、jsp等各个文件进行筛选、组装,变成一个可以直接发布的项目
http://www.mvnrepository.com
清理:删除编译的结果,为重新编译做准备
编译:java->class
测试:针对于项目中的关键点进行测试,亦可用项目中的测试代码去测试开发代码;
报告:将测试的结果进行显示
打包:将项目中包含的多个文件 压缩成一个文件, 用于安装或部署:(java项目-jar、web项目-war)
安装:将打成的包放到本地仓库,供其他项目使用
部署:将打成的包放到服务器上准备运行
下载配置maven
使用maven
mvn compile 只编译main目录中的java文件
mvn test 测试
mvn package 打成jar/war
mvn install 将开发的模块放入本地仓库供其他模块使用(放入的位置是通过gav决定)
mvn clean 删除target目录(删除编译文件的目录)
运行mvn命令必须在pom.xml文件所在目录
目录结构
-src
--main 程序功能代码
--java java代码
--resources 资源代码、配置代码
--test 测试代码
--java
--resources
pom.xml 项目对象模型
POM(项目对象模型):Maven工程的基本工作单元XML文件,包含了项目的基本信息,用于描述项目如何构建,声明项目依赖
<groupId>域名翻转.项目名</groupId>
<groupId>org.lanqiao.maven</groupId>
<artifactId>子模块名</artifactId>
<artifactId>HelloWorld</artifactId>
<version>版本号</version>
<version>0.0.1-SNAPSHOT</version>
依赖
在maven项目中如果要使用一个当时不存在的Jar或模块,则可以通过依赖实现(例如依赖测试类)
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
依赖排除:
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
</exclusions>
依赖关联:
A.jar->B.jar->C.jar
要使 A.jar ->C.jar:当且仅当 B.jar依赖于C.jar的范围是compile
依赖原则:路径最短原则(防止冲突)
路径相同距离:同一个pom文件后覆盖前、不同pom文件前覆盖后
统一编号和版本:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<xx>版本号</xx>
</properties>
//使用动态版本
<version>${
xx} </version>
生命周期
clean lifecycle :清理 pre-clean、clean、post-clearn
default lifecycle :默认(常用)
site lifecycle:站点 pre-site、site、post-site site-deploy
继承
父->子工程,可以通过父工程 统一管理依赖的版本
父工程pom方式打包
在父工程pom中编写依赖
<dependencyManagement>
<dependencies>
<dependency>
给当前工程继承父工程
<parent>
<!-- 1加入父工程坐标gav -->
<groupId>org.lanqiao.maven</groupId>
<artifactId>B</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 2当前工程的Pom.xml到父工程的Pom.xml之间的相对路径 -->
<relativePath>../B/pom.xml</relativePath>
</parent>
在子类中需要声明使用哪些父类的依赖
<dependency>
<!-- 声明:需要使用到父类的junit(只需要ga) -->
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
聚和
聚合可以将拆分的多个子工程合起来共同操作(前置关联工程的install操作)
新建总工程中配置:只能配置在打包为pom方式的maven中
<modules>
<!--项目的根路径 -->
<module>../Maven1</module>
<module>../Maven2</module>
</modules>
配置完聚合之后,操作总工程会自动操作改聚合中配置过的工程
部署Web
新建Maven项目并打war包
pom中配置servlet-api
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
补全路径名:webapp->WEB-INF->web.xml
实际开发中开发人员将自己的项目开发完毕后打成war包(package) 交给实施人员去部署
springboot可以快速开发微服务模块,springboot将各个应用/三方框架设置成了一个个“场景”starthttps://spring.io可以自动生成SpringBoot的文件项目
准备JAVA和MAVEN的环境、实现springboot开发工具、目录结构resources(static:静态资源(js css 图片 音频 视频)
、templates:模板文件(模版引擎freemarker ,thymeleaf;默认不支持jsp)、application.properties: 配置文件对端口号等服务端信息进行配置)
注解:
@SpringBootApplication:springboot的主配置类
@Configuration:表示“配置类”:该类是一个配置类 、自动纳入Spring容器(@Component)
@EnableAutoConfiguration:使spring boot可以自动配置:spring boot在启动时,就会将该包及所有的子包全部纳入spring容器,会根据META-INF/spring.factories找到相应的三方依赖,并将这些依赖引入本项目、Xxx_AutoConfiguration会实现自动装配并给予默认值
@SpringBootConfiguration:自己代码的自动配置
@ConditionalOnXxx:当这些条件都满足时此配置自动装配生效(手工修改改 自动装配:XxxProperties文件中的prefix.属性名=value )
配置文件:
application.properties : k=v,或行内写法(k: v,[Set/List/数组] {map,对象类型的属性},并且 []可省,{}不能省)
application.yml:k:空格v、通过垂直对齐指定层次关系、默认可以不写引号 (双引号会将其中的转义符进行转义)
@Component:将此类型加入Javabean
@ConfigurationProperties(prefix=“student”):根据前缀名实现该类型自动装配,同yml文件相匹配
@Autowired:自动装配从bean中取值
@Value(""):实现单个值注入,可以和全局配置文件实现互补
@Validated:开启jsr303数据校验的注解
@Test:此类型为测试类
@ImportResource(locations={“classpath:spring.xml”}):识别spring.xml配置文件
@bean:通过实现注解配置将此类型加入到bean中
@ConfigurationProperties | @Value | |
---|---|---|
注值 | 批量注入 | 单个 |
松散语法 | 支持 | 不支持 |
SpEL | 不支持 | 支持 |
JSR303数据校验 | 支持 | 不支持 |
注入复杂类型 | 支持 | 不支持 |
多环境切换:配置环境切换和动态环境切换
配置文件的位置:properties的优先级要大于yml
外部文件和外部参数:Run configuration ,argumenets方式和命令控制行
日志:spring boot默认选用slf4j和logback、日志级别、日志信息格式、日志输出路径
Web静态资源:静态资源的存放路径通过WebMvcAutoConfiguration类-addResourceHandlers()指定:/webjars/成静态资源存放目录: {“classpath:/META-INF/resources/”,“classpath:/resources/”,“classpath:/static/”,“classpath:/public/”}以上目录存放资源文件后,访问时不需要加前缀、欢迎页(任意一个静态资源目录中的Index.html)、Logo(任意一个静态资源目录中的favicon.ico)、自定义静态资源存放路径(spring.resources.static-locations=…)
Web动态资源:默认不支持jsp、html等,但是推荐使用模板引擎thymeleaf(网页=模板+数据)
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
使用thymeleaf只需要将文件放入目录:“classpath:/templates/”; 文件的后缀: “.html”;
thymeleaf的th指定方式和符号取值方式(usingthymeleaf文档)
RPC(Remote Procedure Call):远程过程调用
SOA(Service-Oriented Architecture):面向服务架构
Dubbo中控制器和服务端分离
步骤:提供方服务器运行提供方提供的服务、注册中心发布服务、消费方订阅服务、注册中心推送服务、消费方向提供方调用服务
开发dubbo程序:准备环境(linux环境中的jdk及其环境变量和zookeeper)、服务方(引入依赖:pom.xml、接口及实现类@Service、补全WEB-INF/web.xml、配置spring:applicationContext.xml)、消费方(引入依赖:pom.xml改端口号、补全WEB-INF/web.xml、配置springmvc、编写控制器代码@Reference:用于访问服务方提供的服务代码)、监听器(下载incubator-dubbo-ops、打包war、在linux中的tomcat中运行)
quartz:定时执行、异步任务
任务:Job、触发器:定义时间、调度器:将任务和触发器 一一对应
步骤
引入jar包
新建类制定具体任务
新建类任务调用的实现继承Job接口并执行具体任务
public class PlanJob implements Job {
MeetingService meetingService = new MeetingService();
//jobExecutionContext可以获取设置的各种参数值
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
TriggerKey triggerkey =
jobExecutionContext.getTrigger().getKey();
JobKey jobKey = jobExecutionContext.getJobDetail().getKey();
System.out.println("----");
System.out.println(triggerkey+"\n"+jobKey);
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
List<String> infos = (List<String>)jobDataMap.get("infos");
System.out.println(infos);
//存放 计划执行的任务...
meetingService.calClassMeeting();
}
}
新建测试方法类(产生)
public class TestQuartz {
//XxxBuilder ->withIdentity()-->Xxx
public static void main(String[] args) throws SchedulerException, InterruptedException, ParseException {
// PlanJob
JobBuilder jobBuilder = JobBuilder.newJob(PlanJob.class);//PlanJob PlanJob PlanJob
//产生实际使用的Job
JobDetail jobDetail = jobBuilder.withIdentity("meeting Job", "group1").build();
//向Job的execute()中传入一些参数。。。
// JobDatMap
JobDataMap jobDataMap = jobDetail.getJobDataMap();
List<String> names = Arrays.asList(new String[]{
"zs","ls","ww"});
jobDataMap.put("infos",names);
// 触发器(Trigger):时间规则 ,依赖2个对象(TriggerBuilder ,Scheduel)
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
triggerBuilder = triggerBuilder.withIdentity("meeting trigger", "group1");
triggerBuilder.startNow();//当满足条件时 立刻执行
// 2019-03-13 09:46:30 -- // 2019-03-13 09:46:45
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date start = sdf.parse("2019-03-13 09:46:30");
Date end = sdf.parse("2019-03-13 09:46:45");
// triggerBuilder.startAt(start);
// triggerBuilder.endAt(end);
//scheduelBuilder:定执行的周期(时机)
// SimpleScheduleBuilder scheduelBuilder = SimpleScheduleBuilder.simpleSchedule();
// scheduelBuilder.withIntervalInSeconds(1) ;//每隔1秒执行一次
// scheduelBuilder.withRepeatCount(3) ;//重复执行3次
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("5,10,15,30,45 * * * * ? *");
//产生触发器
// SimpleTrigger trigger = triggerBuilder.withSchedule(ScheduleBuilder).build();
CronTrigger trigger = triggerBuilder.withSchedule(cronScheduleBuilder).build();
// 调度器(工厂产生调度器)
SchedulerFactory secheduleFacotry = new StdSchedulerFactory();
//产生调度器
Scheduler scheduler = secheduleFacotry.getScheduler();
//通过调度器 将 任务 和 触发器一一对应
scheduler.scheduleJob(jobDetail,trigger) ;
scheduler.start();
// scheduler.shutdown(true);
}
}
引入jar包
配置类-表对应
配置Spring配置文件(applicationContext.xml)
<!-- 加载db.properties文件 -->
<bean id="config" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
<property name="locations">
<array><value>classpath:db.properties</value></array>
</property>
</bean>
<!-- 引入service层的bean -->
<bean id="studentService" class="org.lanqiao.service.impl.StudentServiceImpl">
<property name="studentMapper" ref="studentMapper"></property>
</bean>
<!-- 配置配置数据库信息(替代mybatis的配置文件conf.xml) -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
</bean>
<!-- 在SpringIoc容器中 创建MyBatis的核心类 SqlSesionFactory -->
<bean id="sqlSessionFacotry" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<!-- 加载mapper.xml路径 -->
<property name="mapperLocations" value="org/lanqiao/mapper/*.xml"></property>
</bean>
配置mapper中的sql语句
使用Spring-MyBatis整合产物开发程序
<bean id="studentMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="org.lanqiao.mapper.StudentMapper"></property>
<property name="sqlSessionFactory" ref="sqlSessionFacotry"></property>
</bean>
<!--Mapper对在SpringIOC中的id默认就是首字母小写接口名,service在ref对象要首字母小写-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFacotry"></property>
<!--指定批量产生 哪个包中的mapper对象-->
<property name="basePackage" value="org.lanqiao.mapper"></property>
</bean>
使用:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
context.getBean("bean") ;
引入jar包
配置类-表对应
配置Spring配置文件(applicationContext.xml):使用Spring整合MyBatis
编写springmvc配置文件:视图解析器、基础配置
配置mapper中的sql语句
配置Web配置文件
<!-- Web项目中,引入Spring -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 整合SPringMVC -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-controller.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
新建boot项目war包
建立基本的web项目所需要的目录结构
webapps/WEB-INF(需要)
webapps/WEB-INF/web.xml (不需要)
webapps/index.jsp
创建tomcat实例并部署项目:如果是一个war包的spring boot项目,在启动服务器tomcat时,会自动调用ServletInitializer类中的configure方法,configure方法会调用spring boot的主配置类从而启动spring boot
创建父工程(引入公共依赖、实体类POJO依赖、module子模块依赖、解决Maven内置tomcat打包不引入xml问题的代码)
创建实体类(实体类需要implements Serializable接口)
创建公共模块实现接口共用(引入实体类POJO依赖、提供公共接口)
创建dao层(映射文件mapper、动态代理接口mapper、spring文件application(加载db文件、配置数据库信息、创建核心类sqlsessionfactory)、将核心类交给spring处理)
创建service层(补全WEB-INF/web.xml并拦截交给spring处理、pom依赖父工程+dao层+公共接口+tomcat代码、编写spring的application文件并顺带启动dao层spring的application、service的具体实现类)
创建显示web层(补全WEB-INF/web.xml并拦截交给springMVC处理、pom依赖父工程+公共接口+tomcat代码、编写控制器、配置sppringMVC)
其他:
在maven中引入一个 mvn中央仓库中不存在的Jar:将jar自己安装到本地mvn仓库:cmd命令(ojdbc7.jar为例):mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc7 -Dversion=10.2.0.5.0 -Dpackaging=jar -Dfile=f:\ojdbc7.jar
解决Maven内置tomcat打包不引入xml问题:
# 在父工程pom.xml的元素中加入
>
>
>
>src/main/java >
>
>**/*.xml >
>
>false >
>
>
>src/main/resources >
>
>
>
建立java文件并引入jar包
指定连接 Redis 服务器的相关信息redis.properties(实现分配连接池和线程)
在spring的applicationContext配置文件中配置连接池、连接工厂和操作模板,并把RedisUtil加入bean中
使用工具类和测试类进行Redis的访问和检测
引入jar包
创建实体类封装Job信息
创建实体类调用的具体方法
创建测试方法初始化容器和开始执行
创建配置文件applicationContext.xml
<!--配置任务信息-->
<bean id="scheduleJobEntity" class="com.yanqun.entity.ScheduleJob" >
<property name="jobId" value="j001"></property>
<property name="jobName" value="任务1"></property>
<property name="jobGroup" value="任务组1"></property>
<property name="jobStatus" value="1"></property>
<property name="cronExpression" value="5,10,30,50 * * * * ? *"></property>
<property name="desc" value="描述..."></property>
</bean>
<!--配置job类信息-->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" >
<property name="jobClass" value="com.yanqun.job.PlanJob"></property>
<property name="jobDataAsMap">
<map>
<entry key="scheduleJob">
<ref bean="scheduleJobEntity"></ref>
</entry>
</map>
</property>
</bean>
<!-- cronTrigger触发器:定义时间规则
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="jobDetail" >
</property>
<property name="cronExpression" value="#{scheduleJobEntity.cronExpression}">
</property>
</bean>-->
<!--SimpleTrigger触发器-->
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean" >
<property name="repeatInterval" value="2000"></property>
<property name="repeatCount" value="10"></property>
<property name="startDelay" value="3"></property>
<property name="jobDetail" ref="jobDetail" ></property>
</bean>
<!--配置调度器-->
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="simpleTrigger" />
</list>
</property>
</bean>