Spring 常见面试
1.AOP实现原理,代理模式,事务
AOP:面向切面编程,在运行时,动态地将代码切入到类,指定的方法或者位置上的编程思想就是面向切面的编程。能够将那些与业务⽆关, 却为业务模块所共同调⽤的逻辑或责任(例如事务处理、⽇志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
1.1 AOP相关的概念
(1) Aspect :切面,切入系统的一个切面。比如事务管理是一个切面,权限管理也是一个切面;
(2) Join point :连接点,也就是可以进行横向切入的位置;
(3) Advice :通知,切面在某个连接点执行的操作(分为: Before advice , After returning advice , After throwing advice , After (finally) advice , Around advice );
(4) Pointcut :切点,符合切点表达式的连接点,也就是真正被切入的地方;
1.2 AOP的实现
AOP分为动态代理和静态代理
静态代理:指AspectJ实现的AOP,直接将切面的编码编译到JAVA文件中
动态AOP:指将切面代码进行动态的织入实现AOP
Spring AOP是动态代理方式实现的,实现的技术为JDK提供的动态代理技术和CGLIB(动态字节码增强技术)。尽管技术不一样,但是结果都是生成一个代理对象。
1.3 代理的介绍
静态代理:
为每一个业务增强都提供一个代理类,由代理类来创建代理对象。
JDK动态代理:
不存在代理类,代理对象直接由代理工具动态生成。
主要使用到 InvocationHandler 接口和 Proxy.newProxyInstance() 方法。
JDK动态代理要求被代理实现一个接口,只有接口中的方法才能够被代理 。
其方法是将被代理对象注入到一个中间对象,而中间对象实现InvocationHandler接口,
在实现该接口时,可以在被代理对象调用它的方法时,在调用的前后插入一些代码。
而Proxy.newProxyInstance() 能够利用中间对象来生产代理对象。
插入的代码就是切面代码。所以使用JDK动态代理可以实现AOP。
cglib代理:
字节码生成技术实现AOP,其实就是继承被代理对象,然后Override需要被代理的方法,在覆盖该方法时,自然是可以插入我们自己的代码的。
因为需要Override被代理对象的方法,所以自然CGLIB技术实现AOP时,就必须要求需要被代理的方法不能是final方法,因为final方法不能被子类覆盖 。
可以有接口也可以没有,生成目标类的子类,这个子类就是代理对象,代理对象是被增强过的。MethodInterceptor. Enhancer.create(target.getClass(),new AccountAdvice());
1.4 Spring的AOP的实现
基于动态代理的,源码里选择具体的代理方法是现根据被代理的对象是否有接口决定的,有接口的对象就用JDK的动态代理,如果无接口,那么就用CGLIB代理。
2.IOC的启动过程
IOC:控制反转,是一种设计思想,将原本程序中手动创建对象的控制权,交由Spring框架来管理。IOC容器就像一个工厂,当我们需要创建一个对象的时候,只需要配置好文件/注解就可以。
DI:依赖注入,则是,甲方开放接口,在它需要的时候,能够将乙方传递进来(注入)所谓的控制反转,甲乙双方不相互依赖,交易活动的进行不依赖于甲乙任何一方,整个活动的进行由第三方负责管理
2.1 IOC启动流程
IOC的启动流程分为两个阶段,第一阶段是容器的启动阶段,第二阶段是Bean实例化阶段。
容器的启动阶段:资源定位---加载配置信息---分析配置信息---装配BeanDefinition
Bean实例化阶段:实例化bean---设置属性---初始化---销毁
2.2 BeanFactory和ApplicationContext
BeanFactory是Spring的核心接口,也是最顶层接口,定义了IOC的基本功能。ApplicationContext继承自BeanFactory,也是Spring中很重要的接口,它不仅实现了BeanFactory的所有功能,并且提供了更多新的功能,更便于开发者使用。
二者区别:
BeanFactory采用延迟加载的形式来注入bean,只有在使用某个bean时(即调用getBean()方法时),才会对bean进行实例化,这样就不能在容器启动的阶段发现Spring的配置问题。ApplicationContext则不同,在容器启动的时候,一次性完成两个阶段,这样在容器启动阶段就可以发现Spring的配置问题,由于需要实例化所有的bean,所以需要占用更多的内存,启动速度也会稍慢。
ApplicationContext比BeanFactory加入了一些更好使用的功能。BeanFactory的许多功能需要通过编程实现,而 ApplicationContext可以通过配置实现。BeanFactory主要面对Spring框架自己,ApplicationContext则为普通开发者所使用。
3.Bean
3.1 Bean的生命周期
BeanFactoryPostProcess
BeanPostProcess
3.2 Bean的作用域
singleton : 唯⼀bean 实例, Spring 中的bean 默认都是单例的
prototype : 每次请求都会创建⼀个新的 bean 实例
request : 每⼀次HTTP请求都会产⽣⼀个新的bean,该bean仅在当前HTTP request内有效
session : 每⼀次HTTP请求都会产⽣⼀个新的 bean,该bean仅在当前 HTTP session 内有效
global-session 全局session作⽤域,仅仅在基于portlet的web应⽤中才有意义, Spring5已经没有了
线程安全问题:
单例 bean 存在线程问题,主要是因为当多个线程操作同⼀个对象的时候,对这个对象的⾮静态成员变量的写操作会存在线程安全问题。
解决办法:
1.类中避免定义可变变量
2.定义一个ThreadLocal存储类中的可变成员变量
3.3 @Component 和 @Bean 的区别是什么
(1)作⽤对象不同
@Component 注解作⽤于类,⽽ @Bean 注解作⽤于⽅法
(2)装配方法不同
@Component 通常是通过类路径扫描来⾃动侦测以及⾃动装配到Spring容器中
@Bean 注解通常是我们在标有该注解的⽅法中定义产⽣这个 bean, @Bean 告诉了Spring这是某个类的示例,当我需要⽤它的时候还给我。
(3) @Bean比@Conponent的自解释性更强
3.4 将⼀个类声明为Spring的 bean 的注解有哪些
1. ⼀般使⽤ @Autowired 注解⾃动装配 bean
2. 想要能够自动装配,可以如下注解
@Component :通⽤的注解,可标注任意类为 Spring 组件。如果⼀个Bean不知道属于哪个层,可以使⽤@Component 注解标注。
@Controller : 对应 Spring MVC 控制层,主要⽤户接受⽤户请求并调⽤ Service 层返回数据给前端⻚⾯
@Service : 对应服务层,主要涉及⼀些复杂的逻辑,需要⽤到 Dao层。
@Repository : 对应持久层即 Dao 层,主要⽤于数据库相关操作。
4.依赖查找和注入的区别
依赖关系查找是指对象本身试图查找依赖关系,例如:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/application-context.xml");
MyBean bean = applicationContext.getBean("myBean")
这里,类本身是通过XML初始化ApplicationContext,它在上下文中搜索ApplicationContext中名为myBean的bean.
依赖注入是指在初始化istance时自动绑定属性的时间.例如:
在application-context.xml中,我们有一行初始化bean,另一行初始化对象,比方说,MyClass:
<bean id="myBean" class="org.mypackage.MyBean"/>
<bean id="myClass" class="org.mypackage.MyClass"/>
然后在MyClass中,你有类似的东西:
@Component
public class MyClass{
@AutoWire
MyBean myBean;
}
在这种情况下,您已指定初始化两个bean的两个istances.并且myClass bean有一个名为myBean的属性,由于注入已经初始化了
5.SpringBoot的好处
a.创建独立的spring应用程序可以单独以jar包运行
b.嵌入的tomcat,jetty或者Undertow,无需部署war文件
c.允许通过maven来根据需要获取starter,通过这些starter项目就能以Java Application的形式运行Spring Boot项目,而无需其他服务器配置
d.尽可能自动配置Spring,Spring Boot提供Spring框架的最大自动化配置,大量使用自动配置,使得开发者对Spring的配置尽量减少
e.提供生产就绪型功能,如指标、健康检查和外部配置,Spring Boot提供了基于http、ssh、telnet对运行时的项目进行监控;我们可以引入 spring-boot-start-actuator 依赖,直接使用 REST 方式来获取进程的运行期性能参数,从而达到监控的目的,比较方便
PS:缺点
依赖太多,一个spring boot项目就有很多M
缺少服务的注册和发现等解决方案
缺少监控集成方案,安全管理方案
6.SpringMVC原理
说说自己对springMVC的了解
7.Spring框架中的设计模式
工厂设计模式: Spring使⽤⼯⼚模式通过 BeanFactory、ApplicationContext 创建bean 对象。
代理设计模式: Spring AOP 功能的实现。
单例设计模式: Spring 中的 Bean 默认都是单例的。
包装器设计模式: 我们的项⽬需要连接多个数据库,⽽且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
观察者模式: Spring 事件驱动模型就是观察者模式很经典的⼀个应⽤。
适配器模式: Spring AOP 的增强或通知(Advice)使⽤到了适配器模式、 spring MVC 中也是⽤到了适配器模式适配 Controller。
8. Spring中的事务
8.1管理事务的方式
- 编程式事务,在代码中硬编码。 (不推荐使⽤)
- 声明式事务,在配置⽂件中配置(推荐使⽤)
声明式事务⼜分为两种:
- 基于XML的声明式事务
- 基于注解的声明式事务
8.2事务的隔离级别
- transactiondefinition.isolation_default: 使⽤后端数据库默认的隔离级别,mysql 默认采⽤的 repeatable_read隔离级别,oracle 默认采⽤的 read_committed隔离级别.
- transactiondefinition.isolation_read_uncommitted: 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
- transactiondefinition.isolation_read_committed: 允许读取并发事务已经提交的数据,可以阻⽌脏读,但是幻读或不可重复读仍有可能发⽣
- transactiondefinition.isolation_repeatable_read: 对同⼀字段的多次读取结果都是⼀致的,除⾮数据是被本身事务⾃⼰所修改,可以阻⽌脏读和不可重复读,但幻读仍有可能发⽣。
- transactiondefinition.isolation_serializable: 最⾼的隔离级别,完全服从acid的隔离级别。所有的事务依次逐个执⾏,这样事务之间就完全不可能产生干扰,也就是说, 该级别可以防⽌脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会⽤到该级别。
8.3事务的传播行为
(1)支持当前事务
- transactiondefinition.propagation_required: 如果当前存在事务,则加⼊该事务;如果当前没有事务,则创建⼀个新的事务。
- transactiondefinition.propagation_supports: 如果当前存在事务,则加⼊该事务;如果当前没有事务,则以⾮事务的⽅式继续运⾏。
- transactiondefinition.propagation_mandatory: 如果当前存在事务,则加⼊该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)
(2)不支持当前事务
- transactiondefinition.propagation_requires_new: 创建⼀个新的事务,如果当前存在事务,则把当前事务挂起。
- transactiondefinition.propagation_not_supported: 以⾮事务⽅式运⾏,如果当前存在事务,则把当前事务挂起。
- transactiondefinition.propagation_never: 以⾮事务⽅式运⾏,如果当前存在事务,则抛出异常。
(3)其他
- transactiondefinition.propagation_nested: 如果当前存在事务,则创建⼀个事务作为当前事务的嵌套事务来运⾏;如果当前没有事务,则该取值等价于transactiondefinition.propagation_required。
8.4 异常@Transactional(rollbackFor = Exception.class)
Exception分为运⾏时异常RuntimeException和⾮运⾏时异常。事务管理对于企业应⽤来说是⾄关重要的,即使出现异常情况,它也可以保证数据的⼀致性
当 @Transactional 注解作⽤于类上时,该类的所有 public ⽅法将都具有该类型的事务属性,同时,我们也可以在⽅法级别使⽤该标注来覆盖类级别的定义。如果类或者方法加了这个注解,那么这个类⾥⾯的⽅法抛出异常,就会回滚,数据库里面的数据也会回滚。
当@Transactional 注解中如果不配置 rollbackFor 属性,那么事物只会在遇到 RuntimeException 的时候才会回滚,加上 rollbackFor=Exception.class ,可以让事物在遇到⾮运⾏时异常时也回滚。
8.JAP
如何使⽤JPA在数据库中⾮持久化⼀个字段
(1)static String transient1; // not persistent because of static
(2)final String transient2 = “Satish”; // not persistent because of final
(3)transient String transient3; // not persistent because of transient
(4)@Transient
String transient4; // not persistent because of @Transient
后两种用的比较多
9.SpringCloud的基本面试知识点
https://blog.csdn.net/u013469325/article/details/105668828/
参考文档
https://blog.csdn.net/u010285974/article/details/104964747/
https://www.cnblogs.com/songanwei/p/9417343.html