advice
1.Spring4
正常执行:@Before======@After======@AfterReturning
异常执行:@Before======@After======@AfterThrowing
2.Spring5
正常执行:@Before(前置通知)=======@AfterReturning(返回后通知)=======@After(后置通知)
异常执行:@Before========@AfterThrowing====@After
二.AOP的底层实现原理AOP是IOC的扩展功能,先有IOC,AOP是整个流程的一个新增扩展点:BeanPostProcessor(后置处理方法)
1.代理对象的创建过程(advice,切面,切点)
2.通过jdk或cglib的方式来生成代理对象。
面向切面编程,与面向对象编程相辅相成。在OOP中以类为基本单元,而AOP是aspect切面。实现方式有静态代理和动态代理。
(1)静态代理:编译阶段就可生成AOP代理类。
(2)动态代理:运行时生成。分为JDK(利用反射,并且要求被代理的类必须实现一个接口,核心是invocationHandler接口和proxy类)和CGLIB(没有实现接口,就用整个代理目标类,通过继承实现,如果一个类是final修饰无法动态代理)
三.循环依赖及三级缓存java动态代理实现与原理详细分析 - Gonjian - 博客园 (cnblogs.com)
什么是循环依赖?多个bean之前相互依赖,形成一个闭环。spring容器一般指默认的单例Bean里。
两种注入方式(基于构造方法和单例模式下的setter的依赖注入,非单例无法处理)对循环依赖的影响,避免使用构造方法会抛出异常,spring解决不了,直接抛出异常。我们AB循环依赖问题只要A的注入方式是setter且singleton就不会有循环依赖问题。
spring的单例对象初始化分为:createbeanInstance实例化(调用构造方法);populateBean填充属性(多bean的依赖属性注入);InitializeBean初始化(init方法)。依赖注入就发生在第一二步。
默认的单例(singleton)的场景是支持循环依赖的,不报错;原型(prototype)的场景是不支持循环依赖的,会报错。
关键在于先把非完整状态的对象优先赋值,即只完成了实例化但是还未初始化。提前暴露不完整对象的引用,先赋值再等后续操作完成赋值。当所有对象完成实例化和初始化操作后,还要把完整对象放到容器里,此时容器里有两个状态,完成实例化还未初始化,完整状态。因为都在容器中,所有要使用不同的map来进行存储,就有了一级缓存和二级缓存。如果一级缓存有了,那么二级缓存中就不会存在同名对象。一级放的是完整对象,二级缓存是非完整对象。
为啥需要三级缓存?三级缓存的value类型是ObjectFactory,是一个函数式接口。存在的意义是保证整个容器的运行工程中同名的bean对象只能有一个。
如果一个对象被代理,或者要生成代理对象,那么要优先生成一个普通对象。两者不能再容器中共存,当一个对象要被代理时,使用代理对象覆盖普通对象。当调用对象时,会回调机制,优先判断对象是否需要被代理。lambda表达式执行对象覆盖。
因此,所有bean对象再创建时优先放到三级缓存中,在后续使用中,如果需要被代理则返回代理对象,不然直接返回普通对象。
三级缓存:createBeanInstance之后,addSingletonFactory
二级缓存:第一次从三级缓存确定对象是代理对象还是普通对象,同时删除三级缓存;
一级缓存:生成完整对象后放一级,删除二三级缓存。
spring内部通过三级缓存解决缓存依赖(DefaultSingletonBeanRegistry)第一级缓存(也叫单例池)singletonObjects:存放已经经历了完成生命周期的bean对象
第二级缓存: earlySingletonObjects,存放早期暴露出来的bean对象,bean的生命周期未结束,也就是已经实例化(申请了内存空间)但未初始化(还没放值)的bean放入该缓存里。
第三级缓存:singletonFactories, 存放可以生成bean的工厂
refresh()方法就是加载容器初始化的方法。
四,spring的事务如何回滚
就是怎么实现?(分为编程式事务管理和声明式事务管理)
总:spring的事务是由AOP来实现的,首先要生成具体的代理对象,然后按照AOP的流程执行具体操作。正常要通过通知完成核心功能,但是事务不是,是通过一个TransactionInterceptor(事务拦截器),然后调用invoke实现具体的逻辑。
分:1.准备工作,解析各个方法上事务相关属性,根据属性判断是否开启新事务。
2.当开启时,获取数据库连接,关闭自动提交,开启事务
3.执行具体SQL逻辑操作
4.操作失败通过completeTransactionAfterThrowing,完成事务回滚,具体回滚通过doRollBack方法实现。
5.没有意外,commiteTransactionAfterThrowing,实现doCommite
五.spring的传播特性1.使用Spring的好处
(1)轻量,基本版本2M;
(2)控制反转;
(3)AOP;面向切面编程,提取公共业务逻辑,和服务分开;
(4)容器;
(5)MVC框架;
(6)事务管理
(7)异常处理。
2.依赖注入
不必创建对象,但必须描述怎么创建。描述配置文件中哪些组件需要哪些服务,有IOC容器将它们装配在一起。
(1)构造函数注入
(2)setter注入
(3)接口注入
在spring framework中,仅使用构造函数和setter注入。
3.
BeanFactory(主要的有DefaultListableBeanFactory的功能)将利用BeanDefinition来生成bean对象,BeanDefinition相当于BeanFactory的原材料,bean对象就是产品。
4.构造函数和setter注入区别
5.spring的配置方式
(1)XML配置,以bean标签开头;
(2)注解配置,需要在spring配置文件中启动;
(3)基于Java API配置:通过@Bean和@Configuration
6.spring的bean的作用域
(1)singleton:默认是单例的
(2)prototype:每次请求都会创建一个新的bean实例
(3)request:每次HTTP请求产生一个新的bean,仅在当前HTTP request内有效;
(4)session:在一个session中,一个session对应一个实例。
(5)Global-session
最后三个仅当用户使用applicationcontext可用。
7.如何理解IOC和DI
一个是思想,一个是设计模式。
IOC不用我们自己创建对象,交给bean工厂创建管理,通过面向接口编程的方式来实现对业务组件的动态依赖。IOC是spring争对解决程序耦合存在的。
实际中,spring通过配置文件(如XML或properties)指定需要实例化的Java类,包括类的一组初始化值,通过加载读取配置文件,用spring提供的方法(getbean())获取进行初始化的实例对象。
传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
DI—Dependency Injection,即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。那么DI是如何实现的呢? Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。
DI(依赖注入)其实就是IOC的一种类型,还有一种是DL(Dependency Lookup依赖查找)。 DL由Martin Fowler 在2004年初的一篇论文中首次提出的。他总结:控制的什么被反转了?就是:获得依赖对象的方式反转了。
理解Spring中的IoC和DI - 超超不会飞 - 博客园 (cnblogs.com)
8.将一个类声明为bean的注解
一般使用@autowired注解自动装配bean,要想把类标识成可用于@autowired注解自动装配的bean的类,可用以下:
(1)@component,通用注解
(2)@repository ,对应持久层即Dao层
(3)@service,对应服务层,需要用到Dao层
(4)@controller对应MVC的控制层,接受用户请求并调用service层返回的数据给前端页面。
9.bean的生命周期
10,spring的内部bean
只有将bean用作另一个bean的属性时,才能将bean声明为内部bean。
11.spring装配
当bean在容器中组合在一起,称为bean装配。spring容器需要知道需要什么bean以及如何使用依赖将bean绑定起来。
通过检查beanfactory,不同模式:
(1)no;(2)byName;(3)byType(4)构造函数,有大量参数;(5)autodetect,尝试通过构造函数使用auto wired装配,不能就尝试通过bytype自动装配。
12.如果出现同名bean
(1)同一配置文件的,以最上面定义为准
(2)不同配置文件的,以后解析的为准,覆盖
(3)同文件的@bean和@componentscan,以bean生效;
13.spring中单例bean的线程安全问题
线程安全问题都是由全局变量及静态变量引起的。如果只读没问题,但是多线程同时写有问题。
无状态和有状态bean
有状态就是有实例变量的对象,可以保存数据,是非线程安全的。适用于prototype原型模式。
无状态就是一次操作,不能保存数据。是线程安全的。适用于单例模式。
spring适用threadlocal解决线程安全问题。
@value($())是在XML中找Key,@value(“”)是直接指定字符串,



