二、Spring框架

Spring框架是一个轻量级的应用框架,核心特性包括控制反转(IOC)和面向切面编程(AOP)。IOC通过Spring容器管理对象的生命周期,降低了代码耦合。AOP用于在不修改原有代码的情况下,实现横切关注点,如日志记录、事务管理和权限校验。依赖注入(DI)使得对象间的依赖关系得以解耦,Spring通过XML配置、注解和工厂模式等多种方式实现DI。此外,Spring还支持Bean的生命周期管理,包括单例、多例、懒加载等,并提供了多种作用域。Spring框架的优点在于其分层架构和组件的可选性,可以与其他框架如Hibernate、Struts等无缝集成。
摘要由CSDN通过智能技术生成

目录

#Spring框架概念

#使用 Spring 有哪些方式?

#Spring-IOC

##IOC概念:

###什么是 Spring容器

###Spring容器 管理/实例化  对象的几种方式(spring容器的启动问题。--面试)

###BeanFactory和ApplicationContext有什么区别

ss

##Spring IoC 的实现机制/原理

#Spring-AOP

##AOP概念:

##Spring 中 AOP 的应用场景

##解释一下Spring AOP里面的几个名词

1. 切面(Aspect)=切入点表达式 + 通知方法

##AOP动态代理/AOP的实现方式

###什么是代理?

###动态代理的实现机制/原理

###两种动态代理

###框架中使用的代理模式

#Spring-DI依赖注入

##DI概念:

##依赖注入方式:依赖注入的不同方式

ss

#Spring-Bean

##Bean概念:

##Spring对象(Bean)的生命周期

ss

##bean的自动装配

##Spring-bean的五大作用域(必会)   面试

##bean的单例、多例、懒加载

ss

#MVC设计思想

ss

#Spring Framework

##什么是 Spring Framework?

##Spring Framework 的优点。

##不同版本的 Spring Framework 有哪些主要功能?

#Spring循环依赖

##什么是循环依赖

##什么情况下循环依赖可以被处理?

##Spring是如何解决的循环依赖?



#Spring框架概念

Spring框架是一个开源的 应用程序框架,是对bean的生命周期进行管理的轻量级容器
在整个框架中负责 宏观调控,负责整合其他的第三方框架
其两大核心技术:IOC、AOP,可以降低代码的耦合性。

#使用 Spring 有哪些方式?

1、作为一个成熟的 Spring Web 应用程序。  

2、作为第三方 Web 框架,使用 Spring Frameworks 中间层。

3、用于远程使用。

4、作为企业级 Java Bean,它可以包装现有的 POJO(Plain Old Java Objects)。

#Spring-IOC

##IOC概念:

“控制反转”,由Spring容器管理对象的生命周期,降低代码耦合性,支持即时的实例化和延迟加载服务。

###什么是 Spring容器

    概念:Spring容器的数据结构是Map集合,Map<key,value>, key是bean(第三行bean标签)中id值, value是通过反射机制实例化的对象class值.
        数据结构: Map<key,value> 
        Bean标签:<bean id="user" class="com.jt.demo.User"></bean>

###Spring容器 管理/实例化  对象的几种方式(spring容器的启动问题。--面试)

在Spring中:对于一个类,我们可以
1、xml配置文件方式-基本不用          原始的开发使用xxx.xml文件 用来管理对象
2、全注解方式(@Configuration+@Bean)现在都使用java类的形式当作配置文件则将该java类 称之为配置类.
Spring容器管理对象本质-1、2、是通过反射机制 自己new对象来实例化的对象;都必然默认调用无参构造
                 反射机制在框架中 一般使用比较多,给定一个类就可以获取其中的对象
3、工厂模式              并不是任意对象都可以通过new的关键字 实例化;抽象类对象 不可以直接实例化,所以要用到工厂模式实现
因为不可以实例化对象,所以就不能通过1、2、反射创建管理对象
    面试问如何启动Spring容器/启动容器调用的哪个类
    1)xml配置文件方法:
    调用ApplicationContext容器顶级接口 来启动spring容器
    ClassPathXmlApplicationContext 加载实现类对象
    2)全注解方式-面试问注解的接口叫什么    
    调用ApplicationContext容器顶级接口 来启动spring容器
    AnnotationConfigApplicationContext 加载实现类对象
    面试问怎么实例化的对象:

根据当前spring的配置规则,实例化接口对象-是xml方式,就用xml的规则;是全注解方式,就用注解的规则,通过ApplicationContext容器顶级接口就可以找到所有的实现类,通过getBean()方法可以获取到对象

###BeanFactory和ApplicationContext有什么区别

BeanFactory在Spring容器启动的时候不会去实例化Bean,从容器中拿Bean的时候才会去实例化——————懒汉式

 ApplicationContext在Spring容器启动的时候就把所有的Bean全部实例化了————饿汉式

ss

@Component//将当前的类,交给Spring容器管理

配置类中:
@Configuration //将当前类标识为配置类
@ComponentScan("com.jt")//包扫描的注解,当spring容器启动时,根据指定的包路径,扫描其子孙包 com.jt是根包
@Bean //配置类中,将方法的返回值,交给Spring容器管理

##Spring IoC 的实现机制/原理

Spring 中的 IoC 的实现原理就是工厂模式(BeanFactory)加反射机制。

#Spring-AOP

##AOP概念:

面向切面编程-通过代理对象调用执行目标方法并对目标方法进行了扩展的的功能就是切面,这种编程思想叫AOP;利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高开发效率。

##Spring 中 AOP 的应用场景

缓存、事物开启;日志记录,安全验证,权限校验 异常的处理 等方面

##解释一下Spring AOP里面的几个名词

1. 切面(Aspect)=切入点表达式 + 通知方法

切入点表达式(本质上就是一个判断if): 如果目标对象满足切入点表达式的判断(if),则spring自动为其创建代理对象;如果不满足,就不管了
通知方法:  对目标方法进行扩展的方法.

AOP规则:  先判断目标对象是否满足切入点表达式,如果目标对象满足切入点表达式,则spring自动为其创建代理对象并执行通知方法

AOP的四种切入点表达式

bean表达式 

within表达式 

execution表达式

@annotation表达式

五种通知方法

//1.前置通知: 在目标方法执行之前执行.
    @Before("pointcut()")

//2.后置通知: 在目标方法执行之后执行
    @AfterReturning("pointcut()")

 //3.异常通知: 目标方法执行报错时,执行该通知
    @AfterThrowing("pointcut()")

 //4.最终通知: 目标方法之后都要执行的通知
    @After("pointcut()")

 //5.重点掌握 环绕通知: 在目标方法执行前后都要执行. 即控制目标方法
    @Around("pointcut()")
2. 连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。 在Spring AOP中,一个连接点 总是 代表一个方法的执行。 通过声明一个org.aspectj.lang.JoinPoint类型的参数可以使通知(Advice)的主体部分获得连接点信息。
3. 通知(Advice):在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。 通知的类型将在后面部分进行讨论。许多AOP框架,包括Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链。
4. 切入点(Pointcut):匹配连接点(Joinpoint)的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。 切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。

Spring定义了Pointcut接口,用来组合MethodMatcher和ClassFilter,可以通过名字很清楚的理解, MethodMatcher是用来检查目标类的方法是否可以被应用此通知,而ClassFilter是用来检查Pointcut是否应该应用到目标类上
5. 引入(Introduction):(也被称为内部类型声明(inter-type declaration))。声明额外的方法或者某个类型的字段。 Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。
6. 目标对象(Target Object): 被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫做 被通知(advised) 对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。

包含连接点的对象。也被称作被通知或被代理对象。
7. AOP代理(AOP Proxy): AOP框架创建的对象,用来实现切面契约(aspect contract)(包括通知方法执行等功能)。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。 注意:Spring 2.0最新引入的基于模式(schema-based)风格和@AspectJ注解风格的切面声明,对于使用这些风格的用户来说,代理的创建是透明的。

 AOP框架创建的对象,包含通知。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
8. 织入(Weaving):把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象。 这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。 Spring和其他纯Java AOP框架一样,在运行时完成织入。

 组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。

##AOP动态代理/AOP的实现方式

###什么是代理?

不能直接引用一个对象,此时可以通过“代理对象”来实现间接引用

代理是通知目标对象后创建的对象。从客户端的角度看,代理对象和目标对象是 一样的。

一般采用代理模式,主要的目的就是为了解耦.将公共的通用的方法(功能/业务)放到代理对象中. 由业务层专注于业务执行即可;用户以为调用的是目标方法,其实调用的是代理对象

###动态代理的实现机制/原理

主要是通过反射机制实现的

###两种动态代理

1、 动态代理-JDK代理

要求: 被代理者/目标方法必须 要么是接口,要么实现接口

2、动态代理-CGLIB代理

被代理者/目标方法有无接口都可以创建代理对象. 代理对象是目标对象的子类 **重写子类方法

怎么让目标方法执行?两种代理方式一样:method点invoke方法

JDK中执行目标方法
-method.invoke(target,args);
CGlib中执行目标方法
-method.invoke(target,args);

###框架中使用的代理模式

 Spring中默认采用的动态代理的规则是JDK代理,如果被代理者没有接口.则自动使用CGLIB

SpringBoot中默认代理模式采用CGLIB代理.如果需要修改为JDK代理则需要修改配置文件即可

#Spring-DI依赖注入

##DI概念:

Spring中的依赖注入机制,为当前对象注入属性(属性也是对象),即程序在运行时 依靠IOC容器来动态注入对象需要的外部资源。

##依赖注入方式:依赖注入的不同方式

1、注解注入

1)按照类型注入——如果被注入的属性 是一个接口,单个实现类 时用,自动注入接口的实现类
-@Autowired 可以将Spring容器中的对象,自动注入到属性中.

2)按照名称(key/实现类名称)注入——如果被注入的属性 是一个接口,多个实现类 时用,指定自动注入接口的实现类
-@Autowired
 @Qualifier("cat") //该注解不能单独使用,必须配合Autowired使用,根据key进行注入

2、构造器注入

构造器注入指的是在类中构造带参数的构造方法实现类的注入,

 3、set注入:使用属性的setter方法注入

setter注入指的是在类中加入setter方法实现类的注入

区分构造函数注入和 setter 注入。
构造函数注入                                        setter 注入 
没有部分注入                                       有部分注入 
不会覆盖 setter 属性                            会覆盖 setter 属性 
任意修改都会创建一个新实例              任意修改不会创建一个新实例 
适用于设置很多属性                            适用于设置少量属性

ss

可以将Spring容器中的对象,自动注入到属性中.
1、按照类型注入——被注入的属性 是一个接口,单个实现类 时用,自动注入接口的实现类
-@Autowired
2、按照名称(key)注入——被注入的属性 是一个接口,多个实现类 时用,指定自动注入接口的实现类
-@Autowired
 @Qualifier("cat") //该注解不能单独使用,必须配合Autowired使用,根据key进行注入
拓展:
@Resource               相当于@Autowired(类型注入)
@Resource(name="cat") 相当于@Autowired+ @Qualifier("cat")(名称注入)
        一般不用,因为是javax的东西,不是Spring的,以后可能用不了。但面试可能问到

#Spring-Bean

##Bean概念:

被spring容器管理的对象称之为bean;(手动创建的对象不叫bean)

Spring 工厂底层构建Bean对象借助什么机制:借助反射机制

##Spring对象(Bean)的生命周期

一个对象从创建到消亡,可以划分为四个阶段(对象创建-初始化-使用-销毁). 如果需要对程序进行干预.则可以通过周期方法/函数在 对象创建的各个阶段 进行干预. (又称为 回调函数/钩子函数/接口回调)

ss

@PostConstruct  //在对象创建后立即调用  进行初始化操作
@PreDestroy //对象消亡时 进行调用

##bean的自动装配

Spring 容器能够自动装配相互合作的bean,这意味着容器不需要<constructor-arg>和<property>配置,能并通过Bean工厂自动处理bean之间的协作。

当 bean 在 Spring 容器中组合在一起时,它被称为装配或 bean 装配。Spring 容器需要知道需要什么 bean 以及容器应该如何使用依赖注入来将 bean 绑定 在一起,同时装配 bean。

##Spring-bean的五大作用域(必会)   面试

1、singleton作用域:默认作用域,不管接受到多少个请求,容器中只有一个bean的实例。

2、prototype作用域:为每一个请求创建一个bean的实例。

3、request作用域:为每一个request请求创建一个实例,不同request请求会使用不同的实例。

4、session作用域:为每一个session会话创建一个实例,不同session会话使用不同的实例。

5、global-session全局作用域:所有会话共享一个实例。如果想要声明让所有会话共享的存储变量的话,那么这全局变量需要存储在global-session中。

##bean的单例、多例、懒加载

1、单例:  在内存中只有一份对象 ,某个类的实例在 多线程环境下只会被创建一次出来。
2、多例:在内存中可能有多份对象-如果当前线程中有一个人在       使用这个多例对象,那就只有一份;如果多个线程同时使用这个多例对象,那就有多份。
       使用场景:比如多个人连接同一个数据库时,就得用多例
规则:Spring默认管理的对象都是单例的。通过@Scope。注解,控制对象单例/多例

Spring的bean对象默认是单例的还是多例的? 单例bean存不存在线程安全问题呢?(必会) 多例呢,怎么变成多例。--面试
1. 在spring中的对象默认是单例的,但是也可以配置为多例。
2. 单例bean对应的类存在可变的成员变量  并且其中存在改变这个变量的线程时,多线程操作该bean时会出现    线程安全问题/ Controller 并发的安全。当多线程中存在线程改变了bean对象的可变成员变量时,其他线程无法访问该bean对象的初始状态,从而造成数据错乱
解决办法:

1、在bean中避免定义可变成员变量;
2、在bean中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中。将类变量保存在线程的变量域中,让不同的请求隔离开来。

3、懒加载机制/延迟加载机制:
规则:
如果Spring容器创建对象时,对象立即创建则该加载方式为“立即加载”;——容器启动创建
如果Spring容器创建对象时,对象在被使用的时候才被创建则该加载方式为“懒加载”——使用时创建

判断是否为懒加载:看对象什么时候创建,即看对象中的无参构造什么时候被使用-使用DeBug看对象什么时候创建、无参构造是什么时候被使用的
Spring默认条件下都是立即加载  通过@lazy注解将其变成懒加载
使用场景:
场景1:服务器启动时,如果加载太多的资源,则必然导致服务器启动慢,适当的将不重要的资源设置为懒加载
-使用时候再创建对象使用
场景2:有时用户会需要一些特殊的“链接”,比如连接数据库、redis等,而这些链接的创建需要很长时间,可以设置为懒加载--因为多例模式都是懒加载,所以这些特殊的连接都是单例模式

单例、多例、懒加载的关系:-@Lazy只能在单例里用
只要对象是多例模式,则都是懒加载!加不加@Lazy都是懒加载 
只有在单例模式中控制懒加载才有效!加上@Lazy时懒加载,不加@Lazy时立即加载

ss

配置类中:
通过@Scope注解,控制对象单例/多例
@Scope(“singleton”) //默认值 单例模式*用在配置类中
@Scope(“prototype”)//多例模式*用在配置类中

通过@Lazy 注解,控制对象的懒加载
默认条件下都是立即加载  加上@lazy将其变成懒加载*用在配置类中 

#MVC设计思想

概念:与面向对象、面向过程类似的的东西
其中,M是指业务模型,V是指视图页面,C则是控制器,MVC设计思想,实现了前后端的松耦合;但实际中很多业务逻辑复杂,为了很好的体现MVC设计思想,后端代码也进行了分层
 
层级代码结构(注意MVC思想不是三层代码结构)
MVC > 三层代码结构!!!

ss

分层说明:
1. 控制层 Controller 与前端页面交互的. @Controller
2. 业务层 Service 编辑业务逻辑. @Service
3. 持久层 Mapper 实现数据库的相关操作 @Repository/@Mapper

#Spring Framework

##什么是 Spring Framework?

Spring 是一个开源应用框架,旨在降低应用程序开发的复杂度。它是轻量级、松 散耦合的。它具有分层体系结构,允许用户选择组件,同时还为 J2EE 应用程序 开发提供了一个有凝聚力的框架。它可以集成其他框架,如 Structs、Hibernate、 EJB 等,所以又称为框架的框架。

##Spring Framework 的优点。

由于 Spring Frameworks 的分层架构,用户可以自由选择自己需要的组件。 Spring Framework 支持 POJO(Plain Old Java Object) 编程,从而具备持续集 成和可测试性。由于依赖注入和控制反转,JDBC 得以简化。它是开源免费的。

##不同版本的 Spring Framework 有哪些主要功能?

Version Feature Spring 2.5 发布于 2007 年。这是第一个支持注解的版本。 Spring 3.0 发布于 2009 年。它完全利用了 Java5 中的改进,并为 JEE6 提供了支 持。 Spring 4.0 发布于 2013 年。这是第一个完全支持 JAVA8 的版本

 Spring Framework 有哪些不同的功能?
轻量级 - Spring 在代码量和透明度方面都很轻便。IOC - 控制反转 AOP - 面向 切面编程可以将应用业务逻辑和系统服务分离,以实现高内聚。容器 - Spring 负 责创建和管理对象(Bean)的生命周期和配置。MVC - 对 web 应用提供了高 度可配置性,其他框架的集成也十分方便。事务管理 - 提供了用于事务管理的通 用抽象层。Spring 的事务支持也可用于容器较少的环境。JDBC 异常 - Spring 的 JDBC 抽象层提供了一个异常层次结构,简化了错误处理策略。

#Spring循环依赖

##什么是循环依赖

就是A依赖B的同时B也依赖了A

@Component
public class A {
    // A中注入了B
	@Autowired
	private B b;
}

@Component
public class B {
    // B中也注入了A
	@Autowired
	private A a;
}

比较特殊的还有

// 自己依赖自己
@Component
public class A {
    // A中注入了A
	@Autowired
	private A a;
}

##什么情况下循环依赖可以被处理?

  1. 出现循环依赖的Bean必须要是单例
  2. 依赖注入的方式不能全是构造器注入的方式

##Spring是如何解决的循环依赖?

Spring通过三级缓存解决了循环依赖,其中一级缓存为单例池(singletonObjects),二级缓存为早期曝光对象earlySingletonObjects,三级缓存为早期曝光对象工厂(singletonFactories)。当A、B两个类发生循环引用时,在A完成实例化后,就使用实例化后的对象去创建一个对象工厂,并添加到三级缓存中,如果A被AOP代理,那么通过这个工厂获取到的就是A代理后的对象,如果A没有被AOP代理,那么这个工厂获取到的就是A实例化的对象。当A进行属性注入时,会去创建B,同时B又依赖了A,所以创建B的同时又会去调用getBean(a)来获取需要的依赖,此时的getBean(a)会从缓存中获取,第一步,先获取到三级缓存中的工厂;第二步,调用对象工工厂的getObject方法来获取到对应的对象,得到这个对象后将其注入到B中。紧接着B会走完它的生命周期流程,包括初始化、后置处理器等。当B创建完后,会将B再注入到A中,此时A再完成它的整个生命周期。至此,循环依赖结束!

面试官:”为什么要使用三级缓存呢?二级缓存能解决循环依赖吗?“

答:如果要使用二级缓存解决循环依赖,意味着所有Bean在实例化后就要完成AOP代理,这样违背了Spring设计的原则,Spring在设计之初就是通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来在Bean生命周期的最后一步来完成AOP代理,而不是在实例化后就立马进行AOP代理。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值