单例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
@Service
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
@Service
public class MyService {
private MyRepository myRepository;

@Autowired
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
@Service
public class MyService {
@Autowired
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包实现起步依赖.