1、Spring
1.1、简介
- Spring
- Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架
- 目的
- 解决企业级应用开发的复杂性
- 功能
- 使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
- 范围
- 任何Java应用
- 理念
- 使现有技术更加容易使用
- SSM Struct2 + Spring + Hibernate
- SSH SpringMvc + Spring + Mybatis
1.2、Spring优点
- Spring是一个开源的免费的框架(容器)
- Spring是一个轻量级的、非入侵式的框架
- 控制反转(IOC), 面向切面编程(AOP)
- 支持事务的处理,对框架整合的支持
Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架
1.3、拓展
- Spring Boot
- 一个快速开发的脚手架
- 基于SpringBoot可以快速的开发单个微服务
- 约定大于配置
- Spring Cloud
- Spring Cloud是基于SpringBoot实现的
- 弊端
- Spring发展了太久之后,违背了原来的理念,配置十分繁琐 ,人称"配置地狱"
2、IOC
-
IOC本质
- 控制反转是一种设计思想,DI是实现IOC的一种方法.没有IOC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建有程序自己控制,控制反转后将对象的创建转移给第三方
- 获得对象的方式反转了
- IOC是Spring框架的核心内容,使用多种方式完美的实现了IOC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IOC
- Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对啊ing存入容器,程序使用时再从IOC容器中取出需要的对象
- 所谓IOC就是Spring进行创建,管理,装配
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式.在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入(DI)
3、IOC创建Bean方式
3.1、无参构造(默认)
3.2、有参构造
-
通过参数下标创建
<bean id="user" class="com.pojo.User"> <constructor-arg index="0" value="123"/> <constructor-arg index="1" value="lalala"/> </bean>
-
通过类型创建(不建议使用,假设两个参数类型相同就会拉跨)
<bean id="user" class="com.pojo.User"> <constructor-arg type="java.lang.Integer" value="123"/> <constructor-arg type="java.lang.String" value="asd"/> </bean>
-
通过参数名创建
<bean id="user" class="com.pojo.User"> <property name="id" value="123"/> <property name="name" value="lilili"/> </bean>
在配置文件加载的时候,容器中管理的对象就已经初始化了
4、Spring配置
4.1、alias
别名
<alias name="user" alias="lalal"/>
User user = (User) context.getBean("lalal");
4.2、bean
-
id
- bean的唯一标识符
-
class
- bean对象所对应的全限定名: 包名 + 类名
-
name
- 也是别名,而且name可以起多个 (多个类名之间使用空格,逗号,分号分隔)
4.3、import
- 一般用于团队开发使用,可以将多个配置文件导入,合并为一个 (内容相同只会调用其中一个)
5、DI依赖注入
6.1、构造器注入
- 详见3
6.2、setter注入(重点)
-
依赖注入
- 依赖 bean对象的创建依赖于容器
- 注入 bean对象中的所有属性,由容器来注入
-
普通值注入
<bean id="user" class="com.pojo.User"> <property name="name" value="China"/> </bean>
-
Bean注入
<bean id="address" class="com.pojo.Address"> <property name="address" value="Center"/> </bean> <bean id="user" class="com.pojo.User"> <property name="address" ref="address"/> </bean>
-
数组类型注入
<bean id="user" class="com.pojo.User"> <property name="books"> <array> <value>《aaa》</value> <value>《bbb》</value> </array> </property> </bean>
-
List类型注入
<bean id="user" class="com.pojo.User"> <property name="hobbys"> <list> <value>qq</value> <value>ww</value> <value>eee</value> </list> </property></bean>
-
Set类型注入
<bean id="user" class="com.pojo.User"> <property name="games"> <set> <value>丝绸之路经济带</value> <value>21世纪海上丝绸之路</value> </set> </property></bean>
-
Map类型注入
<bean id="user" class="com.pojo.User"> <property name="card"> <map> <entry key="idCard" value="123456789"/> <entry key="bankCard" value="987654321"/> </map> </property></bean>
-
NULL注入
<bean id="user" class="com.pojo.User"> <property name="wife"> <null/> </property></bean>
-
Properties配置注入
<bean id="user" class="com.pojo.User"> <property name="info"> <props> <prop key="领土">960万平方公里</prop> <prop key="历史">上下5000年</prop> </props> </property></bean>
6.3、拓展方式注入
-
p命名空间
-
可以直接注入属性的值 (对应set注入property)
-
先在beans标签中加约束
xmlns:p="http://www.springframework.org/schema/p"
-
配置bean
<bean id="user" class="com.pojo.User" p:name="nihao"/>
-
-
c命名空间
-
必须存在有参构造器 (对应构造器注入constructor-arg)
-
现在beans标签中加约束
xmlns:c="http://www.springframework.org/schema/c"
-
配置bean
<bean id="user" class="com.pojo.User" c:_0="hi"/>
-
6.4、Bean的作用域
-
单例模式(默认机制)
-
容器只会创建一个对象,重复get的对象是同一个
<bean id="user" class="com.pojo.User" scope="singleton"> <property name="name" value="China"/> </bean>
-
-
原型模式
-
每次从容器get都会创建一个新的对象
<bean id="user" class="com.pojo.User" scope="prototype"> <property name="name" value="China"/> </bean>
-
-
其余的request、session、application、websocket只能在web开发中使用到
- request
- 将单个bean定义的范围限定为单个HTTP请求的生命周期;也就是说,每个HTTP请求都有自己的bean实例,该实例是在单个bean定义的基础上创建的。仅在可感知web的Spring ApplicationContext上下文中有效。
- session
- 将单个bean定义的范围限定为HTTP会话的生命周期。仅在可感知web的Spring ApplicationContext上下文中有效。
- application
- 将单个bean定义的范围限定为ServletContext的生命周期。仅在可感知web的Spring ApplicationContext上下文中有效。
- websocket
- 将单个bean定义的范围限定为WebSocket的生命周期。仅在可感知web的Spring ApplicationContext上下文中有效。
- request
6、Bean的自动装配
- 自动装配式Spring满足bean依赖的一种方式
- SPring会在上下文中自动寻找,并自动给bean装配属性
- 装配方式
- 在xml中显式的配置
- 在java中显式的配置
- 隐式的自动装配bean**[重要]**
6.1、byName自动装配
- 会自动在容器上下文中查找和自己对象set方法后面的值对应的beanid
<bean id="user" class="com.pojo.User" scope="prototype" autowire="byName">
<property name="name" value="China"/>
</bean>
6.2、byType自动装配
- 会自动在容器上下文中查找和自己对象属性类型相同的bean
<bean id="user" class="com.pojo.User" scope="prototype" autowire="byType">
<property name="name" value="China"/>
</bean>
- byName的时候 ,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致
- byType的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致
6.3、使用注解实现自动装配
-
注意
-
导入约束
xmlns:context="http://www.springframework.org/schema/context"
-
配置注解的支持
<context:annotation-config/>
-
@Autoired
- 通过byType方式实现
- 利用反射实现,可以去掉set方法
-
扩展
-
如果显式的定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空
@Autowired(required = false)
-
@Nullable 字段标记了这个注解,说明这个字段可以为null
-
@Qualifier(value=“xxx”) 如果有多个相同的class,可以显示的定义使用哪个bean对象注入
-
@Resource 也可以自动装配,会默认使用byName方式查找,查找不到会使用byType方式查找 是java的注解 也可以@Resource(name=“xxx”)指定名字
-
@Resource和@Autowired的区别
- 都是用来自动装配的,都可以放在属性字段上
- @Autowired通过byType的方式实现,必须要求这个对象存在 [常用]
- @Resource默认通过byName的方式实现,如果找不到名字,则会通过byType的方式实现,如果两个都找不到唯一的bean,就会报错
- 执行顺序不同
- @Autowired通过byType的方式实现
- @Resource默认通过byName的方式实现,如果找不到名字,则会通过byType的方式实现
-
7、使用注解开发
- 在Spring4之后,要使用注解开发,必须保证aop包导入
- 使用注解需要导入context约束,增加注解的支持
xml与注解
- xml更加万能,适用于任何场合!维护简单方便
- 注解 不是自己的类使用不了,维护相对复杂
xml与注解最佳实践
xml用来管理bean
注解只负责完成属性的注入
我们在使用过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持
<context:annotation-config/> <context:component-scan base-package="com.demo"/>
8、使用Java的方式配置Spring
- 我们现在要完全不使用Spring的xml配置了,全权交给Java来做
- JavaConfig是Spring的一个子项目,在Spring4之后,它成为了一个核心功能
- @Component
- 说明类被bean托管,注册到容器中
- @Configuration
- 代表这是一个配置类,就和application.xml一样
- @ComponentScan(“xxx.xxx.xxx”)
- 扫描对应包下的类,创建bean,放到容器中
- @Bean
- 注册一个Bean,相当于application.xml中的bean标签
- 这个方法的名字就是bean标签中的id属性
- 这个方法的返回值,就相当于bean标签中的class属性
- 如果使用了配置类方式去做,就只能通过AnnotationConfig上下文来获取容器,通过配置类的class对象加载
- @Import
- 代表引入一个配置类,相当于appliocation.xml中的import
- 纯Java的配置,在Spring Boot中随处可见
9、代理模式
- 为什么要学习代理模式?
- SpringAOP的底层
- 代理模式的优点
- 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务
- 公共任务交给代理角色,实现了业务的分工
- 公共业务发生扩展的时候,方便集中管理
- 代理模式的缺点
- 一个真实角色就会产生一个代理角色, 代码量会翻倍,开发效率会变低
9.1、静态代理
- 角色分析
- 抽象角色
- 一般会使用接口或者抽象类来解决
- 真实角色
- 被代理的角色
- 代理角色
- 代理真实角色,代理真实角色之后,我们一般会做一些附属操作
- 客户
- 访问代理对象的人
- 抽象角色
9.2、动态代理
- 角色分析
- 和静态代理角色一样
- 动态代理的代理类是动态生成的,不是直接写好的
- 动态代理分为两大类
- 基于接口 JDK动态代理 (默认)
- 基于类 CGLIB
- Java字节码实现 JAVAssist
- 需要了解两个类:Proxy、InvocationHandler 调用处理程序
- Proxy 生成动态代理实例
- InvocationHandler 调用处理程序并返回结果
- 动态代理的好处
- 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务
- 公共业务交给代理角色,实现了业务的分工
- 公共业务发生扩展的时候,方便集中管理
- 一个动态代理类代理的是一个接口,一般就是对应的一类业务
- 一个动态代理类可以代理多个类,只要是实现了同一个接口即可
10、AOP
10.1、什么是AOP
- AOP,面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数时编程的一种衍生范型.利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率.
10.2、AOP在Spring中的作用
提供声明式事务,允许用户自定义切面
- 横切关注点 要扩展的功能
- 切面 横切关注点被模块化的特殊对象 一个类
- 通知 切面必须要完成的工作 类中的一个方法
- 目标 被通知对象
- 代理 向目标对象应用通知之后创建的对象
- 切入点 切面通知执行的地点的定义
- 连接点 与切入点匹配的执行点
10.3、AOP实现方式
- 使用原生Spring API接口+xml 注册bean,设置通知 [springAPI接口实现]
- 使用自定义类+xml 注册bean,设置自定义类作用 [切面定义]
- 使用注解实现+xml 注册bean,开启注解支持 []
- @Aspect 标注这个类是切面
- @Before(“切入点表达式”) …
11、整合Mybatis
11.1、Mybatis-spring
- 编写数据源配置
- SqlSessionFactory
- SqlSessionTemplate
- 给接口加实现类
- 将自己写的实现类注入到Spring中
- 测试使用
11.2、SqlSessionDaoSupport
- 一个抽象的支持类,用来提供SqlSession,调用
getSqlSession()
会得到一个SqlSessionTemplate
,用于执行SQL方法
13、声明式事务
13.1、回顾事务
- ACID原则
- 原子性
- 确保要么都成功,要么都失败
- 一致性
- 一旦事务被提交,要么全部提交,要么全不提交
- 隔离性
- 多个业务可能操作同一个资源,防止数据损坏
- 持久性
- 事务一旦提交,无论系统发生什么问题,结果都不会再被影响,被永久写到存储器中
- 原子性
- 为什么需要事务?
- 如果不配置事务,可能存在
13.2、Spring中的事务
- 声明式事务 AOP
- 配置声明式事务
- 配置事务通知
- 给哪些类配置事务
- 配置事务的传播特性
- 配置事务切入
- 编程式事务 try…cath…