关于Spring的一些问题
单例bean是线程安全的吗
Spring 的单例bean不是线程安全的。如果bean中定义了可修改的成员变量,就可能会有其他线程对其进行修改,所以线程不是安全的。我们可以把单例的bean修改成多例模式或者加锁来解决。
关于AOP
AOP是面向切面编程,主要是把公共模块抽离代码,降低耦合。
项目中有没有用到AOP?
用到过,主要是使用环绕通知和切点的方式,对controller中的方法进行参数拦截,获取到参数后进行判断,如果不满足aop定义的规则则调用自己定义的错误方法报错。
关于Spring事务
Spring事务主要分为两种,编程式事务和声明式事务。其中编程式事务需使用方法实现,对业务代码有入侵性,很少使用。而声明式事务是建立在AOP之上的,主要是通过AOP对方法前后进行拦截,方法执行完后根据运行情况进行提交或回滚。
事务失效
事务失效有很多种情况。首先是异常捕获处理不当会导致事务失效。在trycatch中如果我们自己处理了异常,事务无法得知,则会出现事务失效。正确的解决方法是将异常抛出,让事务知晓代码出了异常,从而进行回滚。其次是Spring默认只会回滚非检查异常,在方法中定义了检查类异常会导致事务不知道出现了异常,从而无法回滚。我们可以配置rollback属性为受检异常定义回滚。最后Spring的事务只能对Public的方法使用,如果方法是private,则无法使用事务。
关于Spring bean
Spring bean的生命周期: 主要分为实例化,属性赋值,初始化,销毁四个阶段。
实例化:Spring容器在加载bean时,会实例化bean,并调用bean的构造方法,将bean的依赖注入到bean中。
属性赋值:Spring容器会调用set方法将属性值注入到bean中。
初始化:Spring容器会调用bean的初始化方法,完成bean的一些初始化工作。
销毁:当容器关闭时,Spring会调用bean的销毁方法,完成一些资源的释放。
bean的定义方法即依赖注入
关于bean的定义,spring有三种方法。
1.xml文件定义:通过xml文件定义bean,并通过标签属性来设置bean的属性值。
2.注解定义:通过注解来定义bean,并通过注解的属性来设置bean的属性值。主要有@Component、@Service、@Repository、@Controller四个注解。
3.java配置:通过java配置类来定义bean,并通过@Bean注解来设置bean的属性值。
关于Bean依赖的注入,spring中也有三种方法。
1.构造方法注入:通过构造方法注入,Spring容器会自动调用构造方法,并将依赖注入到bean中。
例1
2
3
4
5
6
7
8
9
10
public class MyService {
private final MyRepository myRepository;
public MyService(MyRepository myRepository) {
this.myRepository = myRepository;
}
// ...
}
2.setter方法注入:通过setter方法注入,Spring容器会自动调用setter方法,并将依赖注入到bean中。
例1
2
3
4
5
6
7
8
9
10
11
public class MyService {
private MyRepository myRepository;
public void setMyRepository(MyRepository myRepository) {
this.myRepository = myRepository;
}
// ...
}
3.注解注入:通过注解@Autowired,@Resource,Spring容器会自动注入依赖。
关于@Autowired和@Resource,他们两个虽然都是用来注入依赖的,但是有一定差别。@Autowired是spring所提供的注入方法,默认byType注入,可以用在构造方法、方法、字段上。@Resource是J2EE提供的注入方法,默认byName注入,只能用在字段上。
例1
2
3
4
5
6
7
public class MyService {
private MyRepository myRepository;
// ...
}
bean的循环依赖
当有两个及以上的bean互相调用时会发生循环依赖,最后形成闭环。Spring中使用了三级缓存机制来避免循环依赖问题。一级缓存中存放已经具有完整生命周期,初始化完成的bean。二级缓存中存放早期的bean。而三级缓存中存放的是对象工厂的引用,是用来创建bean的。Spring在创建bean时,首先会从一级缓存中查找,如果没有找到,则会从二级缓存中查找,如果还是没有找到,则会从三级缓存中查找,如果还是没有找到,则会使用对象工厂创建bean。
但是如果构造方法中出现了循环依赖问题,Spring的三级缓存对其是没有作用的。这时候就需要我们在方法中加上@Lazy懒加载注解,这样Spring在创建bean时,会延迟加载bean,直到第一次使用时才会创建。
关于Spring mvc的执行流程
1.用户发出请求到前端控制器DispatcherServlet。
2.DispatcherServlet收到请求后,调用HandlerMapping查找Handler。
3.HandlerMapping找到具体的处理器,生成处理器对象及处理器拦截器(如果有),再一起返回给DispatcherServlet。
4.DispatcherServlet调用HandlerAdapter适配器,对处理器进行执行。
5.HandlerAdapter根据处理器类型调用相应的处理器适配器。
6.在方法中添加@RequestMapping注解,可以指定请求的URL和请求方法。
7.通过HttpMessageConverter来返回结果转换为JSON并响应。
关于Springboot的自动装配原理
Spring Boot 通过@EnableAutoConfiguration开启自动装配,通过 SpringFactoriesLoader 最终加载META-INF/spring.factories中的自动配置类实现自动装配,自动配置类其实就是通过@Conditional按需加载的配置类,想要其生效必须引入spring-boot-starter-xxx包实现起步依赖.



