如何学习spring
spring理论(能听懂技术介绍,并且可以对其他人说出去)
spring基础(IoC、DI、AOP)---很重要(spring boot、spring cloud 、spring data)
spring源码(重点是帮助深入理解spring应用)
spring应用(JDBC支持、事务支持、和mybatis整合)
可以解决spring框架中暴露出的问题(调bug)
交接(spring信息同步)
Spring介绍
我们现在学习的spring,spring framework(包含了20多个模块)其中里面有web mvc模块(springmvc)
springboot 、springcloud 与 spring framework不存在包含关系。
spring提供了一站式企业应用解决方案(企业开发的一条龙服务、邮件、消息服务、开发框架)。
spring容器其实指的就是IoC容器,Ioc容器指的就是BeanFactory工厂(DefaultListableBeanFactory)。BeanFactory有一个子接口叫ApplicationContext(应用上下文接口)。
我们需要了解spring容器的初始化过程(BeanFactory是如何管理Bean的实例的,需要源码专题去解决)
IoC:控制反转,创建Bean对象的角色发送了反转,由程序员创建,反转为Spring容器创建。
DI:基于IoC的,在Bean对象创建的过程中,需要注入属性(基本属性、对象属性、集合数组属性)
-
AOP:
面向切面的编程,它只是一种aop联盟提出来的编程思想,根据这种编程思想,有很多的实现:AspectJ、Spring AOP、Spring 整合了AspectJ。
-
AOP的主要作用:横向抽取重复代码,实现代码的重用(事务、日志监控等)、AOP是为了弥补OOP的一些不足。
- 纵向抽取(继承)
- 横向抽取(AOP)
Spring 入口
所谓的spring入口,指的就是如何启动spring容器。
-
基于XML
-
java应用
ApplicationContext ctx = new ClasspathXmlApplicationContext("spring.xml");
-
web应用
web.xml
contextConfigLocation classpath:spring.xml ContextLoaderListener ContextLoaderListener监听器中,会去调用getWebApplicationContext()—>AbstractApplicationContext()
-
-
基于注解
-
java应用
ApplicationContext ctx = new AnnotationConfigApplicationContext(@Configuration配置类);
-
web应用
web.xml
contextConfigLocation @Configuration配置类 ContextLoaderListener ContextLoaderListener监听器中,会去调用getWebApplicationContext()—>AbstractApplicationContext()
getWebApplicationContext得到的默认实现类AnnotationConfigWebApplicationContext
-
IoC和DI的三种实现方式
基于XML
java代码---面向接口开发(正常编写)
-
spring xml配置文件
- IoC---bean标签 ,表示该bean交给spring容器管理
- id
- init-method 初始化方法(源码分析部分,看到该属性啥时候执行)
- destroy-method 它的值就是一个方法名称
- 数据库连接池配置的时候,一定要配置它,具体配置看bean的class类中定义的销毁方法是什么
- DI —bean标签的property子标签和constractor�-arg子标签
- ref
- value
- IoC---bean标签 ,表示该bean交给spring容器管理
基于注解和XML混合
-
java代码
- IoC注解:@Component、@Controller、@Service、@Repository
- DI注解:第一步:在IoC容器中查找指定的依赖;第二步:属性注入
- @Value(注入基本类型和String类型)
- ${xxx}
- context:property-placeholder:第一个去加载指定的properties文件、第二个就是将读取到的key/value数据,去替换spring上下文中出现的属性占位符
${xxx}
- @Autowired(byType---class类型)---spring提供的注解。
- byName—需要配合@Qualifier注解
- @Resource(默认先byName[bean的id或者name])、再byType),建议使用。它是由java提供的注解。
- @Inject(默认是byType)
- byName — @Name
- @Value(注入基本类型和String类型)
-
spring xml配置
dataSource这种第三方的Bean对应的Bean标签
-
context:component-scan:
- 开启@Autowired等几个注解的功能(BeanFactoryPostProcessor)。
- 专门开启@Autowired注解的配置 context:annotation-driven
- 扫描该应用上下文中指定包下面的IoC注解,将这些扫描到的Bean,交给spring容器进行管理。
- 开启@Autowired等几个注解的功能(BeanFactoryPostProcessor)。
基于纯注解
- 零配置:是说的没有spring xml配置文件了,有没有可能包含mybatis(映射文件)
- java代码:
- @Configuration:替代XML配置文件
- @ComponentScan:替代context:component-scan标签
- @Bean:替代bean标签的。
- @ProperySource:主要是替代context:property-placeholder标签的
- @Import:替代import标签,可以将另一个@Configuration类引入到当前配置类中
基于XML和注解方式的优缺点
注解的优势:
配置简单,维护方便(我们找到类,就相当于找到了对应的配置)。
l XML 的优势:
修改时,不用改源码。不涉及重新编译和部署。
AOP的三种实现方式
AOP原理
AOP的作用:在不修改代码的情况下,对功能进行增强(开闭原则)
预编译方式和运行时代理方式
- AspectJ是采取的预编译方式(静态织入)
- Spring AOP是采取的运行时代理方式(动态代理)
- JDK动态代理---基于接口
- CGLib动态代理---基于继承(任何一个非final类都可以被继承)
AOP术语
- 切入点:待增强的方法
- 通知(增强):日志、事务等功能
- 织入
- 切面:切入点和通知的组合
- 目标对象:表现层、业务层、持久层的相关代码。目标对象无须被修改。
- 代理:最终生成的对象。
一句话概括AOP就是:在【目标对象】中定位【切入点】,【织入】对应的【通知】,就变成了【代理对象】
基于XML(spring整合aspectJ)
目标对象(Service实现类)
编写通知类(单独的类,无须继承任何类和实现任何接口)
-
spring配置文件
-
通知类型(五种)
-
* 通知类型(五种):前置通知、后置通知、最终通知、环绕通知、异常抛出通知。
* 前置通知:
* 执行时机:目标对象方法之前执行通知
* 配置文件:
* 应用场景:方法开始时可以进行校验
* 后置通知:
* 执行时机:目标对象方法之后执行通知,有异常则不执行了
* 配置文件:
* 应用场景:可以修改方法的返回值
* 最终通知:
* 执行时机:目标对象方法之后执行通知,有没有异常都会执行
* 配置文件:
* 应用场景:例如像释放资源
* 环绕通知:
* 执行时机:目标对象方法之前和之后都会执行。
* 配置文件:
* 应用场景:事务、统计代码执行时机
* 异常抛出通知:
* 执行时机:在抛出异常后通知
* 配置文件:
* 应用场景:包装异常
-
-
切入点表达式
execution(返回值 包名.类名.方法名(参数类型))
-
基于注解和XML混合(spring整合aspectJ)
目标对象(Service实现类)
-
编写切面类
类上必须加上@Aspect(标记该类是一个AOP 切面类)、@Component(标记该类可以被组件扫描器扫描到spring容器中)
方法上需要加上@Before、@AfterReturning等五个注解,分别对应五种通知类型。
可以在一些方法上加上@PointCut注解(为了去声明一个切入点表达式),该方法可以被@Before、@AfterReturning注解使用。
-
示例:
@Component("myAspect") @Aspect public class MyAspect { private static final String pcut="execution(* *..*.*ServiceImpl.*(..))"; @Before(value="MyAspect.fn()") public void before() { System.out.println("这是注解方式的前置通知"); } @After(value="execution(* *..*.*ServiceImpl.*(..))") public void after() { System.out.println("这是注解方式的最终通知"); } @AfterReturning(pcut) public void after() { System.out.println("这是注解方式的后置通知"); } @Pointcut("execution(* *..*.*ServiceImpl.*(..))") public void fn() {} }
-
spring配置文件
基于纯注解(spring整合aspectJ)
以下代码,主要替换的就是spring配置文件
@Configuration
@ComponentScan("com.kkb.spring.aop")
@EnableAspectJAutoProxy
public class SpringConfiguration{
}
Spring整合Junit
为Springmvc的MockMVC做铺垫
-
junit是专门实现单元测试的
单元测试,主要测试的是业务逻辑。
-
编写spring单元测试代码遇到的问题
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml"); UserService service1 = context.getBean(UserService.class);
以上代码每一个单元测试代码都要编写,但是它又和我们要测试的业务逻辑,没有关系。
解决思路:Junit是通过@RunWith注解,让我们制定一个自定义的运行器(spring已经实现)去运行单元测试代码。
-
示例
@RunWith(SpringJunit4ClassRunner.class) //加载XML配置文件的写法 @ContextConfiguration(locations="classpath:spring.xml") //加载Java配置类的写法 //@ContextConfiguration(classes=SpringConfiguration.class) public class TestSpring{ @Resource private UserService service; @Test public void testAop(){ service.saveUser(); } }
Spring应用之JDBC实现
模板模式:将模板化的代码,抽象为一个抽象类,然后定义一个或多个abstract方法待子类去实现。
持久层的相关框架(封装了JDBC):
- mybatis:和spring整合需要第三方中间整合包(mybatis)
- ibatis
- hibernate
- spring JDBC:本来就是spring的模块,无需和spring整合。
- JdbcTemplate:模板类,主要就是通过该类实现增删改查。
- DBUtils
示例代码:
@Test
public void run1(){
// 创建连接池,先使用Spring框架内置的连接池
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///spring");
dataSource.setUsername("root");
dataSource.setPassword("root");
// 创建模板类
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
// 完成数据的添加
jdbcTemplate.update("insert into account values (null,?,?)", "测试",10000);
}
- JdbcDaoSupport
- 封装了JdbcTemplate
- 继承了该类,则不需要在spring配置文件中,注入JdbcTemplate对象了。
spring应用之事务支持
(看源码--分析事务是如何实现的并且深刻理解AOP的功能)
事务
-
Spring事务:只是做了事务管理。
Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。 Spring事务管理器的接口是PlatformTransactionManager,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。
jdbc事务
-
MySQL事务:讲解MySQL的时候会去详细介绍(redo日志、undo日志)
总结:事务最终都是由数据库本身去实现的。
事务的四大特性
ACID的理解:
-
A:原子性
操作不可分割,要么都成功、要么都失败。
-
C:一致性
账户A(600元)和账户B(400元)总共有1000块钱。
账户A(600元)给账户B(400元)转账200元,最终的结果不管是成功还是失败,A和B的总额还是1000元。
-
I:隔离性(由锁机制实现的。会引起并发访问问题)
为了保证A事务和B事务之间操作是互不影响。
- D:持久性:将结果保存到数据库文件中。
事务并发问题
隔离性不好会引起事务并发问题。
- 更新丢失
- 脏读:A事务读到了B事务未提交的数据。
- 不可重复读:A事务两次读取同一行记录,显示的结果不一致。原因是两次读取期间,B事务对该记录进行了更新操作。
- 幻读:A事务两次读取同一张表,显示的结果条数不一致。原因是两次读取期间,B事务对该表进行了增加和删除操作。
SQL92标准提出了四种隔离级别:
① Read uncommitted (读未提交):最低级别,任何情况都无法保证。
② Read committed (读已提交):可避免脏读的发生。
③ Repeatable read (可重复读):可避免脏读、不可重复读的发生。(注意事项:MySQL在该级别的时候,就可以将幻读给解决掉)
④ Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
MySQL数据库的默认隔离级别是Repeatable Read。
注意事项:
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
spring两种事务实现
spring有两种事务实现方式:编程式事务(不推荐使用)、声明式事务。
spring声明式事务
XML方式
-
spring配置文件
混合方式
由同学们自己去实现
纯注解方式
由同学们自己去实现
Spring和Mybatis整合
需求
查询account表的记录
整合思路
需要整合的,就是项目中的对象(这些对象都要被spring管理)
-
分析有哪些对象需要被spring管理(确定是XML方式还是纯注解方式来管理)
- 业务层
- 实现类(多个)
- 事务相关的对象
- 事务管理器
- 通知类
- 切面类
- 持久层(mybatis)
- 数据源(一个)
- SqlSessionFactory对象(一个)
- Mapper代理对象(多个)
- 业务层
-
配置spring文件(分模块配置思想---便于维护)
-
持久层---一个spring配置文件
-
业务层
- 业务类---一个spring配置文件
- 事务类---一个spring配置文件
将所有spring配置文件整合到一起(方式有多种,具体有哪些??????)
-
-
问题:
- 不知道加哪些依赖?只需要添加最基本的依赖,保证程序不报错即可。