了解spring
-
spring是一个容器,容器中存放的是java对象。
需要做的是把对象放入到容器中,让容器完成对象的创建,对象之间关系的管理(属性赋值)。
我们在程序中从容器中获取要使用的对象 -
什么样的对象放入容器中
- dao类,service类,controller类,工具类
spring中的对象默认都是单例的,在容器中叫这个名称的对象只有一个
-
不放入到spring容器中的对象
- 实体类对象,实体类数据来自数据库的
- servlet,listener,filter等
使用步骤
-
创建maven项目
-
加入maven依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.5.RELEASE</version> </dependency>
-
创建类
-
创建spring需要使用的配置文件:
applicationContext.xml
<bean id="someService" class="cn.zbdx.service.SomeServiceImpl" />
- 测试spring创建的类:
MyTest.java
// 1.指定spring容器创建的对象
String config = "beans.xml";
// 2.创建表示spring容器的对象,ApplicationContext
// ApplicationContext就是表示spring容器,通过容器获取对象了
// ClassPathXmlApplicationContext:表示从类路径中加载spring的配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
// 从容器中获取某个对象,要调用对象的方法
// getBean("配置文件中的bean的id值")
SomeService someService = (SomeService) ac.getBean("someService");
// 使用spring创建好的对象
someService.dosome();
spring是把创建好的对象放入到map中,spring框架有一个map存放对象的。
核心技术
ioc(控制反转)
控制:创建对象,对象的属性赋值,对象之间的关系管理。
反转:把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现。由容器代替开发人员管理对象,创建对象,给属性赋值。
概念:把对象的创建,赋值,管理工作都交给代码之外的容器实现,对象的创建由外部资源完成。
使用目的:减少对代码的改动,也能实现不同的功能,实现解耦合。
di技术
di:依赖注入,表示创建对象,给属性赋值
spring使用的di技术,底层使用的是反射机制
di的实现有两种:
- 在spring的配置文件中,使用标签和属性完成,叫做基于XML的di实现
- 使用spring中的注解,完成属性赋值,叫做基于注解的id实现
di给属性赋值:
-
set注入:spring调用类的set方法,在set方法可以实现属性的赋值
- 简单类型的set注入:
<bean id="myStudent" class="cn.zbdx.service.bao01.Student" > <property name="name" value="xz"/> <property name="age" value="3" /> </bean>
- 引用类型的set注入:
<bean id="myStudent" class="cn.zbdx.service.bao01.Student" > <property name="name" value="xz"/> <property name="age" value="3" /> <property name="school" ref="mySchool" /> </bean> <bean id="mySchool" class="cn.zbdx.service.bao01.School" > <property name="name" value="北京大学" /> <property name="address" value="海淀区" /> </bean>
-
构造注入:spring调用类的有参数构造方法,创建对象,在构造方法中完成赋值。
构造注入使用
<constructor-arg>
标签applicationContext.xml
<bean id="myStudent" class="cn.zbdx.service.bao02.Student" > <constructor-arg name="name" value="wyb" /> <constructor-arg name="age" value="3" /> <constructor-arg name="school" ref="mySchool"/> </bean> <bean id="myStudent1" class="cn.zbdx.service.bao02.Student" > <constructor-arg index="0" value="wx" /> <constructor-arg index="1" value="1" /> <constructor-arg index="2" ref="mySchool"/> </bean> <bean id="myStudent2" class="cn.zbdx.service.bao02.Student" > <constructor-arg value="wxx" /> <constructor-arg value="1" /> <constructor-arg ref="mySchool"/> </bean>
MyTest.java
@Test public void test03() { String config = "/bao01/applicationContext.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(config); Student student = (Student) ac.getBean("myStudent"); System.out.println(student); }
-
自动注入
由spring根据某些规则,给引用类型完成赋值,常用的有byName,byType- byName(按名称注入):java类中引用类型的属性名和spring容器中(配置文件)
<bean>
的id名称一样,且数据类型是一致的,这样的容器中的bean,spring能够赋值给引用类型
语法:
<bean id="myStudent" class="cn.zbdx.service.bao04.Student" autowire="byName"> <property name="name" value="张三"/> <property name="age" value="13" /> </bean> <bean id="school" class="cn.zbdx.service.bao04.School" > <property name="name" value="北京大学" /> <property name="address" value="海淀区" /> </bean>
- byType(按类型注入):java类中引用的数据类型和spring容器中(配置文件)
<bean>
的class属性是同源关系的,这样的bean能够赋值给引用类型。
同源就是一类的意思-
java类中引用类型的数据类型和bean的class的值是一样的
-
java类中引用类型的数据类型和bean的class的值是父子关系类的
-
java类中引用类型的数据类型和bean的class的值是接口和实现类关系的
注意:在byType中,在xml配置文件中声明bean只能有一个符合条件的,多余一个是错误的
-
- byName(按名称注入):java类中引用类型的属性名和spring容器中(配置文件)
多配置文件
多个配置文件的优势:
- 每个文件的大小比一个文件要小很多,效率高
- 避免多人竞争带来的冲突
多文件的配置方式:
- 按功能模块,一个模块一个配置文件
- 按类的功能,数据库相关的一个配置文件,做事务的功能一个配置文件,做service功能的一个配置文件等
spring-school.xml
<bean id="school" class="cn.zbdx.service.bao05.School" >
<property name="name" value="北京大学" />
<property name="address" value="海淀区" />
</bean>
spring-student.xml
<bean id="myStudent" class="cn.zbdx.service.bao05.Student" autowire="byName">
<property name="name" value="张三"/>
<property name="age" value="13" />
</bean>
total.xml
<!--<import resource="classpath:bao05/spring-school.xml" />
<import resource="classpath:bao05/spring-student.xml" />-->
<import resource="classpath:bao05/spring-*.xml" />
classpath
:表示类路径(class文件所在的目录),在spring的配置文件中要指定其他文件的位置,需要使用classpath,告诉spring到哪去加载读取文件。
*
:通配符,表示任意字符
注解的使用步骤
- 加入maven依赖
- 在类中加入spring的注释
- 在spring配置文件中,加入一个组件扫描器的标签,说明注解在项目中的位置
<!--指定多个包的三种方式 -->
<!-- 使用多次组件扫描器,指定不同的包 -->
<context:component-scan base-package="cn.zbdx.bao02" />
<context:component-scan base-package="cn.zbdx.bao03" />
<!-- 使用分隔符;或,分隔多个包名 -->
<context:component-scan base-package="cn.zbdx.bao02;cn.zbdx.bao03" />
<!-- 指定父包 -->
<context:component-scan base-package="cn.zbdx" />
常用的七个注解
-
@Component:创建对象
-
@respotory:创建dao对象,用来访问数据库的
-
@Service:创建service对象,处理业务逻辑的,可以有事务功能
-
@Controller:创建控制器对象的,能够接受用户提交的参数,显示请求的处理结果
以上三个注解的使用语法和@Component一样的,都是创建对象,但是这三个注解还有额外的功能。
@respotory,@Service,@Controller是给项目的对象分层的 -
@Value:简单类型的属性赋值
位置:
- 在属性定义的上面,无需set方法,推荐使用
- 在set方法的上面
-
@Autowired:spring框架提供的注解,实现引用类型的赋值
spring中通过注解给引用类型赋值,使用的是自动注入原理,支持byName, byType。
@Autowired
默认使用的是byType自动注入属性:required,是一个boolean类型的,默认true
required = true:表示引用类型赋值失败,程序报错,并终止执行
required =false:引用类型如果赋值失败,程序正常执行,引用类型是null如果要使用byName方式,需要做的是:
- 在属性上面加入@Autowired
- 在属性上面加入@Qualifier(“bean的id”):表示使用指定名称的bean完成赋值
-
@Resource:jdk中的注解
使用的也是自动注入原理,支持byName, byType
默认是byName:先使用byName自动注入,如果byName赋值失败,再使用byType
@Resource只使用byName方式,需要增加一个属性name,name的值是bean的id
AOP(面向切面编程)
-
AOP(Aspect Orient Programming):面向切面编程,底层是动态代理,可以使用jdk,cglib两种代理方式
- jdk动态管理:使用jdk中的Proxy,Method,InvocationHanderl创建代理对象
要求:目标类必须实现接口 - cglib动态管理:第三方的工具库,创建代理对象。
要求:目标类不能是final的,方法也不能是final的
原理:就是继承,子类就是代理
- jdk动态管理:使用jdk中的Proxy,Method,InvocationHanderl创建代理对象
-
AOP:看做是动态代理的规范化,把实现动态代理的步骤进行了一个规范,定义
-
AOP的作用:
- 在目标类源代码不改变的情况下,增加功能
- 减少代码的重复
- 专注业务逻辑代码
- 解耦合,让业务的功能和日志,事务非业务功能分离
-
什么时候考虑用AOP
- 当你要给一个系统中存在的类修改功能,但是原有类功近乎完善,你有源代码
- 你要给项目中的多个类,增加一个相同的功能
- 给业务方方法增加事务,日志输出
-
AOP的技术实现框架:
- spring:spring在内部实现了aop规范,能做aop的工作
- aspectJ:一个开源的专门做aop的框架。spring框架中集成了aspectJ框架,通过spring就能使用aspectJ的功能
aspectJ实现aop有两种方式:- 使用xml的配置文件,配置全局事务
- 使用注解,我们在项目中要做aop功能,一般都使用注解,aspectJ有五个注解
-
AOP中的术语:
- Aspect:切面,表示增强的功能,就是一堆代码,完成某一个功能,非业务功能
常见的切面功能有:日志,事务,统计信息,参数检查,权限验证 - JoinPoint:连接点,连接业务方法和切面的位置
- PointCut:切入点,指多个连接点方法的集合
- Advice:通知,通知表示切面功能执行的时间
- Aspect:切面,表示增强的功能,就是一堆代码,完成某一个功能,非业务功能
aspectJ
aspectJ框架的使用:
-
切面的执行时间,这个执行时间在规范中叫做Advice(通知,增强)
- @Before:前置通知,在目标方法之前执行切面的功能
- @AfterReturning:后置通知,在目标方法之后执行的,能够获取到目标方法的返回值
- @Around:环绕通知,在目标方法前和后都能增强功能,控制目标方法的访问,修改返回值
- @AfterThrowing:异常通知,在目标方法抛出异常后执行的通知
- @After:最终通知,总是会被执行的代码
- @Pointcut:定义和管理切入点的辅助注解
- 代理的使用方法
- 如果目标类有接口,框架使用jdk动态代理
- 如果目标类无接口,默认使用cglib动态代理
- 有接口也可以强制使用cglib动态代理
-
切面执行的位置,使用的是切入点表达式
execution(访问权限 方法返回值 方法声明(参数) 异常类型)
实现步骤:
- 新建maven项目
- 加入依赖:spring,aspectJ
- 创建目标类:接口和他的实现类,要做的是给类中的方法增加功能
- 创建切面类:普通类
- 在类的上面加入:@Aspect
- 在类中定义方法,方法就是切面要执行的功能代码
在方法的上面加入aspecctJ中的通知注解,例如@Before
有需要指定切入点表达式execution()
- 创建spring的配置文件:声明对象,把对象交给容器统一管理
声明对象可以使用注解或者xml配置文件<bean>
- 声明目标对象
- 声明切面类对象
- 声明aspectJ框架中的自动代理生成器标签
自动代理生成器:用来完成代理对象的自动创建功能的
- 创建测试类
整合Mybatis
-
把mybatis框架和spring集成在一起,向一个框架一样使用
-
使用到的技术:ioc
-
原理:ioc能创建对象
可以把mybatis框架中的对象交给spring统一创建,开发人员从spring中获取对象
开发人员就不用同时面对两个或多个框架了,就面对一个spring -
使用步骤
- 新建maven项目
- 加入maven依赖
- 创建实体集
- 创建dao接口和mapper文件
- 创建mybatis主配置文件
- 创建service接口和实现类,属性是dao
- 创建spring的配置文件:声明mybatis的对象交给spring创建
- 数据源
- SqlSessionFactory
- dao对象
- 声明自定义的service
- 创建测试类,获取service对象,通过service调用dao完成数据库的访问
Spring事务
-
什么是事务
事务是指一组sql语句的集合,集合中有多条sql语句
可能是insert,update,select,delete,我们希望这些多个sql语句都能成功,或者都失败,这些sql语句的执行是一致的,作为一个整体执行。 -
在什么时候想到用事务
当我的操作,涉及得到多个表,或者是多个sql语句的insert,select,需要保证这些语句都是成功才能完成我的功能,或者都失败,保证操作是符合要求的在java代码中写程序,控制事务,此时事务应该放在哪里呢?
service类的业务方法上,因为业务方法会调用多个dao方法,执行多个sql语句 -
多种数据库的访问技术,有不同的事务处理的机制,对象,方法
-
怎么解决不足?
spring提供一种处理事务的统一模型,能使用统一步骤,方法完成多种不同数据库访问技术的事务处理 -
处理事务,需要怎么做,做什么
spring处理事务的模型,使用的步骤都是固定的,把事务使用的信息提供给spring就可以了-
事务内部提交,,回滚事务,使用的事务管理对象,代替你完成commit, rollback
事务管理器是一个接口和他的众多实现类- 接口:
PlatformTransactionManager
,定义了事务重要方法 commit,rollback - 实现类:spring把每一种数据库访问技术对应的事务处理类都创建好了
mybatis
访问数据库–spring创建好的是DataSourceTransactionManager
怎么使用?声明数据库访问技术对应的事务管理器实现类,在spring的配置文件中使用
<bean>
声明 - 接口:
-
业务方法需要什么样的事务,需要说明事务的类型
说明方法需要的事务:- 事务的隔离级别:有4 个值
- READ_UNCOMMITTED:读未提交
- READ_COMMITTED:读已提交
- REPEATABLE_READ:可重复读
- SERIALIZABLE:串行化
- 事务的超时时间:表示一个方法最长的执行时间,如果方法执行超过了时间,事务就回滚
- 事务的传播行为:控制业务方法是不是有事务的,是什么样的事务的
7个传播行为,表示你的业务方法调用时,事务在方法之间是如何使用的。- PROPAGATION_REQUIRED
- PROPAGATION_REQUIRES_NEW
- PROPAGATION_SUPPORTS
- 事务的隔离级别:有4 个值
-
事务提交事务,回滚事务的时机
- 当业务方法执行成功,无异常抛出,当方法执行完毕,spring在方法执行后提交事务。事务管理器commit
- 当业务方法抛出运行时异常或error,spring回滚事务,调用事务管理器的rollback
- 当业务方法抛出非运行时异常,主要是受查异常时,提交事务
受查异常:在代码中,必须处理的异常。例如:IOException
-
事务处理方案
-
适合中小项目使用的,注解方案
spring框架自己用aop实现给业务方法增加事务的功能,使用@Transactional
注解增加事务
使用步骤:- 声明事务管理器对象,开启事务注解驱动
<!-- 使用spring的事务处理--> <!-- 声明事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name="dataSource" ref="myDataSource" /> </bean> <!-- 开启事务注解驱动,告诉spring使用注解管理事务,创建代理对象--> <tx:annotation-driven transaction-manager="transactionManager" />
- 在你的方法上面加入
@Transactional
- 在你的方法上面加入
- 声明事务管理器对象,开启事务注解驱动
-
适合大型项目。使用aspectJ框架功能,在spring配置文件中声明类,方法需要的事务
实现步骤:
- 加入aspectJ依赖
- 声明事务管理器对象
- 声明方法需要的事务类型
- 配置aop:指定哪些类要创建你代理
<!-- 大型项目 -->
<!-- 1. 声明事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="myDataSource" />
</bean>
<!-- 声明业务方法它的事务属性(隔离级别,传播行为,超时时间)
id:自定义名称,表示<tx:Advice> 和 </tx:advice> 之间的配置内容的
transaction-manager:事务管理器对象的id
-->
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<!-- <tx:attributes>:配置事务属性-->
<tx:attributes>
<!--tx:method:给具体的方法配置事务属性,method可以有多个,分别给不同的方法设置事务属性
name:1. 完整的方法名称,不带有包和类
2. 方法可以使用通配符,表示任意字符
propagation:传播行为,枚举值
isolation:隔离级别
rollback-for:指定的异常类名,全限定类名,发生异常一定回滚-->
<tx:method name="buy" propagation="REQUIRED" isolation="DEFAULT"
rollback-for="java.lang.NullPointerException, cn.zbdx.execp.NotEnoughException"/>
</tx:attributes>
</tx:advice>
<!-- 配置aop-->
<aop:config>
<!-- 配置切入点表达式,指定哪些包中类,要使用事务-->
<aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/>
<!-- 配置增强器:关联Advice和pointcut-->
<aop:advisor advice-ref="myAdvice" pointcut-ref="servicePt" />
</aop:config>
以上为个人学习笔记,参考视频来自动力节点,若有雷同,纯属巧合。