作为Java程序员,最先接触的框架是SSH,之后工作后接触SSM,后来就是SpringMVC,现在就是SpringBoot和SpringCloud,不管是那个框架都离不开Spring,可真的理解了Spring吗?
还记得当时学java时候,如何用spring框架,导入包,然后一堆配置,最后继承起来,现在干脆就几个配置,简化了不知道多少最初的配置,有点扯远了,现在开始对Spring做介绍
了解更多JAVA后台知识整理:JAVA后台系列目录
Spring的特征
轻量、控制反转、面向切面、容器、框架
工作中用户面向切面:我们可以做打印日志、程序重试机制
容器:Spring容器内的对象可以相互调用,外部对象如何使用呢 ?静态工具类及方法
事务:我想说的是,事务不简单是在方法上增加一个注解,有可能会失效的
Spring常用模块
核心容器、Spring上下文、SpringAOP、SpringDao、SpringORM、SpringWeb、SpringMVC
Spring常用注解
@Controller、@RestController、@Component、@Repository、@Service
@ResponseBody 、@RequestMapping、@Autorwired、@PathVarable、等等
第三方结合
shiro 权限认证安全
redis / ehcache 缓存
mybatis/hibernate 数据库持久层
quartz/springTask 定时任务
SpringIOC
Spring 通过一个配置文件描述 Bean 及 Bean 之间的依赖关系,利用 Java 语言的反射功能实例化 Bean 并建立 Bean 之间的依赖关系。
Spring 的 IoC 容器在完成这些底层工作的基础上,还提供了 Bean 实例缓存、生命周期管理、 Bean 实例代理、事件发布、资源装载等高级服务。
可以看下这篇知乎:https://zhuanlan.zhihu.com/p/29344811
Spring Bean 作用域
Spring 3 中为 Bean 定义了 5 中作用域,分别为 singleton(单例)、prototype(原型)、 request、session 和 global session,
singleton: 单例模式,Spring IoC 容器中只会存在一个共享的 Bean 实例,无论有多少个 Bean 引用它,始终指向同一对象。该模式在多线程下是不安全的。
Singleton 作用域是 Spring 中的缺省作用域,也可以显示的将 Bean 定义为 singleton 模式
prototype: 原型模式,每次通过 Spring 容器获取 prototype 定义的 bean 时,容器都将创建一个新的 Bean 实例,每个 Bean 实例都有自己的属性和状态,
而 singleton 全局只有一个对象。根据经验,对有状态的bean使用prototype作用域,而对无状态的bean使用singleton 作用域。
request: 在一次 Http 请求中,容器会返回该 Bean 的同一实例。而对不同的 Http 请求则会产生新的 Bean,而且该 bean 仅在当前 Http Request 内有效,当前 Http 请求结束,
该 bean 实例也将会被销毁。
session: 在一次 Http Session 中,容器会返回该 Bean 的同一实例。而对不同的 Session 请求则会创建新的实例,该 bean 实例仅在当前 Session 内有效。同 Http 请求相同,
每一次 session 请求创建新的实例,而不同的实例之间不共享属性,且实例仅在自己的 session 请求内有效,请求结束,则实例将被销毁。
global Session:在一个全局的 Http Session 中,容器会返回该 Bean 的同一个实例,仅在使用 portlet context 时有效。
SpringBean的生命周期
Spring的注入方式:
构造器注入、setter注入、静态工厂注入、实例工厂注入
Spring 种不同方式的自动装配
Spring 装配包括手动装配和自动装配,手动装配是有基于 xml 装配、构造方法、setter 方法等自动装配有五种自动装配的方式,可以用来指导 Spring 容器用自动装配方式来进行依赖注入。
no:默认的方式是不进行自动装配,通过显式设置 ref 属性来进行装配。
byName:通过参数名 自动装配,Spring容器在配置文件中发现bean的autowire 属性被设置成 byname,之后容器试图匹配、装配和该 bean 的属性具有相同名字的 bean。
byType:通过参数类型自动装配,Spring 容器在配置文件中发现 bean 的 autowire 属性被设置成byType,之后容器试图匹配、装配和该bean的属性具有相同类型的bean。
如果有多个 bean 符合条件则抛出错误。
constructor:这个方式类似于 byType, 但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。
autodetect:首先尝试使用constructor 来自动装配,如果无法工作,则使用byType方式。
SpringAOP
1、切面(aspect):类是对物体特征的抽象,切面就是对横切关注点的抽象
2、横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点。
3、连接点(joinpoint):被拦截到的点,因为 Spring 只支持方法类型的连接点,所以在 Spring 中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器。
4、切入点(pointcut):对连接点进行拦截的定义
5、通知(advice):所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类。
6、目标对象:代理的目标对象
7、织入(weave):将切面应用到目标对象并导致代理对象创建的过程
8、引入(introduction):在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段。
AOP 两种代理方式
Spring 提供了两种方式来生成代理对象: JDKProxy 和 Cglib,具体使用哪种方式生成由 AopProxyFactory 根据 AdvisedSupport 对象的配置来决定。默认的策略是如果目标类是接口,
则使用 JDK 动态代理技术,否则使用 Cglib 来生成代理。
*JDK*动态接口代理
JDK 动态代理主要涉及到 java.lang.reflect 包中的两个类:Proxy 和 InvocationHandler。
InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。
Proxy 利用 InvocationHandler 动态创建一个符合某一接口的实例,生成目标类的代理对象。
*CGLib* 动态代理
CGLib 全称为 Code Generation Library,是一个强大的高性能,高质量的代码生成类库,可以在运行期扩展 Java 类与实现 Java 接口,CGLib 封装了 asm,可以再运行期动态生成新的 class。
和 JDK 动态代理相比较:JDK 创建代理有一个限制,就是只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则可以通过 CGLib 创建动态代理。
Spring中的事务
事务的传播性一般用在事务嵌套的场景,比如一个事务方法里面调用了另外一个事务方法,那么两个方法是各自作为独立的方法提交还是内层的事务合并到外层的事务一起提交,
这就是需要事务传播机制的配置来确定怎么样执行。
常用的事务传播机制如下:
PROPAGATION_REQUIRED
Spring默认的传播机制,能满足绝大部分业务需求,如果外层有事务,则当前事务加入到外层事务,一块提交,一块回滚。如果外层没有事务,新建一个事务执行
PROPAGATION_REQUES_NEW
该事务传播机制是每次都会新开启一个事务,同时把外层事务挂起,当当前事务执行完毕,恢复上层事务的执行。如果外层没有事务,执行当前新开启的事务即可
PROPAGATION_SUPPORT
如果外层有事务,则加入外层事务,如果外层没有事务,则直接使用非事务方式执行。完全依赖外层的事务
PROPAGATION_NOT_SUPPORT
该传播机制不支持事务,如果外层存在事务则挂起,执行完当前代码,则恢复外层事务,无论是否异常都不会回滚当前的代码
PROPAGATION_NEVER
该传播机制不支持外层事务,即如果外层有事务就抛出异常
PROPAGATION_MANDATORY
与NEVER相反,如果外层没有事务,则抛出异常
PROPAGATION_NESTED
该传播机制的特点是可以保存状态保存点,当前事务回滚到某一个点,从而避免所有的嵌套事务都回滚,即各自回滚各自的,如果子事务没有把异常吃掉,基本还是会引起全部回滚的。
Spring事务配置中有哪些属性可以配置?以下只是简单的使用参考
事务的传播性:
@Transactional(propagation=Propagation.REQUIRED)
事务的隔离级别:
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
只读:
@Transactional(readOnly=true)
该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。
事务的超时性:
@Transactional(timeout=30)
回滚:
指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)
指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})
事务不生效问题排查
1. 首先要看数据库本身对应的库、表所设置的引擎是什么。MyIsam不支持事务,如果需要,则必须改为InnnoDB。
2 @Transactional所注解的方法是否为public
3 @Transactional所注解的方法所在的类,是否已经被注解@Service或@Component等
4 需要调用该方法,且需要支持事务特性的调用方是在在 @Transactional所在的类的外面。
注意:类内部的其他方法调用这个注解了@Transactional的方法,事务是不会起作用的
5 注解为事务范围的方法中,事务的回滚仅仅对于unchecked的异常有效。对于checked异常无效。
也就是说事务回滚仅仅发生在出现RuntimeException或Error的时候。
了解更多JAVA后台知识整理:JAVA后台系列目录