1.什么是Spring?
Spring是一个开源的分层的javaSE/javaEE一站式的容器的轻量级的,解决业务逻辑层【Service】与web层和数据访问层之间的松耦合问题的容器框架。
2.Spring的结构组成
从下往上test,core容器,aop【面向切面编程】,web,data access
1.test部分只有一个模块:
spring-test:spring测试,提供junit与mock测试功能
spring-context-support:spring额外支持包,比如邮件服务、视图解析等
它们的依赖关系
2.core部分包含4个模块
spring-core:依赖注入IoC与DI的最基本实现
spring-beans:Bean工厂与bean的装配
spring-context:spring的context上下文即IoC容器
spring-expression:spring表达式语言
它们的完整依赖关系
3.aop部分包含4个模块
spring-aop:面向切面编程
spring-aspects:集成AspectJ
spring-instrument:提供一些类级的工具支持和ClassLoader级的实现,用于服务器spring-instrument-tomcat:针对tomcat的instrument实现
它们的依赖关系
4.web部分包含4个模块
spring-web:基础web功能,如文件上传
spring-webmvc:mvc实现
spring-webmvc-portlet:基于portlet的mvc实现
spring-struts:与struts的集成,不推荐,spring4不再提供
它们的依赖关系
5.data access部分包含5个模块
spring-jdbc:jdbc的支持
spring-tx:事务控制
spring-orm:对象关系映射,集成orm框架
spring-oxm:对象xml映射
spring-jms:java消息服务
它们的依赖关系
3.Spring的优点
1.方便解耦,简化开发:Spring是一个超级工厂(超级容器),可以将对象的创建和依赖关系交给Spring工厂去管理
2.AOP编程:Spring提供面向切面编程,可以方便的对程序进行运行监控、权限验证等操作
3.声明事务:只需要通过配置就可以完成对事务的管理,不需要手动编程
4.方便测试:Spring支持junit4,可以通过Spring注解方式测试程序
5.方便集成各种框架:Spring支持各种开源框架的集成。例如(struts、Hibernate、MyBaties等)
6.降低JavaEE API的使用难度: Spring对JavaEE开发中非常难用的API进行封装,使这些开发API应用难度降低。
4.Spring的核心技术
1.IoC(Inverse of Control 反转控制):将java对象创建和维护权利交由Spring工厂进行管理和维护。
2.DI(依赖注入):将某一个java类中的依赖对象快速的添加到另一个java类中。
3.AOP(Aspect Oriented Programming 面向切面编程),基于动态代理的功能增强方式[给自己的程序中添加一些系统需求的处理【日志管理,数据的安全性检查.....】]。
4.事务管理的相关操作。
5.Spring整合/管理其他各层的框架【Spring集成web层SpringMVC/Spring整合数据访问层MyBatis】{SSM}
5.Spring的IoC(Inverse of Control 反转控制)
IoC(Inverse of Control 反转控制): 将java对象创建和维护权利交由Spring工厂进行管理和维护。
1.通过在Spring的配置文件中通过<bean>元素配置由Spring工厂所要创建的java对象。
2.如何从Sprign工厂所创建的众多对象中得到自己需要使用的java对象?
答案:首先得到Spring工厂对象,然后通过这个工厂对象提供的方法getBean(“”)将自己需要的对象得到。
3.Spring工厂对象有那些,如何创建Spring工厂对象,在创建Spring工厂对象的时候需要什么?
1.BeanFactory接口----Spring工厂对象
2.ApplicationContex接口------Spring工厂对象
ApplicationContext接口这个Spring工厂对象是BeanFactory接口的子接口
6.Bean实例化4种方式
无参数构造方法(开发最常用)
package com.click369.javabean;
public class StudentBean {
private int stuid;
private String stuname;
private int stuage;
public StudentBean(){}
.............
}
编写Spring的配置文件:【applicationContext.xml/自己起名】{src/main/resources}
<!-- 无参数构造方法实例化bean -->
<!-- id:对象名称 -->
<!-- class:被创建对象的java类的包名+类名 -->
<bean id="stu" class="com.click369.javabean.StudentBean"></bean>
测试
//创建Spring工厂对象
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
//通过getBean方法从Spring工厂对象中得到需要的java类对象
StudentBean stu= (StudentBean)applicationContext.getBean("stu");
//使用由Spring工厂对象实例化好的java对象
stu.setStuid(1001);
stu.setStuname("lisi");
stu.setStuage(24);
System.out.println("stu=="+stu.toString());
静态工厂方法实例化bean
静态工厂方法:在一个类中书写静态的方法,这个方法返回某个Bean的对象(在方法中创建Bean的对象)
package com.click369.javabean;
public class StudentBean {
private int stuid;
private String stuname;
private int stuage;
public StudentBean(){}
.............
}
创建一个静态工厂方法类,提供一个静态方法,让这个静态方法返回一个实体类的对象
package com.click369.javabean;
/**
* 静态工厂方法类
* @author Administrator
*
*/
public class StaticFactoryMethodClass {
/**
* 静态方法,让这个静态方法返回一个实体类的对象
* @return
*/
public static StudentBean getStaticStudentBean(){
return new StudentBean();
}
}
编写Spring配置
<!-- 静态工厂方法实例化bean的配置 -->
<!-- id:对象名称 -->
<!-- factory-method:配置静态工厂方法 -->
<!-- class:配置静态工厂方法类【包名+类名】 -->
<bean id="student" factory-method="getStaticStudentBean" class="com.click369.javabean.StaticFactoryMethodClass"></bean>
测试代码:
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu= applicationContext.getBean(StudentBean.class);
stu.setStuid(1002);
stu.setStuname("wangwu");
stu.setStuage(25);
System.out.println("stu=="+stu.toString())
实例工厂方法实例化bean
package com.click369.javabean;
public class StudentBean {
private int stuid;
private String stuname;
private int stuage;
public StudentBean(){}
.............
}
创建一个工厂类,提供实例方法,这个实例方法返回java实体类的对象
package com.click369.javabean;
/**
* 工厂类
* @author Administrator
*
*/
public class StudentFactory {
/**
* 实例方法,返回实体类对象
* @return
*/
public StudentBean getStudentBean(){
return new StudentBean();
}
}
Spring配置文件的编写:
<!-- 实例工程方法实例化bean的配置 -->
<!-- 创建实例工厂类对象 -->
<bean id="studentFactory" class="com.click369.javabean.StudentFactory"></bean>
<!-- 配置得到实体类对象 -->
<!-- id:对象名称 -->
<!-- factory-bean:实例工厂类对象 -->
<!-- factory-method:实例工厂类中创建实体类的方法 -->
<bean id="student" factory-bean="studentFactory" factory-method="getStudentBean"></bean>
测试:
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu= applicationContext.getBean(StudentBean.class);
stu.setStuid(1002);
stu.setStuname("wangwu");
stu.setStuage(25);
System.out.println("stu=="+stu.toString());
FactoryBean接口方式实例化bean
FactoryBean是Spring提供的接口,专门用于对bean进行初始化操作的。
如果bean需要使用这种方式进行初始化,那么需要定义类实现这个FactoryBean接口,在实现类中复写getObject的方法。
package com.click369.javabean;
public class StudentBean {
private int stuid;
private String stuname;
private int stuage;
public StudentBean(){}
.............
}
创建一个类,实现FactoryBean接口,重写getObject的方法,返回实体类对象。
package com.click369.factory;
import org.springframework.beans.factory.FactoryBean;
import com.click369.javabean.StudentBean;
public class CreateObject implements FactoryBean<StudentBean>{
@Override
public StudentBean getObject() throws Exception {
return new StudentBean();
}
@Override
public Class<?> getObjectType() {
return StudentBean.class;
}
}
Spring配置文件:
<!-- FactoryBean实例化Bean的配置 -->
<!-- id:对象名称 -->
<!-- class:实现FactoryBean接口的java类的包名+类名 -->
<bean id="student" class="com.click369.factory.CreateObject"></bean>
测试:
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.click369.javabean.StudentBean;
public class TestMain {
public static void main(String[] args) {
ApplicationContext ac1=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu=ac1.getBean(StudentBean.class);
stu.setStuid(1001);
stu.setStuname("zhangsan");
stu.setStuage(23);
stu.setStuaddress("西安");
System.out.println(stu.toString());
}
}
7.FactoryBean接口与BeanFactory接口的区别
共同点:都是接口。
不同点:FactoryBean是Spring提供的专门用来实例化java类的接口。【创造】
BeanFactory接口表示一个Spring工厂对象【Spring容器对象】,包含了实例化好的java类对象。【管理】
BeanFactory接口有一个常用的子接口ApplicationContext接口,我们通常使用ApplicationContext接口充当Spring工厂对象【Spring容器对象】。
8.bean的作用域
bean的作用域:主要是指Spring创建的Bean对象是单例、多例、request、session级别。
有点像JSP动作元素useBean的page/request/session/application.
singleton: 单例模式【在一个spring容器中,对象只有一个实例。(默认值)】
prototype:多例模式/原型模式【在一个spring容器中,存在多个实例,每次getBean 返回一个新的实例。】
request:该属性仅对HTTP请求产生作用,使用该属性定义Bean时,每次HTTP请求都会创建一个新的Bean,适用于WebApplicationContext环境。【一次请求一个对象】
session:该属性仅用于HTTP Session,同一个Session共享一个Bean实例。不同Session使用不同的实例。【同一次回话中的对象都是相同的】
global session:该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个Bean实例。【多个session共享一个对象】
<bean id=”对象名称”
class=”被实例化的javabean类”
scope=”singleton/prototype/request/session/global session”></bean>
1.singleton: 单例模式【在一个spring容器中,对象只有一个实例。(默认值)】
package com.click369.javabean;
public class StudentBean {
private int stuid;
private String stuname;
private int stuage;
public StudentBean(){}
.......
}
<!-- id:对象名称 -->
<!-- class:被创建对象的java类的包名+类名 -->
<!-- scope:设置作用域 -->
<bean id="stu" class="com.click369.javabean.StudentBean" scope="singleton"></bean>
或者
<bean id="stu" class="com.click369.javabean.StudentBean"></bean>
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu1=applicationContext.getBean(StudentBean.class);
StudentBean stu2=applicationContext.getBean(StudentBean.class);
System.out.println("stu1=="+stu1.hashCode());
System.out.println("stu2=="+stu2.hashCode());
prototype:多例模式/原型模式【在一个spring容器中,存在多个实例,每次getBean 返回一个新的实例。】
package com.click369.javabean;
public class StudentBean {
private int stuid;
private String stuname;
private int stuage;
public StudentBean(){}
.......
}
<!-- 无参数构造方法实例化bean的配置 -->
<!-- id:对象名称 -->
<!-- class:被创建对象的java类的包名+类名 -->
<!-- scope:设置作用域 -->
<bean id="stu" class="com.click369.javabean.StudentBean" scope="prototype"></bean>
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu1=applicationContext.getBean(StudentBean.class);
StudentBean stu2=applicationContext.getBean(StudentBean.class);
System.out.println("stu1=="+stu1.hashCode());
System.out.println("stu2=="+stu2.hashCode());
9.bean的生命周期
Spring工厂对象【Spring容器对象】负责创建对象,初始化对象,销毁对象。
也就是说任何一个交给Spring的Bean,它的生命周期统一由Spring容器维护。
测试Bean的创建生命周期:
package com.click369.javabean;
public class StudentBean {
/**
* 测试StudentBean类对象的创建
*/
public StudentBean(){
System.out.println("测试StudentBean类对象的创建");
}
}
<!-- 无参数构造方法实例化bean的配置 -->
<!-- id:对象名称 -->
<!-- class:被创建对象的java类的包名+类名 -->
<bean id="student" class="com.click369.javabean.StudentBean"></bean>
测试:
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
测试初始化:
package com.click369.javabean;
public class StudentBean {
/**
* 测试StudentBean类对象的创建
*/
public StudentBean(){
System.out.println("测试StudentBean类对象的创建");
}
/**
* 测试StudentBean类对象的初始化
*/
public void initStudentBean(){
System.out.println("测试StudentBean类对象的初始化");
}
}
<!-- 无参数构造方法实例化bean的配置 -->
<!-- id:对象名称 -->
<!-- class:被创建对象的java类的包名+类名 -->
<!-- init-method:配置对象的初始化方法 -->
<bean id="student" class="com.click369.javabean.StudentBean" init-method="initStudentBean"></bean>
测试:
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
测试销毁:
Bean的销毁必须满足两个条件:
- bean必须是单例的。
- bean的所在的容器(Spring)必须手动关闭。
package com.click369.javabean;
public class StudentBean {
/**
* 测试StudentBean类对象的创建
*/
public StudentBean(){
System.out.println("测试StudentBean类对象的创建");
}
/**
* 测试StudentBean类对象的初始化
*/
public void initStudentBean(){
System.out.println("测试StudentBean类对象的初始化");
}
/**
* 测试StudentBean类对象的销毁
*/
public void destroyStudentBean(){
System.out.println("测试StudentBean类对象的销毁");
}
}
<!-- 无参数构造方法实例化bean的配置 -->
<!-- id:对象名称 -->
<!-- class:被创建对象的java类的包名+类名 -->
<!-- init-method:配置对象的初始化方法 -->
<!-- destroy-method:配置对象的销毁方法 -->
<bean id="student" class="com.click369.javabean.StudentBean" init-method="initStudentBean" destroy-method="destroyStudentBean"></bean>
测试类:
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu1=(StudentBean)applicationContext.getBean("student");
System.out.println("stu1=="+stu1.hashCode());
//关闭容器
((ClassPathXmlApplicationContext)applicationContext).close();
Bean的生命周期,先创建对象【构造方法执行】,再初始化【自己定义的初始化方法需要通过init-method属性配置】,当关闭容器的时候销毁对象【自己定义的销毁方法需要通过destroy-method属性配置】。
10.Spring的依赖注入是什么?实现方式有几种?每一种如何操作?
依赖注入--在调用者类中将被调用者类的对象,添加到调用者类中这个过程就是依赖注入。
在这个过程中被调用者类的对象就是调用者类的依赖对象。
1.构造方法注入
创建被调用者类
package com.click369.javabean;
/**
* 被调用者类
* @author Administrator
*
*/
public class PersonBean {
public PersonBean(){
System.out.println("PersonBean--被调用者类的构造方法");
}
public void testPerson(){
System.out.println("测试被调用者类");
}
}
调用者类
package com.click369.javabean;
/**
* 调用者类
* @author Administrator
*
*/
public class StudentBean {
//依赖对象
public PersonBean personBean;
public StudentBean(PersonBean personBean){
System.out.println("StudentBean--调用者类的构造方法");
this.personBean=personBean;
}
public void testStudent(){
System.out.println("测试StudentBean类");
personBean.testPerson();
}
}
Spring配置文件
<!-- 创建被调用者类PersonBean -->
<bean id="person" class="com.click369.javabean.PersonBean"></bean>
<!-- 创建调用者类StudentBean -->
<bean id="student" class="com.click369.javabean.StudentBean">
<!-- 构造方法注入 -->
<!-- index:构造方法参数的索引值 -->
<!-- ref:引用对象 -->
<constructor-arg index="0" ref="person"></constructor-arg>
</bean>
测试
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu1=(StudentBean)applicationContext.getBean("student");
stu1.testStudent();
2.Set方法注入
被调用者类:
package com.click369.javabean;
/**
* 被调用者类
* @author Administrator
*
*/
public class PersonBean {
public PersonBean(){
System.out.println("PersonBean--被调用者类的构造方法");
}
public void testPerson(){
System.out.println("测试被调用者类");
}
}
调用者类
package com.click369.javabean;
/**
* 调用者类
* @author Administrator
*
*/
public class StudentBean {
//依赖对象
public PersonBean personBean;
//为依赖对象提供一个set方法
public void setPersonBean(PersonBean personBean) {
this.personBean = personBean;
}
public void testStudent(){
System.out.println("测试StudentBean类");
personBean.testPerson();
}
}
Spring配置文件:
<!-- 创建被调用者类PersonBean -->
<bean id="person" class="com.click369.javabean.PersonBean"></bean>
<!-- 创建调用者类StudentBean -->
<bean id="student" class="com.click369.javabean.StudentBean">
<!-- set方法注入被调用者类 -->
<!-- name:成员变量名称【依赖对象名称】 -->
<!-- ref:引用对象 -->
<property name="personBean" ref="person"></property>
</bean>
测试:
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu1=(StudentBean)applicationContext.getBean("student");
stu1.testStudent();
3.注解
@autowired/@resource
11.Spring的自动装配策略
Spring 提供了某些规则,可以对 bean 进行自动装配。<bean>
的 autowire
属性可以指定自动装配的策略。
策略 | 说明 |
---|---|
byName | 根据名称进行匹配。 |
byType | 根据类型进行匹配。假设 Book 有一个 Author 类型的属性,如果容器中找到 Author 类型的 Bean 时,就会自动把它装配给 Book 的 Author 属性。 |
constructor | 也是根据类型进行匹配,只不过指的是构造函数的情况。假设 Book 有一个构造函数,它有一个 Author 类型的入参;如果容器中找到 Author 类型的 Bean 时,就会自动装配;如果没有找到,则抛出异常。 |
autodetect | 如果 Bean 提供了默认的构造函数,则采用 byType 方式;如果没有,则采用 constructor 方式。 |
<beans>
元素存在 default-autowire 属性,可以设置全局性的自动装配类型;如果为 no,则表示不启用自动装配;还有这些值:byName、byType、constructor 与 autodetect。
在实践中很少在 XML 中开启自动装配功能,而基于注解的配置方式默认采用的是 byType 自动装配策略。
12.autowired和resource的区别
1、共同点
两者都可以写在字段和setter方法上。两者如果都写在字段上,那么就不需要再写setter方法。
2、不同点
(1)@Autowired
@Autowired为Spring提供的注解,需要导入包org.springframework.beans.factory.annotation.Autowired;只按照byType注入
(2)@Resource
@Resource()默认按照ByName自动注入,由J2EE提供,需要导入包javax.annotation.Resource。@Resource有两个重要的属性:name和type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以,如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不制定name也不制定type属性,这时将通过反射机制使用byName自动注入策略。
13.@Component注解
spring注解中@component就是bai说把这个类交给Spring管理,又一次起个名字叫userManager,因为不清楚这个类是dao属于哪个层面,所以就用@Component。
14.什么是AOP?
AOP (Aspect Oriented Programing) 称为:面向切面编程,它是一种编程思想。
AOP 思想: 基于代理思想,对原来目标对象,创建代理对象,在不修改原对象代码情况下,通过代理对象,调用增强功能的代码【系统需求方法】,从而对原有业务方法进行增强。
AOP的底层是动态代理机制【CGLIB动态代理】。
基于两种动态代理机制: JDK动态代理和CGLIB动态代理。
JDK动态代理:基于接口的代理,会生成目标对象的接口的子对象【实现接口的类】
CGLIB动态代理:基于类的代理,会生成目标对象的子对象。【无论是继承父类还是实现接口所产生的类】
15.AOP相关的概念
joinpoint(连接点):指那些被拦截到的点。在spring中指的可以被代理(增强)的方法。【业务类中的业务需求方法】
poingcut(切入点):对哪些连接点进行拦截的定义。在Spring中指的真正需要被代理(增强)的方法。
advice(通知/增强):指拦截到连接点之后要做的事情。真正增强的那些代码(逻辑)。
通知/增强分为:
前置通知,后置通知,异常通知,最终通知,环绕通知。
aspect(切面):是切入点和通知/增强的结合过程。
introduction(引介):一种特殊的通知在不修改类代码的前提下,introduction可以在运行期为类动态地添加一些方法或者字段。
target(目标对象):代码的目标对象。
weaving(织入):把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入。而AspectJ采用编译期织入和类装在期织入。
proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类。
16.基于XML文件的AOP实现
基于XML文件的AOP实现
<aop:config>
<aop:pointcut expression="execution(* com.click369.service.impl.UserServiceImpl.insertService(..))"
id="point1"/>
<aop:pointcut expression="execution(* com.click369.service.impl.UserServiceImpl.updateService(..))"
id="point2"/>
<aop:pointcut expression="execution(* com.click369.service.impl.UserServiceImpl.deleteService(..))"
id="point3"/>
<aop:aspect ref="myAvice">
<aop:before method="savaLog" pointcut-ref="point1"/>
<aop:after-returning method="savaLog" pointcut-ref="point2"/>
<aop:around method="around" pointcut-ref="point3"/>
</aop:aspect>
</aop:config>
17.基于注解的Aop实现
基于注解的Aop实现
@Aspect
@Before("execution(* com.click369.service.impl.UserServiceImpl.insertService(..))")
@AfterReturning("execution(* com.click369.service.impl.UserServiceImpl.updateService(..))")
@Around("execution(* com.click369.service.impl.UserServiceImpl.deleteService(..))")
<!-- 开启aop注解 -->
<aop:aspectj-autoproxy />
18.切入点表达式
1.任意公共方法的执行:
execution(public * *(..))
2.任何一个名字以“set”开始的方法的执行:
execution(* set*(..))
3.AccountService接口定义的任意方法的执行:
execution(* com.xyz.service.AccountService.*(..))
4.在service包中定义的任意方法的执行:
execution(* com.xyz.service.*.*(..))
5.在service包或其子包中定义的任意方法的执行:
execution(* com.xyz.service..*.*(..))
6.在service包中的任意连接点(在Spring AOP中只是方法执行):
within(com.xyz.service.*)
7.在service包或其子包中的任意连接点(在Spring AOP中只是方法执行):
within(com.xyz.service..*)
8.实现了AccountService接口的代理对象的任意连接点 (在Spring AOP中只是方法执行):
this(com.xyz.service.AccountService)
'this'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得代理对象在通知体内可用。
9.实现AccountService接口的目标对象的任意连接点 (在Spring AOP中只是方法执行):
target(com.xyz.service.AccountService)
'target'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得目标对象在通知体内可用。
10.任何一个只接受一个参数,并且运行时所传入的参数是Serializable 接口的连接点(在Spring AOP中只是方法执行)
args(java.io.Serializable)
'args'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得方法参数在通知体内可用。
请注意在例子中给出的切入点不同于 execution(* *(java.io.Serializable)): args版本只有在动态运行时候传入参数是Serializable时才匹配,而execution版本在方法签名中声明只有一个 Serializable类型的参数时候匹配。
11.目标对象中有一个 @Transactional 注解的任意连接点 (在Spring AOP中只是方法执行)
@target(org.springframework.transaction.annotation.Transactional)
'@target'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
12.任何一个目标对象声明的类型有一个 @Transactional 注解的连接点 (在Spring AOP中只是方法执行):
@within(org.springframework.transaction.annotation.Transactional)
'@within'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
13.任何一个执行的方法有一个 @Transactional 注解的连接点 (在Spring AOP中只是方法执行)
@annotation(org.springframework.transaction.annotation.Transactional)
'@annotation'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
14.任何一个只接受一个参数,并且运行时所传入的参数类型具有@Classified 注解的连接点(在Spring AOP中只是方法执行)
@args(com.xyz.security.Classified)
'@args'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
15任何一个在名为'tradeService'的Spring bean之上的连接点 (在Spring AOP中只是方法执行):
bean(tradeService)
16.任何一个在名字匹配通配符表达式'*Service'的Spring bean之上的连接点 (在Spring AOP中只是方法执行):
bean(*Service)
19.什么事务?
对数据库的一系列操作中,保证同时成功或者同时失败。不能出现成部分成功,失败部分的情况。而这一些列操作称为数据库的事务。
20.数据库的事务有4大特征【ACID】
原子性:指事务是一个不可分割的工作单位,事务的操作要么都发生,要么都不发生.
一致性:事务前后数据的完整性必须保持一致。
隔离性:指多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务干扰,多个并发之间的数据要相互隔离。
持久性:指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其又任何影响。简称ACID。其中隔离性最重要。
21.事务的隔离性
使用Java操作的时候设置隔离级别由高到低分别为:
Serializable:可避免脏读、不可重复读、虚读情况的发生。
Repeatable read:可避免脏读、不可重复读情况发生。(可重复读)
Read committed:可避免脏读情况的发生。(读已提交)
Read uncommitted:最低级别,以上情况均为无法保证。(读未提交)
22.Spring的声明式事务管理方式
1.基于xml方式的事物管理操作
数据库中创建t_account账户表,模拟转账,演示spring的事务控制。
create table t_account(
account_id int primary key auto_increment,
user_name varchar(20),
money int
);
insert into t_account values(null,'刘能',10000);
insert into t_account values(null,'赵四',10000);
Spring+MyBatis工程结构
1. 创建工程导入依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.click369.springaop</groupId>
<artifactId>SpringAOPDemo1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!-- spring_tx -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- spring-jdbc -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- MyBatis依赖 -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!-- mybatis-spring 整合包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!--druid 阿里的连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.7</version>
</dependency>
<!-- mysql数据库驱动 -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
</dependencies>
<!-- 配置插件 -->
<build>
<plugins>
<!-- 配置jdk1.8的编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.转账接口
package com.click369.mapper;
import java.util.Map;
/**
* 转账接口
* @author Administrator
*
*/
public interface TransferMapper {
// 加钱
public void addMoney(Map param);
// 减钱
public void lessMoney(Map param);
}
3.在src/main/resources下创建mapper文件夹,mapper文件夹中创建Sql映射文件
<?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="com.click369.mapper.TransferMapper">
<!-- 编写加钱的sql -->
<update id="addMoney" parameterType="hashMap">
update t_account set money = money + #{number} where user_name = #{username}
</update>
<!-- 编写减钱的sql -->
<update id="lessMoney" parameterType="hashMap">
update t_account set money = money - #{number} where user_name = #{username}
</update>
</mapper>
4. 创建业务访问接口以及实现类
package com.click369.service;
/**
* 转账业务访问接口
* @author Administrator
*
*/
public interface TransferService {
/**
* 转账方法
* @throws Exception
*/
void transfer()throws Exception;
}
package com.click369.service.impl;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.click369.mapper.TransferMapper;
import com.click369.service.TransferService;
/**
* 转账业务实现类
* @author Administrator
*
*/
@Service("transferService")
public class TransferServiceImpl implements TransferService {
//定义依赖对象
@Autowired
private TransferMapper transferMapper;
@Override
public void transfer() throws Exception {
//从刘能的账户减少1000元,给赵四的账户增加1000元
Map param1=new HashMap();
param1.put("number", 1000);
param1.put("username", "刘能");
transferMapper.lessMoney(param1);
//int i=10/0;
Map param2=new HashMap();
param2.put("number", 1000);
param2.put("username", "赵四");
transferMapper.addMoney(param2);
}
}
5. 创建数据库链接资源
mydriver = com.mysql.jdbc.Driver
myurl = jdbc:mysql://127.0.0.1:3306/test
myusername = root
mypassword = 123456
6. 配置Spring配置文件
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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">
<!-- 读取数据库链接字符串的资源文件 -->
<context:property-placeholder location="classpath:mydatabase.properties"/>
<!-- 配置数据源 com.alibaba.druid.pool.DruidDataSource -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${mydriver}"></property>
<property name="url" value="${myurl}"></property>
<property name="username" value="${myusername}"></property>
<property name="password" value="${mypassword}"></property>
</bean>
<!-- 配置SqlSessionFactory "org.mybatis.spring.SqlSessionFactoryBean" -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mapperLocations" value="classpath:mapper/*Mapper.xml"></property>
</bean>
<!--扫描所有Mapper接口-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.click369.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
<!-- 配置spring的事务管理 -->
<!-- 1.创建事务管理器对象-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 需要配置数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 2.创建事务-->
<!--id:事务名称 -->
<!--transaction-manager:事务管理器对象-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 使用method配置是事务控制的方法,method的其他属性默认即可 -->
<tx:method name="transfer"/>
</tx:attributes>
</tx:advice>
<!-- 3.通过aop将上面创建好的事物,作用到指定的业务方法中 -->
<aop:config>
<aop:pointcut expression="execution(* com.click369.service.impl.TransferServiceImpl.transfer(..))" id="point1"/>
<!-- aop:advisor专门配置事务对象 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="point1"/>
</aop:config>
<!-- 开启Spring主解 -->
<context:annotation-config></context:annotation-config>
<!-- 配置扫描包 -->
<context:component-scan base-package="com.click369.service.impl"></context:component-scan>
</beans>
7. 测试代码
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
TransferService transferService=(TransferService)ac.getBean("transferService");
transferService.transfer();
7.基于注解方式的事物管理操作
1.在需要管理事务的方法或者类上面 添加@Transactional 注解
package com.click369.service.impl;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.click369.mapper.TransferMapper;
import com.click369.service.TransferService;
/**
* 转账业务实现类
* @author Administrator
*
*/
@Service("transferService")
//使用@Transactional注解来表示当前的类需要被spring的事务管理
@Transactional
public class TransferServiceImpl implements TransferService {
//定义依赖对象
@Autowired
private TransferMapper transferMapper;
@Override
public void transfer() throws Exception {
// 从刘能的账户减少1000元,给赵四的账户增加1000元
Map param1=new HashMap();
param1.put("number", 1000);
param1.put("username", "刘能");
transferMapper.lessMoney(param1);
int i=10/0;
Map param2=new HashMap();
param2.put("number", 1000);
param2.put("username", "赵四");
transferMapper.addMoney(param2);
}
}
2.配置注解驱动事务管理(事务管理注解生效的作用)(需要配置对特定持久层框架使用的事务管理器)
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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">
<!-- 读取数据库链接字符串的资源文件 -->
<context:property-placeholder location="classpath:mydatabase.properties"/>
<!-- 配置数据源 com.alibaba.druid.pool.DruidDataSource -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${mydriver}"></property>
<property name="url" value="${myurl}"></property>
<property name="username" value="${myusername}"></property>
<property name="password" value="${mypassword}"></property>
</bean>
<!-- 配置SqlSessionFactory "org.mybatis.spring.SqlSessionFactoryBean" -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mapperLocations" value="classpath:mapper/*Mapper.xml"></property>
</bean>
<!--扫描所有Mapper接口-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.click369.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
<!-- 开启Spring主键 -->
<context:annotation-config></context:annotation-config>
<!-- 配置扫描包 -->
<context:component-scan base-package="com.click369.service.impl"></context:component-scan>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 需要配置数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 开启事务注解 -->
<!-- <tx:annotation-driven transaction-manager="transactionManager"/>-->
<!-- 默认会找transactionManager为名称的事务管理类对应的bean,
因此可以在配置tx:annotation-driven的时候省略transaction-manager属性 -->
<tx:annotation-driven/>
</beans>
3.测试:
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
TransferService transferService=(TransferService)ac.getBean("transferService");
transferService.transfer();