什么是spring IOC 容器? 有什么作用?优点是什么?
IOC就是控制反转 控制了什么?
UserService userService=new UserService();//耦合度太高 维护不方便,属性值都是空的!
一入IOC 就将创建对象的控制权交给spring的ioc 以前由我们自己控制对象的创建 现在交给spriong的ioc去创建 如果我们要去使用 只需要通过DI(依赖注入)@Autowired(自动注入)就可以使用对象
UserService.class---->无参构造---->对象----->依赖注入(属性赋值)------初始化前-----初始化-----初始化后---->bean
说明:spring先通过无参构造去创建UserService对象,但对象中的@Autowired的属性都是没有值的,spring会去循环找到他们进行属性赋值
初始化前:在对象中会通过@PostConstruct注解去在初始化前的流程中执行此方法,可以对一些需要依赖注入的对象进行赋值
Spring容器必须通过DI注入给我 我才可以使用 DI是是想ioc重要的一环
优点:1 集中管理对象、方便维护 2 降低耦合度
Ioc容器创建的对象就是bean 自己new的就叫对象
Spring IOC的实现机制是什么
简单工厂+反射
简单工厂如果类很多的时候需要一个一个去判断和创建 则采用反射技术来处理(传入的是完整的类路径)
BeanFactory的作用
BeanFactory是spring中非常核心的一个顶层接口
它是bean的工厂 它的主要职责就是生产Bean
它实现了简单工厂的设计模式 通过调用getBean传入标识生产一个Bean
BeanFactory它也是一个容器(管理着Bean的生命周期)
spring容器(管理着Bean的生命周期)ApplicationContext
BeanDefinition的作用
首先是配置bean(通过各种方式xml、@Bean)然后把他们都放到BeanDefinitionMap中(因为会有多个配置的bean)map中的key就是beanName 然后通过循环交给bean工厂进行生产实例化这些bean
ApplicationConText和beanFactory区别
共同点:都可以作为容器
区别:
1 beanFactory也可以作为容器 内存占用率小 作为一个工厂
2 ApplicationConText通知beanFactory去生产bean 自己则不能生产bean
3 ApplicationConText比 beanFactory做的事情更多
比如:ApplicationConText会自动帮我们把我们配置的bean注册进来
BeanFactory 和 FactoryBean 有什么区别?
BeanFactory是一个工厂 也就是一个容器 是来管理和生产bean的
FactoryBean是一个bean 但是一个特殊bean 所以也是由BeanFactory来管理的
重点:
假如userService类实现了FactoryBean 所以就寄生在了userService中 因此它就不在返回userService了
等于说现在我们在容器中获得的userService将不再是它本身的对象了 而是通过FactoryBean的getObject方法返回的对象了 在这个方法里可以返回任何自定义对象(比如:roleService)就会狸猫换太子 所以在容器中getBean的时候返回的就不是userService 而是自定义的roleService
如果想依旧返回原本的对象 可以在getbean的key时候前面加上&符号
而且FactoryBean是一种懒加载的模式
正常的单例bean都在在容器加载的时候帮我们创建 并放到容器中
但是被FactoryBean修饰之后就变成了懒加载了 容器加载完之后 只有等主动获取get的时候 才会输出
Spring中 有两个id相同的 bean 会报错吗,如果会报错,在哪个阶段报错
1在同一个XML配置文件里面,不能存在id相同的两个bean,否则spring容器启动的时候会报错
2在两个不同的Spring配置文件里面,可以存在id相同的两个bean。 IOC容器在加载Bean的时候,默认会多个相同id的bean进行覆盖。
3在Spring3.x版本以后,@Configuration注解去声明一个配置类,然后使用@Bean注解实现Bean的声明
如果我们在同一个配置类里面声明多个相同名字的bean,在Spring IOC容器中只会注册第一个声明的Bean的实例。后续重复名字的Bean就不会再注册了。
说下 spring IOC容器的加载过程
根据包路径扫描到所有.class文件中有没有配置标准的注解 如果有 就会把当前这个bean注册为BeanDefinition对象
1、实例化一个AppLicationContext的对象
2、通过读取器去读取配置类
3、解析class文件对象
判断当前类是否再excludeFilter相匹配 如果匹配就直接排除 反之如果匹配includeFilter那么就通过
如果是java配置类方式解析的话是基于动态注册BeanDefinition的这个扩展点来解析的 里面有一个配置类解析器 通过解析器中doscan方法进行扫描解析
如果是xml方式解析的话是通过LoadBeanDifinition解析,然后注册BeanDefinition
4、把注册好的BeanDefinition对象put到BeanDefinitionMap中缓存起来
使用工厂模式 通过bean工厂去生产bean 是调用getBean的方法
流程:
1 现在就是开始生产bean了 循环判断所有的BeanDefinition是否符合生产的标准(标准条件:是单例 不是懒加载 不是抽象)满足条件才会生产
2、如果符合标准 接下来会判断是否创建完成(因为getBean这个方法既会创建也会获取数据)如果创建好了就直接返回
3、实例化对象之前,Spring提供了一个扩展点,允许用户来控制是否在某个或某些Bean实例化之前做一些启动动作。叫做postProcessBeforeInstantiation() (在实例化前可以直接返回一个自定义UserService对象。如果是这样,表示不需要Spring来实例化了,直接执行初始化后这一步)
4、实例化 如果没有创建 就会先利用推断构造方法确定要使用的构造方法 再进行反射的方式进行实例化对象 但这个实例化的bean并不是完整的bean 他是一个没有属性注入的bean
5、Bean对象实例化出来之后,Spring提供了一个扩展点postProcessMergedBeanDefinition(),此扩展点是为了找出注入点并缓存
6、所以实例化后就会进行属性赋值,它会遍历所找到的注入点依次进行注入。@Autowired、@Resource、@Value等注解,都是通过postProcessProperties()扩展点来实现的(甚至可以自定义进行注入操作)
7、初始化前,也是Spring提供的一个扩展点postProcessBeforeInitialization(),
8、最终进行初始化 这一步会实现很多扩展接口(Aware接口 生命周期回调等 这里如果当前这个bean需要实现aop 动态代理那么就在这里被创建)
9、初始化后,Spring提供的一个扩展点postProcessAfterInitialization(),对Bean最终进行处理,Spring中的AOP就是基于初始化后实现的,初始化后返回的对象才是最终的Bean对象。
10、创建完成后 然后放到Map中(单例池)
SpringIoc的扩展点以及调用时机
在注册BeanDefinition阶段时 两个扩展接口
1 动态注册BeanDefinition(如果没有配置bean 但还是希望注册BeanDefinition)接口提供了一个注册器 通过注册器可以创建bean (先执行)
2在所有BeanDefinition注册完后实现BeanFactoryPostProcessor(bean工厂后置处理器)进行自定义扩展(提供了可以查询每一个注册好的BeanDefinition 但是只能通过name查询 并没有BeanDefinitionMap)还可以修改任何一个BeanDefinition中的属性(作用域 懒加载等)
在初始化阶段 钩子方法
Awate接口 BeanNameAware、beanFactoryAware方法去扩展当前bean
例如:初始化阶段调用XXXAware接口的SetXXXAware方法
生命周期回调 扩展的接口
生命周期的回调:spring在初始化回调 销毁回调的方法
什么是javaBean和springBean和对象的区别
Spring bean
被springIOC容器管理的对象称为bean bean是一个有spring ioc容器实例化和管理的对象
Java Bean
就是类的对象 里面会有构造方法属性之类的
配置bean有哪几种方式
1 xml :<bean class="UserService" id="">
2 注解:@Component(@Controller @Service @Repostory)
3 javaConfig:@Bean 可以自己控制实例化过程
4 @Inport:3种方式
Bean有哪几种作用域
@scope 注解 以及 xml方式配置作用域
作用域有:(5个)
单例(默认作用域)
多例
必须是web应用的话
Request作用域 一个请求会创建一个bean对象
Session作用域 一个会话会创建一个bean对象
Application作用域 一个全局应用共享一个bean对象
Spring的bean是线程安全的吗?
单例bean的情况下 如果再类中声明成员变量 并且有读写操作(有状态)就是线程不安全的
但是 只需要把成员变量声明在方法中(无状态) 单例bean就是安全的
Spring如何处理线程并发问题?
当两条线程同时去请求UserService类的时候 并且发生了读写请求 那么就会发生线程并发不安全的问题
解决:
1设置为多例:当每条线程访问UserService类时候都是重新new UserService 不会访问同一个
2 将成员变量放在ThreadLocal
3 同步锁 会影响服务器性能
4 把成员变量声明在方法中(无状态)
成员变量:Static修饰成为类变量或静态变量,还有就是方法外的变量。生命周期与类相同。
局部变量:就是方法中的变量。生命周期就是再次方法中。
Bean有哪些生命周期的回调方法?有哪几种实现方式?
Bean的生命周期回调有两种:
1 bean生命周期初始化的时候
2 bean生命周期销毁的时候
三种实现方式
初始化和销毁同理
第一种是通过注解的方式放到方法上进行实现
第二种是通过实现接口重写的方式进行实现
第三种是通过@Bean上配置参数初始化和销毁的方法进行实现
执行顺序:先初始化后销毁 多个初始化时顺序为(销毁同理):注解方式->实现接口->bean注解上配置参数
Bean的生命周期
Spring是如何解决bean的循环依赖的?
第三级缓存就是打破循环用的?
Spring如何避免在并发情况下获取不完整的bean
双重检查锁机制
Spring容器启动时 为什么先加载BeanFactoryPostProcess?
因为BeanDefiniton会在ioc容器加载的比bean先注册 而BeanFactoryPostProcess就是所有的BeanDefiniton注册完后做扩展用的 所以要先加载
Bean的创建顺序是什么样的
Bean的创建顺序是由BeanDefinition的顺序来决定的 当然依赖关系也会影响Bean创建顺序
BeanDefinition的注册顺序有什么来决定的?
主要是有注解(配置)的解释顺序来决定的:
1 @Configuration
2 @Component
3 @Import-类
4 @Bean
5 @Import-ImportBeanDefinitionRegistar
javaConfig是如何代替xml的配置方式的
如果让自动注入没有找到依赖Bean是不报错?
@Autowired默认required为ture 当没有找到依赖时 发抛出错误 如果手动置为false就不会报错了
如果自动注入找到了多个依赖Bean时不报错
可以通过想要成功的内个bean类上添加@Primary注解 就不会报错了
@Autowired注解和@Resource之间的区别
共同点:自动注入
区别:
1 Autowired是基于spring的 Resource是基于jdk的
2 Autowired是根据类型匹配 如果类型匹配到了多个 那就根据name去匹配注入
Resource默认是根据名字去匹配 如果名字没有匹配到才会根据类型去匹配
@Autowired注解自动装配的过程?
1 在Bean实例化后预解析(解析@Autowired标注的属性、方法)
2 在bean属性注入真正解析(拿到上一步缓存的元数据 去ioc容器帮进行查找 并且返回注入)
首先根据预解析的元数据拿到类型取容器中查找
如果查询结果为一个 就将该bean装配给@Autowired指定的数据
如果查询结果为多个 那么@Autowired会根据名称来查找
如果查询结果为空 那么会抛出异常 解决方法是 使用required=false
@Bean之间的方法调用是怎么保证单例的?
@Configuration加与不加的区别是什么?
1 如果希望@Bean的方法返回的对象是单例 需要在类上面加上@Configuration
2 spring会在invokBeanFactoryPostProcessor 通过内置BeanFactoryPostProcessor中会CGLib生 成动态代理
3 当@Bean方法互调时 则会通过CGLib进行增强 通过调用的方法名作为bean的名称去ioc容器 中获取 进而保证了@Bean方法的单例
Spring AOP中常用名词解释?
1.切面(Aspect): 在spring aop指定就是"切面类" 切面类 会管理职切点、通知
2.连接点(Joinpoint):指定就是被增强的业务方法
3.通知(Advice): 就是需要增加到业务方法中的公共代码通知有很多类型
4.切点(Pointcut): 由它决定哪些方法需要增强 哪些不需要增强 结合切点表达式实现
5.目标对象(Target Object): 指定的是增强的对象
6.织入(Weaving): spring aop用的织入方式:动态代理
spring通知有哪些类型?
1 前置通知:在目标方法被调用之前通用通知功能
2 后置通知:在目标方法被调用之后通用通知功能 不会关心方法的输出是什么
3 返回通知:在目标方法成功执行后调用同通知
4 异常通知:在目标方法抛出异常后调用通知
5 环绕通知:通知包裹了被通知的方法 再被通知的方法调用之前和调用之后执行自定义的行为
Spring AOP和AspectJ Aop有什么区别?
AOP实现的关键在于代理模式,AOP代理主要分为静态代理和动态代理
静态代理的代表为AspectJ 动态代理则以Spring AOP为代表
Spring AOP使用的动态代理 它基于动态代理来实现 默认
如果使用接口 用JDK提供的动态代理实现
如果没有接口 则使用CGLIB实现
JDK动态代理和CGLIB动态代理的区别?
JDK动态代理只提供接口的代理 不支持类的代理
1 JDK会在运行时为目标类生成一个 动态代理类$proxy*.class
2 该代理类是实现了目标类接口 并且代理类会实现接口所有的方法增强代码
3 调用是 通过代理类先去调用处理类进行增强 在通过反射的方式进行调用目标方法
如果代理类没有实现接口 那么spring aop会选择使用CGLIB来动态代理目标类
1 CGLIB的底层是通过ASM在运行时动态的生成目标类的一个子类
2 并且会重写父类所有的方法增强代码
3 调用时先通过代理类进行增强 再直接调用父类对应的方法进行调用目标方法
CGLIB是通过继承的方式做的动态代理 因此如果被某个类标记为final 则无法使用代理
PS:jdk动态代理 比 CGLIB 性能好20%左右
jdk动态代理 生成类速度快 调用慢
CGLIB 生成类速度慢 调用快
介绍aop有几种实现方式?
Spring 1.2 基于接口的配置
Spring 2.0 schema-based配置:使用XML方法类配置 使用 命名空间<aop></aop>
Spring 2.0 @AspectJ配置:注解方式
什么情况下AOP会失效 怎么解决?
失效原因: 内部调用不会触发Aop
解决方式:必须走代理 重新拿到代理对象再次执行方法才能进行增强
1 在本类中自动注入当前的bean
2 设置暴露当前代理对象到本地线程
Spring的AOP是在哪里创建的动态代理的?
1 正常的Bean会在Bean的生命周期的初始化后 通过 后置处理器创建aop的动态代理
2 当循环依赖的Bean会在Bean的生命周期的属性注入时候 创建aop
AOP的实现大致分为三步?
当@EnableAspectJAutoProxy会通过@Import注册一个BeanPostProcessor处理AOP
1 解析切面 :在Bean创建之前的第一个Bean后置处理器会去解析切面(解析切面中的通知、切点 一个通知就会解析成一个advisor)
2 创建动态代理:正常的Bean初始化后调用Bean的后置处理器 拿到之前缓存的advisor 在通过 advisor中的切点 判断当前Bean是否被切点表达式匹配 如果匹配 就会为Bean创 建动态代理
3 调用:拿到动态代理对象 调用方法 就会判断当前方法是都增强的方法 就会通过调用链的方式依 次去执行通知
spring事物四大特性
原子性
一致性
隔离性
持久性
Spring支持的事物管理类型 spring事物实现方式有哪些?
1 编程式事务管理:通过编程的方式管理事务 带来极大的灵活性 难维护
2 声明式事务管理:可以将业务代码和事务管理分离 只需要用注解和xml配置管理事务
Spring事务的传播行为?
Spring事务实现原理?
使用:
@EnableTransactionManagement
1 解析切面 :在Bean创建之前的第一个Bean后置处理器会去解析切面(解析切面中的通知、切点 一个通知就会解析成一个advisor)
2 创建动态代理:正常的Bean初始化后调用Bean的后置处理器 拿到之前缓存的advisor 在通过 advisor中的切点 判断当前Bean是否被切点表达式匹配 @Transacational(方法里 面是不是有 类上面是不是有 接口或者父类是不是有) 匹配到就创建动态代理
3 调用:动态代理
try{
4.创建一个数据库连接Connection 并且修改数据库连接的autoCommit属性为false 禁止 此链接自动提交 这是实现spring事物非常重要的一步
5.然后执行目标方法 方法中会执行数据库操作
}
catch{
6.如果出现了异常 并且这个异常是需要回滚的就会回滚事物 否则仍然提交事物
}
Spring事务传播行为实现原理?
spring的事物信息是存在ThreadLocal中的 所以一个线程永远只能有一个事物
融入:当传播行为是融入 外部事物则拿到ThreadLocal中的Connection 共享一个数据库连接共同 提交、回滚
创建新事物:当传播行为是创建新事物 回见嵌套新事物存入ThreadLocal 将外部事物暂存起 来当嵌套事物提交、回滚后 然后暂存的事物信息恢复到ThreadLocalzhogn中
Spring中运用的设计模式?
1 简单工厂 ----BeanFactory
2 工厂方法 ----FactoryBean
3 单例模式 ----Bean实例
4 适配器模式 ----springMvc中的HandlerAdatper
5 装饰器模式 ----BeanWrapper
6 代理模式 ----AOP底层
7 观察者模式----spring的时间监听
8 策略模式