Spring&SpringBoot
Spring
什么是Spring?
spring框架是一个轻量化的java开发框架,它的目的在于帮助开发者提高开发效率,减轻开发负担,使用spring框架也有助于项目代码的维护。Spring有两大特性,分别是IOC和AOP。
Spring的优缺点?
优点:
(1)方便解耦,简化开发
通过Spring提供的IOC容器,我们可以将对象之间的依赖交给IOC容器进行维护,简化了代码也降低了耦合。
(2)支持面向切面编程,提高代码的复用性
通过Spring提供的AOP功能,可以进行面向切面编程,将具有共同特征的业务逻辑进行封装,然后给需要用到的方法进行动态增强。比如权限校验,监控等功能。
(3)spring整合了Junit,方便开发者进行单元测试。
缺点:
(1)spring内部使用了反射,对性能有影响
(2)对于初学者,学习成本较大,掌握整体框架慢
Spring框架有哪些核心模块?
IOC,AOP,数据库模块(JDBC,ORM,事务),web模块,单元测试
IOC
一、什么是控制反转IOC?
控制反转(IOC)是指spring框架可以帮我们创建管理对象,同时也可以帮我们管理对象之间的依赖关系。IOC还指spring框架中的一系列IOC容器,比如BeanFactory、ApplicationContext容器等。
参考资料
二、为什么要使用IOC?
1、在没有使用IOC的时候,如果对象A的创建依赖对象B,那么在创建对象A的时候,需要先创建好对象B,然后再将对象B给到对象A,最后完成对象A的创建。如果对象的创建依赖别的对象,层次很深的时候,收到创建对象再去注入,要会非常麻烦,也导致代码难维护。
2、使用IOC容器后,可以提前把需要的对象配置在xml文件中,IOC容器就会帮我们处理好对象之间的依赖关系。这样就将控制器交给了IOC容器,也降低了系统的耦合性。
二、Spring对象的创建过程
三、Spring 对象的生命周期
和cjlib动态代理)(基于继承),aop使用的是cjlib动态代理模式。目前市面上有spring aop和aspectJ两种aop技术
2、谈谈aop的实现原理
(1)Spring Aop
spring aop使用了jdk动态代理和cjlib动态代理,所以是在运行时期增强,当被代理的类有实现接口时,使用jdk动态代理,当被代理的类没有实现接口时,使用cjlib动态代理。cjlib动态代理的原理是创建一个继承被代理类的子类,因为是使用的继承,所以都被代理类使用的是final修饰类或者使用final修饰了方法,那么使用final修饰的类和方法将不能被代理或增强。
(2)AspectJ
AspectJ使用的是静态代理模式,所以它是在编译时期就对方法进行了增强。在性能上AspectJ要好于SpringAop。
3、Spring 事务
(1)编程式和声明式
编程式
编程式一般使用TransactionTemplate管理事务,代码如下:
@Autowired
private TransactionTemplate transactionTemplate;
public void test(){
transactionTemplate.excute(new TransactionCallbackWithoutResult(){
@Override
protected void doInTransactionWithoutResult(TransactionStatus ts){
try{
// 业务代码
.......
}catch (Exception e){
// 回滚
ts.setRollbackOnly();
}
}
});
}
声明式
声明式事务管理是基于AOP实现,使用@Transactional注解进行事务管理。当某个方法加上@Transactional后,这个bean对象(调用的对象)就会进行AOP生成代理对象,代理对象执行某个方法时就会判断方法是不是有@Transactional注解,如果有就会开启事务,所谓的开启事务就是使用事务管理器获取一个数据库连接,然后修改数据库连接的autocommit属性,改成fasle,这样在这个连接上执行sql时就不会自动提交了,接下来就会执行方法,执行完看有没有抛异常,如果没有抛就提交事务,有异常则回滚。
(2) 事务的传播行为
属性 | 描述 |
---|---|
required | 如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行 |
required_new | 当前方法必须启动一个新的事务,并在它自己的事务内运行,将其它事务挂起 |
supports | 如果有事务在运行,当前方法就在这个事务内运行,否装它可以不在事务中运行 |
not_supports、never | 当前方法不应该在事务中运行,如果有事务,就将它挂起 |
mandatory | 当前方法必须在事务中运行,如果没有事务则抛出异常 |
(3)事务的隔离级别
读未提交、读已提交、可重复读、串行化
(4)事务失效的场景
- 必须要使用spring管理的对象(代理对象)调用方法,否则如果被调用的方法使用 @Transactional(propagation =
Propagation.REQUIRES_NEW)是无效的,在Spring中是使用代理的方式实现事务,发生自身调用的时候,没有经过Spring的代理,自然事务失效。确实想在同一个类的某个方法中,调用它自己的另外一个方法,该怎么办呢? 可以用AopContext.currentProxy()获取代理对象 - 在多线程调用中会失效,比如在方法A中多线程调用方法B,因为不在同一个线程中,所以拿到的数据库连接不是一个,是不同的事务。
- 方法被finall修饰,则会造成事务失效,因为spring事务的底层是使用的aop,是使用动态代理生成的代理类(cjlib,基于继承),在代理类中实现事务功能,如果某个方法被finall修饰,在代理类中就无法重写该方法,无法添加事务。
- 如果方法不是public的,则事务会失效,因为在事务的源码中会判断目标方法是不是public的,不是则不支持事务。
SpringBoot
1、springBoot有三个重要的注解:
@ComponentScan
(1)默认扫描启动类(@SpringBootApplication注解的main)所在的包及其子包的beans(使用@Service,@Controller,@Component注解的类),并将扫描的beans加入到IOC容器中。
(2)如果你的类不在启动类所在的包或其子包,你就需要在@ComponentScan里面配置上扫描路径,如@ComponentScan({"com.cs.other","com.cs1.other1"})
@EnableAutoConfiguration:
首先需要先理解@EnableAutoConfiguration中的两个注解:
@AutoConfigurationPackage
@AutoConfigurationPackage中使用了@Import(AutoConfigurationPackages.Registrar.class)
注解,@Import注解的作用是给容器导入组件。@ComponentScan能导入使用了@Controller、@Service、@Component的组件。而@Import组件可以导入任意组件,它有3中方式。
@Import(AutoConfigurationImportSelector.class)
AutoConfigurationImportSelector中有个getCandidateConfigurations()方法,他是从各个starter包的META-INF/spring.factories路径中加载各个组件,并根据@Conditional组件进行过滤,就是按照条件加载(按需加载)。
@SpringBootConfiguration:
声明这是一个配置类