# spring-annotation **Repository Path**: tdpain/spring-annotation ## Basic Information - **Project Name**: spring-annotation - **Description**: spring核心注解 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-01-24 - **Last Updated**: 2024-02-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # spring-annotation #### 介绍 spring核心注解 #### 软件架构 软件架构说明 #### 安装教程 1. xxxx 2. xxxx 3. xxxx #### 使用说明 1. xxxx 2. xxxx 3. xxxx #### 参与贡献 1. Fork 本仓库 2. 新建 Feat_xxx 分支 3. 提交代码 4. 新建 Pull Request #### 特技 1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md 2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) 3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) 6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) #### 第17章 @Scope /** * @since 2.5 */ @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Scope { @AliasFor("scopeName") String value() default ""; /** * @since 4.2 */ @AliasFor("value") String scopeName() default ""; ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT; } 从@Scope注解的源码可以看出,@Scope注解是从Spring2.5版本开始提供的注解,并且在@Scope注解中提供了三个属性,具体含义分别如下所示。 value:表示作用范围,可以取如下值。 singleton:表示单例Bean,IOC容器在启动时,就会创建Bean对象。如果标注了@Lazy注解,IOC容器在启动时,就不会创建Bean对象,会在第一次从IOC容器中获取Bean对象时,创建Bean对象。后续每次从IOC容器中获取的都是同一个Bean对象,同时,IOC容器会接管单例Bean对象的生命周期。 prototype:表示原型Bean。IOC容器在启动时,不会创建Bean对象,每次从IOC容器中获取Bean对象时,都会创建一个新的Bean对象。并且@Lazy注解对原型Bean不起作用,同时,IOC容器不会接管原型Bean对象的生命周期 request:表示作用域是当前请求范围。 session:表示作用域是当前会话范围。 application:表示作用域是当前应用范围。 scopeName:Spring4.2版本开始新增的属性,作用与value属性相同。 proxyMode:指定Bean对象使用的代理方式,可以取如下值。 DEFAULT:默认值,作用与NO相同。 NO:不使用代理。 INTERFACES:使用JDK基于接口的代理。 TARGET_CLASS:使用CGLIB基于目标类的子类创建代理对象。 #### spring解决循环依赖 三级缓存存放位置: private final Map singletonObjects = new ConcurrentHashMap<>(256); private final Map> singletonFactories = new HashMap<>(16); private final Map earlySingletonObjects = new ConcurrentHashMap<>(16); 每个Map的含义如下所示: singletonObjects:一级缓存,存储所有实例化,并且为属性赋值的单实例Bean earlySingletonObjects:二级缓存,存储实例化后还没来得及为属性赋值的单实例Bean singletonFactories:三级缓存,存储生产单实例Bean的工厂 Spring解决循环依赖为什么需要二级缓存? 二级缓存主要是为了分离创建出的完整的Bean和未对属性赋值的Bean,二级缓存中实际主要存储的是未对属性赋值的Bean, 这样做的目的就是为了防止在多线程并发的场景中,读取到还未创建完成的Bean。所以,为了保证在多线程并发的环境中, 读取到的Bean是完整的(已经为属性赋值),不会读取到未对属性赋值的Bean,需要使用二级缓存解决循环依赖。 另外,就一、二、三级缓存而言, 二级缓存主要存储的是三级缓存创建出来的,并且未对属性赋值的Bean, 这样做的目的也是为了防止三级缓存中的工厂类重复执行创建对象的逻辑。 Spring只用二级缓存能否解决循环依赖?为什么一定要用三级缓存来解决循环依赖呢? 其实,Spring使用二级缓存就完全能够解决循环依赖的问题,也可以支持Spring基于BeanPostProcessor的扩展能力。 但是,由于Spring中的方法在设计上遵循了单一职责的原则,一个方法通常只做一件事情,getBean()方法就是获取Bean对象。 但是,调用BeanPostProcessor创建动态代理是处于创建Bean的过程,如果在getBean()中实现这个逻辑,显然代码逻辑比较耦合。 为了解决代码耦合的问题,保持方法的职责单一,方面后期维护。需要将创建动态代理的BeanPostProcessor放在创建Bean的方法中。 并且将判断是否存在循环依赖的逻辑放在getSingleton()方法中。此时就需要三级缓存,在三级缓存中存放一个工厂接口, 在接口的实现类中调用BeanPostProcessor创建动态代理对象。为了防止重复创建代理对象,将三级缓存中创建的代理对象存入二级缓存。 在Spring中使用三级缓存完美解决了解耦、性能、扩展的问题。 Spring循环依赖经典面试题: 什么是循环依赖问题? 循环依赖有哪些类型? 在spring中支持哪种循环依赖? 列举几种Spring不支持的循环依赖的场景,为什么不支持? Spring解决循环依赖的流程是什么? Spring解决缓存依赖时,二级缓存的作用是什么? Spring只用二级缓存能否解决循环依赖?为什么一定要用三级缓存来解决循环依赖呢? 你从Spring解决循环依赖的设计中得到了哪些启发? #### AOP切面问题 AOP切面中注解提供了哪些注解,各自的作用是什么? AOP切面中环绕通知的注解是如何实现的? AOP切面型注解的执行顺序是什么? @After、@AfterReturning、@AfterThrowing的区别是什么? 你在平时工作中,会在哪些场景下使用AOP切面型注解? 你从AOP切面型注解的设计中得到了哪些启发?