spring(更新中 )

Spring

为什么要使用 spring?

1.Spring是 开源 的 轻量级 框架

2.一站式框架,内部支持对多种优秀开源框架的集成。

3.Spring 核心 主要有两部分:

  (1)AOP:面向切面编程,扩展功能不是修改源代码实现。

  (2)IOC:控制反转。创建对象不是通过new方式来实现,而是交给Spring配置来创建对象。

BeanFactory 和ApplicationContext有什么区别?

ApplicationContext是BeanFactory的实现类

BeanFactory顶层设计(抽象)  而ApplicationContext是User Interface

IOC的功能是在DefaultListableBeanFactory类中完成的 有共同的接口

SpringBean的声明周期

生命周期:创建-调用-销毁的过程

如果Bean是单例且立即加载的,声明周期就是Spring容器的声明周期;如果延时加载,就在调用前创建对象;如果不是单例的,就和正常对象声明周期一样,调用前创建,调用后由gc去销毁。

SpringBean各作用域之间的区别

 spring中用到了哪些设计模式?

工厂模式BeanFactory、单例模式(容器是单例)、原型模式(容器是多例)、代理模式、享元模式、门面模式。适配器模式、委派模式、装饰器模式、责任链模式、空对象模式、解释器模式等

Spring、SpringBoot、SpringCloud有什么区别?

Spring是已有的生态,可以完成日常开发所有功能。

SpringBoot在Spring简化开发,通过约定优于配置的思想减少配置文件的数量,减少配置的管理和维护成本。全面的去Servlet化,能够自运行,部署也简单,jar包替掉war包。

Springcloud分布式 提供多个服务之间的服务治理,打造一个springcloud生态,不需要自己整合框架。

Spring的自调用

Spring中大部分的bean都被aop增强过,也就是说执行方法时,大部分时候执行的都是代理对象,两个代理对象之间调用并不算自调用。假设我们有一个类是ServiceA,这个类中有一个A方法,A方法中又调用了B方法。当我们使用AOP进行拦截的时候,首先会创建一个ServiceA的代理类,其实在我们的系统中是存在两个ServiceA的对象的,一个是目标ServiceA对象,一个是生成的代理ServiceA对象,如果在代理类的A方法中调用代理类的B方法,这个时候AOP拦截是可以生效的,但是如果在代理类的A方法中调用目标类的B方法,这个时候AOP拦截是不生效的。

如何解决spring自调用导致的一些问题

参考:Spring AOP中自我调用的问题_OkidoGreen的博客-CSDN博客

1.通过ThreadLocal暴露代理对象

第一步:<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>

第二步:修改自调用处的代码比如

((ITargetService)AopContext.currentProxy()).doSomething2();

在方法执行的时候 会把代理对象存放到threadlocal中,

oldProxy = AopContext.setCurrentProxy(proxy);

currentProxy里面就是取了ThreadLocal的线程变量。

public static Object currentProxy() throws IllegalStateException {
		Object proxy = currentProxy.get();
		if (proxy == null) {
			throw new IllegalStateException(
					"Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.");
		}
		return proxy;
	}

2.初始化构造方法注入application对象

3.通过BeanPostProcessor的方式

为什么spring要用三级缓存才能解决循环依赖(Spring实现AOP的时机)

参考:spring循环依赖及解决方法_cristianoxm的博客-CSDN博客_spring循环依赖及解决方式

Spring 为何需要三级缓存解决循环依赖,而不是二级缓存?_Java团长在csdn的博客-CSDN博客

简单来说:在不考虑代理的情况,只需要两层缓存就可以满足需求,一个用来存放实例化完全的bean,另一个用于存放早期创建的bean。或者在不考虑循环依赖但存在代理的情况,只要每次初始化完bean立马创建一个代理对象存到缓存中,也可以只需要两层缓存就能实现。

但因为这两种场景可能同时存在,所以需要第三级缓存来存放早期bean的代理对象工厂,这样在初识化完bean的时候,在注入时注入的是代理对象而不是原始对象。

Spring非单例的bean为什么不能解决循环依赖

结论:作用域scope为property的对象如果和另一个作用域也为property的对象循环依赖时,是无法处理的。如果和另一个作用域为singleton的对象,在单例对象加载方式是立即加载的时候,可以解决循环依赖;如果单例对象是延时加载则不行会报错(先获取多例时)。总结就是单例对象如果先于多例对象创建,就不会报错,否则通不过多例对象的检查。

上述现象依赖spring的一些设计:

1.spring对于多例对象是不进行缓存的

2.对于正在创建中的多例对象会加到threadlocal中

3.如果判断当前beanname已经存在threadlcoal中会报错

protected boolean isPrototypeCurrentlyInCreation(String beanName) {
		Object curVal = this.prototypesCurrentlyInCreation.get();
		return (curVal != null &&
				(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
	}

Spring构造方法注入属性为什么解决不了循环依赖

spring核心逻辑如下图

    // bean对象实例创建的核心实现方法
    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
    		throws BeanCreationException {
    		// 省略其他代码
    		// 1. 调用构造函数创建该bean对象,若不存在构造函数注入,顺利通过
    		instanceWrapper = createBeanInstance(beanName, mbd, args);
    		// 2. 在singletonFactories缓存中,放入该bean对象,以便解决循环依赖问题
    		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    		// 3. populateBean方法:bean对象的属性赋值
    		populateBean(beanName, mbd, instanceWrapper); 		
    		// 省略其他代码
    	return exposedObject;
    }

setter和构造器注入发生循环依赖的时机不同,一个是在populateBean方法中,此时早期对象已经构造出来放入容器中,另一个发生在createBeanInstance中,还没有执行到addSingletonFactory方法,所以在后面的BeanFactory中找不到相应的bean,就报错了

private Object resolveReference(Object argName, RuntimeBeanReference ref) {
		try {
			Object bean;
			String refName = ref.getBeanName();
			refName = String.valueOf(doEvaluate(refName));
			if (ref.isToParent()) {
				if (this.beanFactory.getParentBeanFactory() == null) {
					throw new BeanCreationException(
							this.beanDefinition.getResourceDescription(), this.beanName,
							"Can't resolve reference to bean '" + refName +
									"' in parent factory: no parent factory available");
				}
				bean = this.beanFactory.getParentBeanFactory().getBean(refName);
			}
//            略。。。
}


spring怎么实现事务

Spring本身没有事务,它的事务依赖于数据库提供的事务功能,Spring通过IOC和AOP生成代理对象,按照aop的流程完成事务管理。Spring有两种事务管理方法,分别是编程式事务管理和声明式事务管理。

具体点就是获取connection对象后关闭自动提交,否则sql传到数据库执行完就自动提交了,没办法手动提交和回滚了,然后执行sql,根据sql执行结果决定是提交还是回滚。

参考:Spring的事务是如何实现的? - 简书

Spring怎么实现事务?_Starring丶爸爸的博客-CSDN博客_spring如何实现事务管理

Spring的两种事务管理

例子:( 二十一 ) Spring 编程式事务管理 - 邓维-java - 博客园


spring的事务传播机制--实现原理???

spring事务传播机制_钧令的博客-CSDN博客_spring事务的传播机制


AOP的使用场景,这些场景有哪些特点

1. Authentication 权限
2. Caching 缓存
3. Context passing 内容传递
4. Error handling 错误处理
5. Lazy loading 懒加载
6. Debugging 调试
7. logging, tracing, profiling and monitoring 记录跟踪 优化 校准
8. Performance optimization 性能优化
9. Persistence 持久化
10. Resource pooling 资源池
11. Synchronization 同步
12. Transactions 事务

解释一下什么是 aop?

解释一下什么是 ioc?

spring 有哪些主要模块?

Spring有哪些主要模块_一只菜居的博客-CSDN博客_spring模块有哪几个部分

spring 常用的注入方式有哪些?

Spring常用的三种注入方式 - 沫小淘 - 博客园

spring 中的 bean 是线程安全的吗?TODO

等价于Java中的bean是线程安全的吗。spring没有对bean进行线程安全处理,和自己写的代码有关。spring只提供管理功能。对于无状态的bean是线程安全的

spring 自动装配 bean 有哪些方式?

spring 事务实现方式有哪些?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值