一.什么是spring
1.简介:Spring是一个开源的设计层面框架,解决了类与类之间的彻底解耦,它将面向接口的编程思想贯穿整个系统应用。
2.spring核心:
IOC(Inverse of Control 控制反转
):将bean的创建权和引用权(DI(依赖注入))交给 spring容器。容器中的bean安不安全与spring没有关系,spring并没有对容器中的bean做处理,安全性取决于bean本身。
AOP(Aspect Oriented Programming 面向切面编程
):对共同的连接点进行切面。
3.实际开发三层架构:
表现层(controller):提供了与Spring MVC等框架的整合;
业务层(service):可以管理事务、记录日志等;
持久层(dao):提供了与Mybatis、Hibernate等框架的整合。
二.spring IOC XML入门
1.使用xml对简单数据类型引用
导入spring依赖
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.10.RELEASE</version></dependency>
</dependencies>
先创建一个pojo模板类
在resources下新建一个applicationContext.xml文件
(1)空参构造创建对象
这种方式,容器通过无参构造创建对象,name="name"通过Book对象中的setter方法设置值。
也可以通过p空间命名方法赋值
测试,获取bean的三种方式:
结果:
-----false
-----《射雕英雄传》
(2)也可以通过有参构造创建对象,并对属性赋值
按构造方法的参数一一对应进行赋值
按参数类型进行赋值
按参数位置进行赋值
2.使用xml对引用数据类型引用(ref)
先创建一个类BookDaoImpl
再创建一个BookServiceImpl类,含有BookDao的引用,并有setter方法
xml配置两个类
测试:
结果:
book save
3.使用xml对引用数据类型的自动装配
按类型,ioc容器中被装配的对象只能有一个,不然会报错。
按名称装配,BookServiceImpl中的引用必须要有这个引用的setter方法。
4. 使用xml工厂创建对象
(1)静态工厂
(2) 实例工厂创建对象
(3)动态工厂创建对象
4. 使用xml创建集合成员属性的对象
先创建一个pojo模板对象
配置xml
5. 使用xml创建数据库连接池
resources创建jdbc.properties
三.获取容器的几种方式
1.ApplicationContext 应用上下文容器取(从类路径中加载) :
new ClassPathXmlApplicationContext("bean1.xml", "bean2.xml");
new ClassPathXmlApplicationContext("applicationContext.xml");
但要注意bean的生命周期要为singleton,也就是说,不管没有getBean(), 使用上下文容器获取bean,就会实例化该bean。
2. ApplicationContext (从文件系统中加载):
new FileSystemXmlApplicationContext("D:\\applicationContext.xml");
文件路径为绝对路径,且注意使用转义符,直接使用“C:\sjt\idea\code\spring\springinterface\src”, 会报错,需要将“\”转义。
3.XmlWebApplicationContext (从web系统中加载):在tomcat启动时就会加载,此处不做说明,在web应用中说明。
4.AnnotationConfigApplicationContext:
new AnnotationConfigApplicationContext(Spring_Config.class)是通过注解加载到,下面会讲解
5.使用bean工厂:
new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
spring-config.xml文件中配置的bean不会被实例化,即光实例化容器,并不会实例化bean 而是在执行以下代码时才会被实例化,即使用bean的时候。
四.spring ioc注解入门
一.spring注解介绍(简化xml麻烦的配置):
1.@Component :没有指定名称的时候,默认名称是bean名称的首字母小写名称。
2.@Component衍生出三个注解,就是为了区分三层架构。
(1)@Controller:用于表现层bean定义。
(2)@Service:用于业务层bean定义。
(3)@Repository:用于数据层bean定义。
3.@Autowired:用于注入对象。
注意1:自动装配基于反射设计创建对象并暴力反射对应属性为 私有属性初始化数据,因此无需提供setter方法。 注意2:自动装配建议使用无参构造方法创建对象(默认),如果不提供对应构造方法,请提供唯一的构造方法。
4.@Qualifier:
使用@Qualifier注解开启指定名称@Component("bookDao")装配bean: 用于多态 @Qualifier("bookDao") 注意:@Qualifier注解无法单独使用,必须配合@Autowired注解使用。
5.@Value:用于对简单数据类型引用进行赋值。
6.@Bean:提供一个获取管理对象的方法,并声明bean,@Bean修饰的方法形参根据类型自动装配。
7.@Configuration:用于声明是一个配置类。
8.@ComponentScan({"com.dengzhihong"}):扫描包下的注解。
9.@PropertySource({"classpath:jdbc.properties"}):声明文件数据源。
10.@Import({jdbcConfig.class,MybatisConfig.class}):用于导入其他配置类,一般在spring-config,spring容器配置类中导入其他配置类。
五.代码具体演示
这里暂不使用springMvc容器。
导入pom依赖
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.9.RELEASE</version></dependency><dependency><groupId>javax.annotation</groupId><artifactId>javax.annotation-api</artifactId><version>1.3.2</version><scope>compile</scope></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.12</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.46</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.1</version></dependency><!--spring整合mybatis--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.9.RELEASE</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.5</version></dependency>
一.jdbcConfig配置类,由spring容器创建数据类连接池对象:
二.MybatisConfig配置类,由spring容器创建SQLSessionFactoryBean对象:
三.Spring_Config配置类,Spring容器入口:
四.jdbc.properties文件
五.dao层
@AutoWired对 bookMapper引用自动装配mapper接口对象。
六.mapper接口
七.pojo模板对象,省略setter和getting方法
八.service层对象
测试:
结果:
BookDaonull
null
BookDao我是dao
jdbc:mysql://localhost:3306/springdb
BookService
BookDao我是dao
jdbc:mysql://localhost:3306/springdb
相信大家对,ioc容器自动装配有了一定的了解了,你的引用不需要再new了,由spring容器通过@AutoWired标识,自动从容器中装配。
六.AOP面向切面编程
一.什么是面向切面编程呢?
-
AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构。
-
作用:在不惊动原始设计的基础上为其进行功能增强。简单的说就是在不改变方法源代码的基础上对方法进行功能增强。
-
Spring理念:无入侵式/无侵入式。
-
实现:AOP运用的是动态代理模式。
aop简介:
-
连接点(JoinPoint):正在执行的方法,例如:select()、delete()、show()等都是连接点。
-
切入点(Pointcut):进行功能增强了的方法,例如:delete()方法,select(),show()方法没有被增强所以不是切入点,但是是连接点。
-
在SpringAOP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
-
一个具体方法:com.dengzhihong.AOP.dao包下的BookDao接口中的无形参无返回值的delete()方法
-
匹配多个方法:需要设置切入点表达式,由 *或..和+占位符表示。
-
-
-
通知(Advice):在切入点前后执行的操作,也就是增强的共性功能
-
在SpringAOP中,功能最终以方法的形式呈现
-
-
通知类:通知方法所在的类叫做通知类
-
切面(Aspect):描述通知与切入点的对应关系,也就是哪些通知方法对应哪些切入点方法。
二.规则则:
设置切入点:
1.描述切入点通常描述接口,而不描述实现类
2.访问控制修饰符针对接口开发均采用public描述(可省略 )
3.包名书写尽量不使用..匹配,效率低,常用*做单个包描述匹配,或精准匹配
4.返回值类型对于增删改类使用精准类型加速匹配,对于查询类使用*通配快速描述
5.接口名/类名书写名称与模块相关的采用*匹配,例如UserService书写成*Service,绑定业 务层接口名
6.通常不使用异常作为匹配规则
三. 切入点表达式:
1、 *:单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现 execution(public * com.itheima.*.UserService.find*(*))
2、 .. :多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写 execution(public User com..UserService.findById(..))
3、+:专用于匹配子类类型 execution(* *..*Service+.*(..))
四.由下列方式来定义或者通过 &&、 ||、 !、 的方式进行组合:
- execution:用于匹配方法执行的连接点;
- within:用于匹配指定类型内的方法执行;
- this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;
- target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;
- args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;
- @within:用于匹配所以持有指定注解类型内的方法;
- @target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
- @args:用于匹配当前执行的方法传入的参数持有指定注解的执行;
- @annotation:用于匹配当前执行方法持有指定注解的方法;
七.AOP入门案例
一.在spring容器配置类中开启aop功能
二.创建一个BookDao接口及其实现类BookDaoImpl
三.创建通知类BookAdvice,并在类上注解@Component ,设置切面类 @Aspect
前置通知:在切入点方法执行之前执行
测试:
结果:
我是前置通知
delete
三.后置通知:在切入点方法执行之后执行,无论切入点方法内部是否出现异常,后置通知都会执行。
四.环绕通知(重要)
五.带返回值的通知
连接点:
通知类:
测试:
结果:
接口全类名interface com.dengzhihong.AOP.dao.BookDao 方法名:select
aroundSelect前环绕
select
aroundSelect后环绕
110
六.返回值后通知:在切入点方法执行之后执行,如果切入点方法内部出现异常将不会执行。
注意:JoinPoint参数必须在第一,否则会报错。
结果:
select
afterReturning advice ...10 [10]
七.异常后通知:在切入点方法执行之后执行,只有当切入点方法内部出现异常之后才执行。
八.通知类初始化bean
1. Spring容器启动
2. 读取所有切面配置中的切入点
3. 初始化bean,判定bean对应的类中的方法是否匹配到任意切入点 - 匹配失败,创建原始对象 - 匹配成功,创建原始对象(目标对象)的代理对象
4. 获取bean执行方法 - 获取的bean是原始对象时,调用方法并执行,完成操作 - 获取的bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作
测试:
结果:
com.dengzhihong.AOP.dao.impl.BookDaoImpl@53f6fd09
class com.sun.proxy.$Proxy24
由此可知,连接点的执行实际上是通过他的代理类执行的,底层是动态代理。
目标对象(Target):被代理的对象,也叫原始对象,该对象中的方法没有任何功能增强。
代理对象(Proxy):代理后生成的对象,由Spring帮我们创建代理对象。
八.事务@Transactional注解
事务的作用:
1.一般事务:在数据层保障一系列的数据库操作同成功同失败 。
2.spring事务:在数据层或业务层保障一系列的数据库操作同成功同失败。
3.事务最好还是配置在业务层,只有配置在业务层,才会出异常时,自动回滚
4.配置在dao层的话,只是数据库操作时异常会回滚
5.配置到web层的话,也可以,但是引起异常的情况就更多,除非安全性特别高。而且controller层只支持注解式的事务
直接上代码:
一.Spring整合Mybatis相关代码(依赖、MybatisConfig)省略。
二.设置事务管理器transactionManager(将事务管理器添加到IOC容器中)
三.开启注解式事务驱动
四.在service层接口处添加事务注解
注意:
-
Spring注解式事务通常添加在业务层接口中而不会添加到业务层实现类中,降低耦合
-
注解式事务可以添加到业务方法上表示当前方法开启事务,也可以添加到接口上表示当前接口所有方法开启事务
五.mapper接口
六.service接口实现类
测试A给B转100块:
数据库表
结果 :
出现异常:Exception in thread "main" java.lang.ArithmeticException: / by zero
事务回滚,账号不变。
九.事务的传播行为
一.什么是事务的传播行为:在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。
方法必须是public修饰符,否则注解不会生效。
在TransactionDefinition定义传播行为的常量:
1.TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
2.TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
3.TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
4.TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
5.TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
6.TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
7.TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于第1条。
例子:
在transfer()方法中开启了事务(接口中),那么方法内的UserMapper.outMoney()和UserMapper.InMoney(),log()方法就会加入到transfer()方法事务中,三个方法要么同时成功,要么同时失败。
我们希望log()方法也加入到两个转钱方法中,那么需要开启一条新事务。
这样就
二.Spring事务的回滚机制:
1.Spring的AOP即声明式事务管理默认是针对unchecked exception回滚。如果一个方法,不仅作为切点添加了异常切面,而且还添加了事务,那么当这个方法抛出异常时,总是切面先捕获到异常,并且吞掉了这个异常。而事务是捕获不到这个异常的,因此事务是不生效的。
2.Spring的事务边界是在调用业务方法之前开始的,业务方法执行完毕之后来执行commit or rollback(Spring默认取决于是否抛出runtimeException)。
3.如果你在方法中有try{}catch(Exception e){}处理,那么try里面的代码块就脱离了事务的管理,若要事务生效需要在catch中throw new RuntimeException ("xxx")。
4.对于RuntimeException类型异常或者Error错误,Spring事务能够进行回滚操作。但是对于编译器异常,Spring事务是不进行回滚的,所以需要使用rollbackFor来设置要回滚的异常。
十.bean的生命周期
这张图是我拿大佬的,读书人只能说是拿(滑稽保命)
大佬的Spring bean生命周期