spring
2022-04-02 17:33:11 196 举报
AI智能生成
spring
作者其他创作
大纲/内容
建议
建议使用多配置文件
使用多配置文件就是spring中管理类的applicationContext.xml文件
1、多配置文件,每个单独的文件就很小了,读取的效率也会提高
2、避免了冲突,已经多人开发带来的竞争
如果项目有多个模块,一个模块一个配置文件
比如:之前写的学生管理系统
- 学生信息管理使用一个配置文件
- 班级管理使用一个配置文件
按照类的功能进行分配,数据库相关的类放在一个配置文件,做事务管理的一个配置文件
service的一个配置文件等;
1、多配置文件,每个单独的文件就很小了,读取的效率也会提高
2、避免了冲突,已经多人开发带来的竞争
如果项目有多个模块,一个模块一个配置文件
比如:之前写的学生管理系统
- 学生信息管理使用一个配置文件
- 班级管理使用一个配置文件
按照类的功能进行分配,数据库相关的类放在一个配置文件,做事务管理的一个配置文件
service的一个配置文件等;
多配置文件的包含关系
学生模块和学校模块分开
spring-student.xml
spring-school.xml
需要一个主配置文件进行包含,当我们加载主配置文件的时候,会把主配置文件中包含的配置文件
加载到spring容器中
total.xml
包含必须用到的东西:classPath:
规定的是target/classes/作为根目录
spring-student.xml
spring-school.xml
需要一个主配置文件进行包含,当我们加载主配置文件的时候,会把主配置文件中包含的配置文件
加载到spring容器中
total.xml
包含必须用到的东西:classPath:
规定的是target/classes/作为根目录
1、直接指定路径包含
<import resource="classPath:demo04/spring-student.xml"/>
<import resource="classPath:demo04/spring-school.xml"/>
<import resource="classPath:demo04/spring-student.xml"/>
<import resource="classPath:demo04/spring-school.xml"/>
2、使用通配符的形式
<import resource="classPath:demo04/spring-*.xml" />
<import resource="classPath:demo04/spring-*.xml" />
【注意】
【注意】:这个通配符包含的文件不能包括主配置文件本身,否则会出现加载死循环
并且使用这个通配符的形式,这些xml文件必须放在一个目录之下,否则无法加载
这是官方文档中的声明
并且使用这个通配符的形式,这些xml文件必须放在一个目录之下,否则无法加载
这是官方文档中的声明
小知识点
1、spring配置文件读取properties配置文件
<context:property-placeholder location="classpath:student.properties"/>
spring简介
出现在2003年左右,是为了解决企业级开发的难度,减轻对项目模块之间的管理
类与类之间的管理,帮助开发人员创建对象,管理对象之间的关系
spring的核心是ioc和aop,能实现模块之间,类之间的解耦合
类与类之间的管理,帮助开发人员创建对象,管理对象之间的关系
spring的核心是ioc和aop,能实现模块之间,类之间的解耦合
官网:spring.io
spring-ioc:控制反转
1、 关于ioc的概念
控制反转(Inversion of control):
原本是程序员自己创建对象, 给属性赋值。并且管理类与类之间的关系。
现在是spring框架,也就是spring容器来创建对象,给属性赋值,管理类与类
之间的关系,实现类与类之间,模块与模块之间解耦合
原本是程序员自己创建对象, 给属性赋值。并且管理类与类之间的关系。
现在是spring框架,也就是spring容器来创建对象,给属性赋值,管理类与类
之间的关系,实现类与类之间,模块与模块之间解耦合
2、IOC的技术实现,就是使用DI(Dependency Injection)
就是依赖注入:只需要在程序中提供需要创建的对象的名称即可
其他的操作都是容器完成的
其他的操作都是容器完成的
3、spring创建对象的步骤
1、在maven中添加依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
2、编写spring的配置文件,也就是ApplicationContext.xml
直接使用xml-configuration File
然后选择spring-config,创建一个applicationContext.xml的spring配置文件
然后选择spring-config,创建一个applicationContext.xml的spring配置文件
告诉spring创建对象,声明bean,告诉spring,我们需要创建哪个对象
id:自定义名称,唯一
class:创建的类的全限定名称
底层需要反射机制实例化对象,因此,不能使用接口
这个时候spring就会执行这样的代码
SomeService someService = new SomeServiceImpl();
然后将这个对象放进map集合中
map.put("SomeService",someService);
就是map.put(id,对象);
id:自定义名称,唯一
class:创建的类的全限定名称
底层需要反射机制实例化对象,因此,不能使用接口
这个时候spring就会执行这样的代码
SomeService someService = new SomeServiceImpl();
然后将这个对象放进map集合中
map.put("SomeService",someService);
就是map.put(id,对象);
在根标签<beans>下加入类配置信息
<bean id="唯一的标识" class="需要创建的类对象的全限定名称" />
<bean id="唯一的标识" class="需要创建的类对象的全限定名称" />
3、在程序中使用spring来完成对象的创建
1、声明配置文件位置:target/classes是根目录。
2、spring容器加载配置文件,ApplicationContext ac = new ClassPathXmlApplicationContext(配置文件);
3、使用ac.getBean(对应的那个配置文件的bean的ID);
4、获取对象以后强制类型转换成自己需要的,然后调用方法
关于spring的执行时机
1、在执行读取配置文件信息的时候就会创建对象,创建对象会调用无参构造
2、关于spring中获取创建对象的数量以及创建对象的名称
获取创建对象的数量:ac.getBeanDefinintionCount();
获取所有对象的名称: String [] names = ac.getBeanDefinitionNames();
4、spring容器创建对象进行属性赋值
DI
概念
di:依赖注入,表示创建对象,给对象赋值
di的实现方式有两种
1、在spring配置文件中,使用标签和属性完成,叫做基于XML的di实现
2、使用spring中的注解,完成属性赋值,叫做基于注解的di实现
di的实现方式有两种
1、在spring配置文件中,使用标签和属性完成,叫做基于XML的di实现
2、使用spring中的注解,完成属性赋值,叫做基于注解的di实现
1、set注入(设值注入):spring调用类的set方法进行属性的赋值。
2、构造注入:spring调用类的有参数构造方法。创建对象。创建时完成赋值;
2、构造注入:spring调用类的有参数构造方法。创建对象。创建时完成赋值;
基于xml配置文件的DI实现
set注入,设值注入
1、spring调用类的set方法进行属性的赋值。
基本类型的设值注入:(基本数据类型和String)
<bean id="user" classes="com.javase.User" >
<property name="id" value="1001" />
<property name="name" value="张三" />
</bean>
<property name="id" value="1001" />
<property name="name" value="张三" />
</bean>
1、实际上是spring底层调用了set方法进行赋值,因此必须有set方法,没有会报错!
2、这个name不是指类中的属性,他底层肯定是通过反射机制找到哪个对应的set方法
比如:id 就会去找setId
因此:他是根据set方法进行访问的
如果此时<property name="email" value="lisi@qq.com" />
这个时候即使没有email这个属性,只要有setEmail方法就不会出错
【那个set方法必须有参数】
2、这个name不是指类中的属性,他底层肯定是通过反射机制找到哪个对应的set方法
比如:id 就会去找setId
因此:他是根据set方法进行访问的
如果此时<property name="email" value="lisi@qq.com" />
这个时候即使没有email这个属性,只要有setEmail方法就不会出错
【那个set方法必须有参数】
引用类型的设值注入
User{id=123, name='李四', school=School{name='清华大学', address='大兴区'}}
通过ref进行指向
User 对象中有个属性是引用数据类型 School
这个时候
<property name="" value="" />没法直接赋值
需要通过ref指向另一个对象
<property name="school" ref="school" />
通过ref进行指向
User 对象中有个属性是引用数据类型 School
这个时候
<property name="" value="" />没法直接赋值
需要通过ref指向另一个对象
<property name="school" ref="school" />
自动注入
byName
1、 在进行set注入的时候,有的属性值是一个引用数据类型
我们对于引用数据类型需要使用<property name="school" ref="myschool" />
的形式,让他找到这个引用数据类型
我们对于引用数据类型需要使用<property name="school" ref="myschool" />
的形式,让他找到这个引用数据类型
2、 现在,使用byName命名规则,spring会自动查找进行赋值,不需要手动赋值
给当前bean声明autowire属性:autowire="byName",这个时候,这个javabean就会
自己去寻找需要的引用数据类型
但是条件是:这个引用数据类型的id,必须和这个声明的属性值一样
也就是:
private School school; 这个引用数据类型的javabean的id必须是school
给当前bean声明autowire属性:autowire="byName",这个时候,这个javabean就会
自己去寻找需要的引用数据类型
但是条件是:这个引用数据类型的id,必须和这个声明的属性值一样
也就是:
private School school; 这个引用数据类型的javabean的id必须是school
byType
<bean id="user" class="com.javase.demo03.User" autowire="byType" >
<property name="id" value="1001" />
<property name="name" value="李四" />
</bean>
<bean id="myschool" class="com.javase.demo03.School" >
<property name="name" value="北京大学" />
<property name="address" value="大兴区" />
</bean>
<property name="id" value="1001" />
<property name="name" value="李四" />
</bean>
<bean id="myschool" class="com.javase.demo03.School" >
<property name="name" value="北京大学" />
<property name="address" value="大兴区" />
</bean>
如果autowire属性值是:byType,这个时候,spring就会根据这个引用数据类型
去查找这个数据
比如说:private School school; 他就会去beans中查找这个School引用数据类型
说白了就是,private School school = new School();
去查找这个数据
比如说:private School school; 他就会去beans中查找这个School引用数据类型
说白了就是,private School school = new School();
同源关系有三种,都可以符合
1、当前javabean对应的类中的引用数据类型和beans中的某个class相同
2、当前javabean对应的类中的引用数据类型在beans中有个class是他的子类
2、当前javabean对应的类中的引用数据类型在beans中有个接口实现类
1、private School school = new School();
2、private School school = new SmallSchool;
3、private School school = new SchoolImpl();
1、当前javabean对应的类中的引用数据类型和beans中的某个class相同
2、当前javabean对应的类中的引用数据类型在beans中有个class是他的子类
2、当前javabean对应的类中的引用数据类型在beans中有个接口实现类
1、private School school = new School();
2、private School school = new SmallSchool;
3、private School school = new SchoolImpl();
构造注入
构造注意前提就是必须有构造方法
1、直接使用name和value的形式,name就对应类中的属性名
<bean id="user" class="com.javase.demo03.User">
<constructor-arg name="id" value="1001" />
<constructor-arg name="name" value="李四"/>
<constructor-arg name="school" ref="school" />
</bean>
<constructor-arg name="id" value="1001" />
<constructor-arg name="name" value="李四"/>
<constructor-arg name="school" ref="school" />
</bean>
2、使用index下标的形式,从0开始,指代每个位置上的参数
<constructor-arg index="0" value="1002"/>
<constructor-arg index="1" value="王五"/>
<constructor-arg index="2" ref="school"/>
<constructor-arg index="1" value="王五"/>
<constructor-arg index="2" ref="school"/>
3、默认按照位置进行赋值
<constructor-arg value="1002"/>
<constructor-arg value="王五"/>
<constructor-arg ref="school"/>
<constructor-arg value="王五"/>
<constructor-arg ref="school"/>
基于注解色DI实现
1、@Component,创建对象的注解,一般用在不是三层架构的普通类中
2、@Repository,创建对象,用在持久层中,dao接口实现的上面
3、@Service,创建对象,用在业务逻辑层,在service实现类的上面,有事务处理的功能
4、@Controller,控制层对象,用来接收用户输入,进行结果展示
5、@Value,进行属性注入,也就是属性赋值,可以用在属性上,也可以用在set方法上
6、@Autowired,自动注入,针对的是引用类型,有两种注入的方式
1、byName
通过id,也就是名字来进行查找
2、byType
默认的是这种方式,通过数据类型来进行查找,只要符合同源类型即可
当使用byName的时候,有一个注解叫做@Qualifier
是用来赋值的
是用来赋值的
7、@Resource。自动注入,这个不是spring自带的,是JDK中自带的注解
1、byName
通过javabean中的id,和属性值进行匹配
1、没有手动给这个引用数据类型附上值,则如果没有找,就会使用byType
2、手动赋值以后,没有找到就会报错
2、byType
根据类型来进行查找,同源关系
注解的实现步骤
1、在maven中加入依赖,spring-context,加入这个依赖会自动的加入spring-aop依赖,注解使用的就是srping-aop.jar
2、在类中加入注解
3、在配置文件中声明组件扫描器,通知spring去扫描哪些包寻找对象,并创建对象,<cotext:component-scan > base-package="包名"
加入扫描包的三种方式
1、一次加入多个
把每个包都写出来
<context:component-scan base-package="com.javase.domain" />
<context:component-scan base-package="com.javase.dao" />
<context:component-scan base-package="com.javase.service" />
<context:component-scan base-package="com.javase.domain" />
<context:component-scan base-package="com.javase.dao" />
<context:component-scan base-package="com.javase.service" />
2、通过;或者,进行包与包之间的分割
<context:component-scan base-package="com.javase.service;
com.javase.domain;
com.javase.dao" />
com.javase.domain;
com.javase.dao" />
3、扫描父包
<context:component-scan base-package="com.javase" />
这里建议时不要使用在高一级的包,因为文件夹越深效率越低
这里建议时不要使用在高一级的包,因为文件夹越深效率越低
4、使用配置文件进行赋值操作
1、编写properties配置文件
2、在spring配置文件中声明这个属性配置文件
<context:property-placeholder location="classpath:student.properties"/>
3、在需要的地方比如说属性上
@(value="${name}")
private String name;
private String name;
5、通过Value("#{属性}")获取值
@Value("#{}")
其实是SpEL表达式的值,可以表示常量的值,或者获取bean中的属性
其实是SpEL表达式的值,可以表示常量的值,或者获取bean中的属性
目的:实现业务逻辑之间的解耦合,比如:service和dao
spring-aop:面向横切面编程
1、spring中的动态代理
1、使用JDK动态代理
使用Proxy,Method,InvocationHandle来创建代理对象,条件是必须有接口
2、使用CGlib第三方工具库动态代理
要求就是他的方法不能是final的,属性不能是final的,实际底层通过继承的原理实现代理类
动态代理的优点,功能
1、在不修改源代码的情况下,对某个类中的方法进行功能的增强
2、减少重复代码
3、让程序员专注于业务逻辑代码的编写
4、让程序解耦合,业务功能,日志功能,事务处理功能等都分开了,互相之间的联系不紧密
2、aop是什么?
1、aop就是(Aspect Orient Programming),面向切面编程,是基于动态代理实现的
可以使用jdk自带的动态代理,也可以使用cglib第三方工具库。aop就是动态代理的规范化
他把动态代理的实现步骤已经完成了,开发人员只需要通过一定的规范就行为和使用即可
可以使用jdk自带的动态代理,也可以使用cglib第三方工具库。aop就是动态代理的规范化
他把动态代理的实现步骤已经完成了,开发人员只需要通过一定的规范就行为和使用即可
2、 怎么理解面向切面编程:
1、在分析业务功能的时候,分析出哪些功能是切面功能,找到合适的切面
2、合理的安排切面的执行时机,在目标方法的前面还是目标方法的后面
3、合理的安排切面的执行位置,在哪个类上,在哪个方法上
切入点表达式
比如说有一个业务逻辑是这样的。需要在用户进行购买商品的时候记录下的操作的时间,token等信息的时候。就可以使用AOP,分析出一个切面,创建一个切面增强方法,完成业务逻辑。
3、aop的作用
1、在不修改源代码的情况下,增强功能
2、减少代码的重复
3、程序员可以专注于业务逻辑的实现
4、解耦合,业务逻辑。事务处理,日志管理等之间解耦合
4、什么时候考虑使用aop
1、给系统中已经存在的一个类增加功能,在不修改源代码的情况下增加功能
2、项目中多个类都需要实现同一个功能
3、给业务方法增加事务,或者日志输出等
3、相关术语
1、Asepect:切面的,就是一个类,比如:MyAspect.java这个类,这个类中有方法,
方法就是切面方法,目的是增强功能的。是给业务逻辑代码,常见的有,日志输出,事
务处理,统计信息,参数检查,权限验证等
方法就是切面方法,目的是增强功能的。是给业务逻辑代码,常见的有,日志输出,事
务处理,统计信息,参数检查,权限验证等
2、JoinPoint:连接点,就是指某个目标方法,那就是一个切入点,连接业务方法和切面的位置,就是那个业务方法
3、Pointcut:切入点,就是多个连接点的集合,多个方法
4、目标对象,就是需要增强功能的那个类
5、Advice:通知,也可以称之为增强,通知切面的执行时间,是在方法前,还是在方法之后?
4、一个切面必须要有的三要素:
1、必须有切面的功能代码,就是用来增强业务的代码
2、必须有切入点,就是切面的执行位置
3、必须有通知,就是通知切面的执行时间
5、关于aop的实现
1、spring
spring框架内部实现了aop,可以使用aop进行工作,
一般都是在事务处理中使用aop,但是spring使用aop比较繁琐,麻烦
一般都是在事务处理中使用aop,但是spring使用aop比较繁琐,麻烦
2、AspectJ
是另一个框架,是专门用来做aop的,spring框架已经集成了aspectJ框架
通过spring,可以使用aspectJ的aop功能
通过spring,可以使用aspectJ的aop功能
AspectJ的两种使用方式
1、使用xml配置文件,配置全局事务
2、使用注解开发,5个注解
6、AspectJ框架的具体实现
1、aspectJ的实现步骤
1、添加spring依赖
2、添加aspectJ依赖
3、创建接口和接口实现类
4、创建切面类增强功能,执行切面的执行位置,切面的执行时间
5、将对象交给spring容器进行管理
6、声明代理对象的配置信息
<aop:aspectj-autoproxy proxy-target-class="true"/>【必须声明】
2、切入点表达式,确定切面的执行位置
切入点表达式,是使用在注解上的,是声明这个注解,也就是这个切面的执行位置
语法规则:execution(访问控制修饰符 返回值类型 包名.类名.方法名(形参列表)) 抛出异常 )
* 匹配任意一个或者多个字符
.. 使用在参数上,表示有0个或者多个参数
使用在包上,表示当前包和子包
+ 使用在类上,表示当前类和子类
使用在接口上,表示当前接口及其实现类
.. 使用在参数上,表示有0个或者多个参数
使用在包上,表示当前包和子包
+ 使用在类上,表示当前类和子类
使用在接口上,表示当前接口及其实现类
execution(public * *(..))
指定切面执行的位置:表示所有公共的方法
execution(* set*(..)) 只有连个参数 : 返回值 方法名(参数)
指定切面执行的位置:表示所有以set开头的方法
execution(* com.javase.service.*.*(..))
指定切面执行的位置:表示com.javase.service下的所有类中的所有方法,方法参数任意
execution(* com.javase.service..*.*(..))
指定切面执行的位置:表示com.javase.service包及其子包下的所有类的所有方法
execution(* *..service.*.*(..))
指定切面执行的位置:表示所有路径下的service包中的所有类的所有方法
比如: com.javase.service.
com.javase.dao.service.
crm.javase.service.
指定切面执行的位置:表示所有公共的方法
execution(* set*(..)) 只有连个参数 : 返回值 方法名(参数)
指定切面执行的位置:表示所有以set开头的方法
execution(* com.javase.service.*.*(..))
指定切面执行的位置:表示com.javase.service下的所有类中的所有方法,方法参数任意
execution(* com.javase.service..*.*(..))
指定切面执行的位置:表示com.javase.service包及其子包下的所有类的所有方法
execution(* *..service.*.*(..))
指定切面执行的位置:表示所有路径下的service包中的所有类的所有方法
比如: com.javase.service.
com.javase.dao.service.
crm.javase.service.
3、通知,Advice,使用5个注解完成,确定切面的执行时间
1、关于参数:JoinPoint jp:每个通知都可以有这个参数,这个参数如果出现必须是第一个位置上
2、这个参数是用来获取目标方法的签名的
3、使用方法: - 获取签名:Signature sign = jp.getSignature();
- 获取方法名:String name = sign.getName();
- 获取参数:Object [] args = jp.getArgs();
2、这个参数是用来获取目标方法的签名的
3、使用方法: - 获取签名:Signature sign = jp.getSignature();
- 获取方法名:String name = sign.getName();
- 获取参数:Object [] args = jp.getArgs();
1、@Before:前置通知
1、必须使用在类上
2、必须指定切入点表达式
3、返回值为void
4、没有参数,有的话只有一个
2、必须指定切入点表达式
3、返回值为void
4、没有参数,有的话只有一个
@Before(value="execution(* *..service.*.do*(..))")
public void doBefore(){
}
public void doBefore(){
}
2、@AfterReturning:后置通知
1、必须使用在类上
2、必须指定切入点表达式
3、没有返回值
4、有参数,Object res ,如果还有就是jp
5、这个参数的名称必须和注解中的returning相同
2、必须指定切入点表达式
3、没有返回值
4、有参数,Object res ,如果还有就是jp
5、这个参数的名称必须和注解中的returning相同
@AfterReturning(value="execution()",returning="res")
public void doAfterReturning(Object res){
}
public void doAfterReturning(Object res){
}
1、关于基本数据类型和String,在这个类中修改不影响返回值
2、如果是引用数据类型,使用set方法进行了数据的改动,则返回的那个数据就会有变化
3、@Around:环绕通知
1、必须使用在类上
2、必须指定切入点表达式
3、返回值为Object
4、参数只有一个就是ProceedingJoinPoint
5、使用pjp.proceed()就是执行目标方法,等价于
method.invoke()
6、可以改变返回值结果,可以进行中间阶段的判断
7、因为pjp的父类是JoinPoint,可以读取参数,进行判断
8、几乎就是那个Proxy中的InvocationHanler接口实现类
2、必须指定切入点表达式
3、返回值为Object
4、参数只有一个就是ProceedingJoinPoint
5、使用pjp.proceed()就是执行目标方法,等价于
method.invoke()
6、可以改变返回值结果,可以进行中间阶段的判断
7、因为pjp的父类是JoinPoint,可以读取参数,进行判断
8、几乎就是那个Proxy中的InvocationHanler接口实现类
@Around(value="execution()")
public Object doAround(ProceedingJoinPoint pjp){
Object res = null;
//在前面加强
res = pjp.proceed();//执行目标方法
//在后面加强
return res;
}
public Object doAround(ProceedingJoinPoint pjp){
Object res = null;
//在前面加强
res = pjp.proceed();//执行目标方法
//在后面加强
return res;
}
4、@AfterThrowing:异常通知
1、必须使用在类上
2、必须指定切入点表达式
3、没有返回值
4、有参数,是Exception e,如果还有就是jp
5、这个参数的名称必须和注解中的throwing相同
6、他的实际意义就是
try{
这里是目标方法执行
}catch(){
如果目标方法出现异常,则在这里执行并打印异常信息
}
2、必须指定切入点表达式
3、没有返回值
4、有参数,是Exception e,如果还有就是jp
5、这个参数的名称必须和注解中的throwing相同
6、他的实际意义就是
try{
这里是目标方法执行
}catch(){
如果目标方法出现异常,则在这里执行并打印异常信息
}
@AfterThrowing(value="execution()",throwing="e")
public void doAfterThrowing(Exception e){
e.getMsg();
}
public void doAfterThrowing(Exception e){
e.getMsg();
}
5、@After:最终通知
1、必须使用在类上
2、必须指定切入点表达式
3、没有返回值
4、没有参数,如果有就是jp
5、他的实际意义就是
try{
目标方法执行
}catch (Exception e){
如果出现异常信息,就会e.printStackTrace();
}finally{
【总是被执行】
}
2、必须指定切入点表达式
3、没有返回值
4、没有参数,如果有就是jp
5、他的实际意义就是
try{
目标方法执行
}catch (Exception e){
如果出现异常信息,就会e.printStackTrace();
}finally{
【总是被执行】
}
@After(value="execution()")
public void doAfter(){
}
public void doAfter(){
}
6、@Pointcut:切入点表达式管理的注解
就是省力了,如果有多个一样的切入点表达式
直接就用那个别名了
就是省力了,如果有多个一样的切入点表达式
直接就用那个别名了
1、使用注解@Pointcut,来对切入点表达式进行定义和管理
2、出现在方法的上面
- 这个方法没有返回值
- 这个方法的方法体没有代码
- 这个方法没有参数
3、这个方法的方法名就是这个定义的切入点表达式的别名
使用的语法规则:
@Pointcut(value="execution(表达式)")
private void mypt(){
}
因为这个表达式一般都是在本类中进行使用,因此定义为private
并且,这个方法名mybt就是这个表达式的别名
2、出现在方法的上面
- 这个方法没有返回值
- 这个方法的方法体没有代码
- 这个方法没有参数
3、这个方法的方法名就是这个定义的切入点表达式的别名
使用的语法规则:
@Pointcut(value="execution(表达式)")
private void mypt(){
}
因为这个表达式一般都是在本类中进行使用,因此定义为private
并且,这个方法名mybt就是这个表达式的别名
4、cglib动态代理的实现
1、spring已经集成了cglib代理
2、cglib代理不需要接口就能实现,底层原理是通过集成
3、如果没有使用接口,底层创建代理对象使用的就是cglib
4。如果使用接口也可以使用cglib,需要在配置文件中进行设置
<aop:aspectj-autoproxy proxy-target-class="true" />
spring-mybatis整合开发
1、spring整合mybatis的想法
就是spring框架使用ioc技术将mybatis的对象交给spring来进行统一创建和管理
例如:service对象,dao对象,工具类对象,控制层对象
2、开发步骤
1、在maven中加入依赖
1、加入spring依赖
2、加入mybatis依赖
3、加入mysql驱动依赖
4、加入单元测试junit依赖
5、加入spring事务处理的依赖
6、加入druid连接池的依赖
7、加入spring和mybatis集成的依赖
8、加入pagehelper分页依赖
需要在mybatis配置文件中加入插件信息
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor" />
</plugins>
2、加入mybatis依赖
3、加入mysql驱动依赖
4、加入单元测试junit依赖
5、加入spring事务处理的依赖
6、加入druid连接池的依赖
7、加入spring和mybatis集成的依赖
8、加入pagehelper分页依赖
需要在mybatis配置文件中加入插件信息
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor" />
</plugins>
2、创建实体类
3、创建dao接口
4、编写sql映射文件(mapper文件),也就是每个数据库dao对应的xml配置文件
5、编写mybatis主配置文件
6、编写service及其实现类
7、创建spring配置文件,将mybatis中需要的对象交给spring容器管理
1、dataSource数据源对象
就是数据库连接池:druid
<!-- dataSource数据库连接池,我是用的是druid -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc_url}"/>
<property name="username" value="${jdbc_user}"/>
<property name="password" value="${jdbc_pwd}"/>
<property name="maxActive" value="${jdbc_max}"/>
</bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc_url}"/>
<property name="username" value="${jdbc_user}"/>
<property name="password" value="${jdbc_pwd}"/>
<property name="maxActive" value="${jdbc_max}"/>
</bean>
2、mybatis主配置文件加载的SqlSessionFactoryBean对象
就是sqlSessionFactory
<!-- 创建SqlSessionFactoryBean对象 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis.xml"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis.xml"/>
</bean>
3、dao对象,就是数据库操作类的实现类,这里使用的还是代理类的形式
<!--将所有的dao代理对象都创建出来-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.javase.dao"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.javase.dao"/>
</bean>
4、创建service业务处理
8、创建测试类,获取service对象,通过service调用dao完成数据的处理
3、spring整合的mybatis的事务是自动提交的
4、关于spring配置文件中读取属性配置文件
<context:property-placeholder location="classpath:student.properties"/>
spring-事务处理机制
1、什么是事务?
是指在一个业务中(一个业务划分的最小单元),涉及到多张表,或者是多条DML语句共同参与,并且要求这几条DML语句同时成功,或者同时失败,才能完成业务逻辑。那么几条DML语句捆绑执行,同时成功同时失败,这个整体就是一个事务,比如银行转账,必须两个账户的余额更新同时成功或者同时失败
2、以前怎么处理事务?
1、JDBC中,使用conn连接处理事务,使用的是conn.commit(),或者是conn.rollback()
2、Mybatis中,使用sqlSession处理事务,sqlSession.commit() , sqlSession.rollback()
3、在hibernate中,使用Hibernate.commit() , Hibernate.rollback()处理事务
3、不足之处?
每一种数据库访问技术都有自己的一个事务的处理方式,没有一个统一的规范化,不利于开发
4、spring处理事务有什么优点?
优点:spring将各种不同类型的数据访问技术都集成了,提供了一个事务的统一模型
即使是不同类型的数据访问技术,也可以使用这个步骤
即使是不同类型的数据访问技术,也可以使用这个步骤
5、spring怎么处理事务?
1、spring使用事务管理器机制,使用事务管理器对象完成事务的提交和回滚
2、事务管理器是由接口和他的众多实现类构成的
3、 接口:PlatformTransactionManager,定义了事务的重要方法,commit和rollback
实现类:spring把每种数据库访问技术的对应的事务处理的实现类都定义好了
mybatis访问数据库 ---> DataSourceTransactionManager
hibernate访问数据库 ---> HibernateTransactionManager
实现类:spring把每种数据库访问技术的对应的事务处理的实现类都定义好了
mybatis访问数据库 ---> DataSourceTransactionManager
hibernate访问数据库 ---> HibernateTransactionManager
6、spring怎么使用事务?
1、告诉spring,你需要使用哪种数据库访问技术
2、在spring配置文件中声明这个类型,就是对应的事务的管理器对象的实现类
Mybatis <bean id="transactionManager" class="DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<property name="dataSource" ref="dataSource" />
</bean>
7、事务有哪些处理机制,哪些事务类型
事务的属性
1、事务的隔离级别
1、DEFAULT:spring默认的隔离级别,读已提交
默认的
2、READUNCOMMIT:读未提交(脏读)
3、READCOMMIT:读已提交
4、REPEARABLE_READ:可重复读
5、SERIALIZABLE:序列化读
2、事务的传播行为
1、propagation_required
如果已经有事务,则使用当前事务,如果当前没有事务,会新建事务
默认的
2、propagation_supports
当前方法支持事务,就是有事务可以,没有事务也可以,支持:supports
3、propagation_requires_new
当前方法必须有事务,及时他在的这个方法已经有事务,这个事务必须挂起,等待当前的事务
4、propagation_mandatory
你要调用我,你必须有事务,没有事务就报错
支持当前事务;如果不存在当前事务,则抛出异常。
支持当前事务;如果不存在当前事务,则抛出异常。
5、propagation_nested
如果存在当前事务,则在嵌套事务中执行,行为如下propagation_required不然的话。
6、propagation_never
不支持当前事务;如果存在当前事务,则抛出异常。
7、propagation_not_supported
不支持当前事务,而是始终以非事务方式执行。
3、事务的超时时长
timeout
- 就是指当前事务执行的最大时间,如果超过了这个时间,事务就会回滚
- 一般都是不设置的,单位是s(秒)
TIMEOUT_DEFAULT
使用基础事务系统的默认超时,如果不支持超时,则不使用。
- 一般都是不设置的,单位是s(秒)
TIMEOUT_DEFAULT
使用基础事务系统的默认超时,如果不支持超时,则不使用。
默认
8、使用注解的方式进行事务的处理
1、注解方式是spring自带的事务处理的方式,适合中小型项目
2、使用spring注解控制事务的步骤
1、声明事务管理器对象
<bean id="transactionManager" class="DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<property name="dataSource" ref="dataSource" />
</bean>
- 创建事务管理器对象
- 声明使用哪种数据库的数据源
- 声明使用哪种数据库的数据源
2、告诉spring我们将使用注解的形式进行事务的控制
<!--开启注解的驱动,就是告诉spring,我们要使用注解的形式进行事务的控制-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
- 声明注解式开发
- 指定事务管理器对象
- 切记这里是
tx:annotation-driven
- 指定事务管理器对象
- 切记这里是
tx:annotation-driven
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
3、使用注解进行事务控制
1、使用@Transactional注解进行开发
2、这个注解一般都是出现在方法上,就是需要控制事务的那个类,一般不在类上,因为不是所有的方法都需要进行事务的控制
3、@Transactional的属性
1、Propagation(事务的传播方式) -----> Propagation.REQUIRED
2、isolation(事务的隔离级别) -----> Isolation.DEFAULT
3、readOnly(数据库信息是否只读,这个针对于查询,提高效率) -----> false
4、timeout(处理事务的超时时间) -----> -1
5、rollbackFor(指定需要回滚的异常类,是Class[]数组) ----->
6、rollbackForClassName(指定需要回滚的异常类类名) ----->
7、noRollbackFor:指定不需要回滚的异常类。
8、noRollbackForClassName:指定不需要回滚的异常类类名。类型为 String[],
4、底层实现原理
环绕通知实现
@Around()
public Object doAfter(ProceedingJoinPoint pjp){
spring开启事务
try{
pjp.目标方法执行()
spring提价事务
} catch ( Exception e ) {
spring回滚事务
}finally{
spring关闭事务
}
}
public Object doAfter(ProceedingJoinPoint pjp){
spring开启事务
try{
pjp.目标方法执行()
spring提价事务
} catch ( Exception e ) {
spring回滚事务
}finally{
spring关闭事务
}
}
9、使用aspectJ的aop进行事务的处理
1、使用aspectJ框架进行事务的处理,适合于中大型项目的开发
2、开发步骤
1、加入新的依赖,使用aspectJ依赖
新加入 aspectj 的依赖坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
2、创建事务管理器对象,告诉spring我们使用的是那种数据库访问技术
<bean id="transactionManager" class="DataSourceTransactionManager">
<properties name="dataSource" ref="dataSource" />
</bean>
<properties name="dataSource" ref="dataSource" />
</bean>
3、配置事务通知(就是事务的属性,就是那个注解中的相关参数-->@Transactional(参数信息))
1、通知某个方法使用哪种事务的处理方式(隔离级别,传播行为,超时时间等)
2、id:id是自定义的
3、transaction-manager:事务管理器对象,使用使用上面定义的管理器对象
4、<tx:attributes>:就是设置事务的属性
5、<tx:method name="buy":就是针对某个或者某些方法
6、rollback-for:这个抛出异常必须是全限定名称
<tx:advice id="buyAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="buy"
propagation="REQUIRED"
isolation="DEFAULT"
read-only="false"
rollback-for="java.lang.NullPointerException,
com.javase.execption.NotStockExecption"
/>
</tx:attributes>
</tx:advice>
<tx:attributes>
<tx:method name="buy"
propagation="REQUIRED"
isolation="DEFAULT"
read-only="false"
rollback-for="java.lang.NullPointerException,
com.javase.execption.NotStockExecption"
/>
</tx:attributes>
</tx:advice>
4、配置增强器
1、上面的事务已经设置完毕,那么这个事务到底是针对于那个方法?那个类中中的方法?
2、需要配置一个增强器:就是指定你配置好的那个事务,到底是给谁用的
3、这个地方需要配置一个aop
<aop:config>
<!--切入点表达式,指定位置-->
<aop:pointcut id="servicept" expression="execution(* *..service..*.*(..))"/>
<!--声明增强器,将切入点表达式和上面声明的事务连接起来-->
<aop:advisor advice-ref="buyAdvice" pointcut-ref="servicept"/>
</aop:config>
<!--切入点表达式,指定位置-->
<aop:pointcut id="servicept" expression="execution(* *..service..*.*(..))"/>
<!--声明增强器,将切入点表达式和上面声明的事务连接起来-->
<aop:advisor advice-ref="buyAdvice" pointcut-ref="servicept"/>
</aop:config>
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
spring-web开发部署
1、环境配置
1、使用模板创建项目,webapp项目
2、增加目录,java,resource等标准的web开发目录结构
3、配置pom文件添加对应依赖
1、自动添加了junit单元测试依赖
2、添加spring-context框架依赖
3、添加spring-tx,事务处理依赖
4、添加spring-jdb,事务处理依赖
5、添加mybatis依赖
6、添加spring-mybatis集成依赖
7、添加mysql驱动依赖
8、添加druid数据库连接池依赖
9、添加aspectJ处理事务的依赖
10、添加java.servlet-api依赖
11 、添加jsp-api依赖
12、添加github中的分页处理工具依赖
13、添加获取spring容器的web依赖
<!-- 用来获取spring容器对象的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
2、业务处理,三层架构配置
4、编写实体类
5、编写dao接口及mapper文件
6、配置mybatis主配置文件
7、编写service及其实现类
8、编写spring配置文件,将对象交给spring容器进行管理
9、创建controller控制层servlet,进行控制层操作
3、spring容器对象的获取的方法
配置spring配置文件的位置,可以被ContextLoaderListener读取到
XML文件中配置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
1、直接获取
String key = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
// WebApplicationContext ac = (WebApplicationContext) this.getServletContext().getAttribute(key);
// WebApplicationContext ac = (WebApplicationContext) this.getServletContext().getAttribute(key);
2、通过WebApplicationContextUtils工具进行获取
WebApplicationContext ac = WebApplicationContextUtils.getRequiredWebApplicationContext(this.getServletContext());
0 条评论
下一页