Spring相关框架面试
* 如有错误请指正
1、SpringMvc
-
SpringMvc的工作原理图
-
SpringMVC工作流程描述
1、客户端发送请求到前端控制器。
2、前端控制器DispatcherServlet根据请求查找对应的处理器映射器HandleMapping。
3、处理器映射器根据用户请求,找到对应的处理器执行链并返回给前端控制器。
4、前端控制器请求处理器适配器执行对应的Handler,即处理器方法。
5、Handler处理器执行完毕后,返回处理器适配器一个ModelAndView对象。
6、处理器适配器接收到返回的ModelAndView后,返回给前端控制器。
7、前端控制器接收到ModelAndView后,请求视图解析器,对视图进行解析。
8、视图解析器根据view匹配对应的视图,然后返回给前端控制器。
9、前端控制器结合视图和Model中的数据进行视图渲染。
10、前端控制器响应客户端请求。
2、Spring
-
谈谈Spring的了解
- 简单来说Spring是一个轻量级的框架,它的主要核心内容为Spring IOC和Spring AOP。(详细请往下)
-
Spring IOC
- 谈谈你对ioc的了解
- spring ioc控制反转,在之前也叫做DI(依赖注入),本身是一个容器,用来装配管理bean对象。
- 简单来说在之前对象的实例化由自己控制,有了ioc之后,统一交给了spring容器来管理,在需要使用时,由spring容器进行实例化创建,这就叫控制反转,而实例化的所有对象就是spring beans。
- 依赖注入的方式
- 通过构造方法进行注入。
- 通过setter注入。
- 通过接口注入。
- Spring中有多少种IOC容器
- Spring提供了两种IOC容器,分别为BeanFacotry和ApplicationContext。
- BeanFactory由Spring-beans项目提供,ApplicationContext由Spring-context提供。(在源码中可以查到)
- ApplicationContext容器包括 BeanFactory 容器的所有功能。
- ApplicationContext是BeanFactory的子接口,ApplicationContext提供了更完整的功能:
- 继承了MessageSource,支持国际化。
- 统一的资源文件访问方式(ResourceLoader & ResourcePatternResolver)。
- 提供在监听器中注册bean事件 。
- 同时加载多个配置文件。
- 两者之间的区别:
- BeanFactory采用的是延迟加载形式来注入Bean,即只有在使用到Bean的时候,才对该Bean进行实例化。
- ApplicationContext是在容器启动时,一次性创建了所有的bean。
- ApplicationContext相对来说占用内存,启动慢,但是可以监测到对应的依赖是否注入。而BeanFactory只有在调用的时候,如果有异常才会抛出。
- 简述IOC机制
- IOC实现原理简单来说就是工厂模式和反射机制实现的。
- 谈谈你对ioc的了解
-
Spring AOP
- 谈谈你对aop的了解
- aop面向切面编程,是一种编程思想,对oop的一种补充,能在不改变原有业务逻辑的情况下,增强横切逻辑代码,常见使用场景有事务管理、日志。。
- aop主要内容为:Aspect(切面)、PointCut(切点)和Advice(通知)等。
- Advice(通知)
- 通知包含了Before(前置通知)、After(后置通知)、After Returning(返回后通知)、After Throwing(抛出异常后通知)和Around(环绕通知)。
- Before,在JoinPonit之前执行,通常使用注解@Before表示。
- After,在JoinPonit之后执行,通常使用注解@After表示。
- After Returning,在JoinPonit正常执行完成后,通常使用注解@AfterReturning表示。
- After Throwing,在JoinPonit执行出现异常后,通常使用注解@AfterThrowing表示。
- Around,在JoinPonit之前和之后各执行一次,通常使用注解@Around表示。
- Aop实现方式
- 静态代理:
- 动态代理:基于jdk和cglib。
- 如何使用AOP
- 基于xml方式实现。
- 基于注解方式实现。
- 目前通常使用的是注解方式,通过使用@Aspect注解。
- 谈谈你对aop的了解
-
Spring Bean
- spring bean的生命周期。
- spring bean的作用域
- Spring 框架支持以下五个作用域,分别为 singleton、prototype、request、session 和 global sessio。
- singleton:在spring IoC容器仅存在一个单例Bean实例,默认值。
- prootype:每次请求都返回一个新的bean。
- request:每次 HTTP 请求都会产生一个新的 Bean 实例,并且该 Bean 仅在当前 HTTP 请求内有效。
- session:每一个的 Session 都会产生一个新的 Bean 实例,同时该 Bean 仅在当前 HTTP Session 内有效,同一个HTTP Session共享一个Bean,不同Session使用不同的Bean。
- global sessio:在spring5中已经废弃,一般用于Portlet应用环境,该作用域仅适用于WebApplicationContext环境。
- 详细描述:
- 在BeanDefinition接口中,拥有singleton和prototype两种作用域。
-
1 public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { 2 3 /** 4 * Scope identifier for the standard singleton scope: {@value}. 5 * <p>Note that extended bean factories might support further scopes. 6 * @see #setScope 7 * @see ConfigurableBeanFactory#SCOPE_SINGLETON 8 */ 9 String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; 10 11 /** 12 * Scope identifier for the standard prototype scope: {@value}. 13 * <p>Note that extended bean factories might support further scopes. 14 * @see #setScope 15 * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE 16 */ 17 String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; 18 }
- 当启动容器时,便会往BeanFactory中注册多个Scope。
-
1 public abstract class WebApplicationContextUtils { 2 3 public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, 4 @Nullable ServletContext sc) { 5 6 beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope()); 7 beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope()); 8 if (sc != null) { 9 ServletContextScope appScope = new ServletContextScope(sc); 10 beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope); 11 // Register as ServletContext attribute, for ContextCleanupListener to detect it. 12 sc.setAttribute(ServletContextScope.class.getName(), appScope); 13 } 14 15 beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory()); 16 beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory()); 17 beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory()); 18 beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory()); 19 if (jsfPresent) { 20 FacesDependencyRegistrar.registerFacesDependencies(beanFactory); 21 } 22 } 23 }
- 其他作用域处理逻辑
-
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory { protected <T> T doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { //创建bean实例 // Create bean instance. if (mbd.isSingleton()) { //singleton,单例 sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } }); beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } else if (mbd.isPrototype()) { //prototype创建一个新的实例 // It's a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { //既不是singleton也不是prototype String scopeName = mbd.getScope(); if (!StringUtils.hasLength(scopeName)) { throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'"); } //通过scope的名称获取注册的实例,Scope接口的实现类,在 // org.springframework.web.context.support.WebApplicationContextUtils.registerWebApplicationScopes注册的 Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { Object scopedInstance = scope.get(beanName, () -> { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } }); beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new ScopeNotActiveException(beanName, scopeName, ex); } } }
- spring中单例bean的线程安全
- 对于单例bean来说,所有线程共享一个bean,所以存在资源竞争。如果是无状态的bean,那么就不存在线程安全的问题。如果是有状态的bean,spring一般提供了ThreadLocal去解决线程安全的问题,比如:RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等。
- 无状态bean(Stateless Bean):bean一旦实例化就被加进会话池中,各个用户都可以共用;即使用户已经消亡,bean 的生命期也不一定结束,它可能依然存在于会话池中,供其他用户调用;是线程安全的。
- 有状态bean(Stateful Bean):有数据存储功能,每个用户有自己特有的一个实例,在用户的生存期内,bean 保持了用户的信息,即“有状态”;一旦调用结束或实例结束,bean 的生命期也将结束,是非线程安全的。
-
Spring中使用了哪些设计模式
- 工厂设计模式:Spring使用工厂模式通过BeanFactory或ApplicationContext获得bean对象
- 单例设计模式:Spring中bean的默认工作域是单例的(singleton)。
- 代理设计模式:Spring Aop功能的实现。
- 模板方法模式:Spring中的JdbcTemplate
- 包装器设计模式:
- 观察者模式:Spring 事件驱动模型就是观察者模式。
- 适配器模式:Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配
Controller
。
-
Spring自动装配
- Spring自动装配支持5种模式
- no – 缺省情况下,自动配置是通过“ref”属性手动设定。
- byName – 根据属性名称自动装配。如果一个bean的名称和其他bean属性的名称是一样的,将会自装配它。
- byType – 按数据类型自动装配。如果一个bean的数据类型是用其它bean属性的数据类型,兼容并自动装配它。
- constructor – 它通过调用类的构造函数来注入依赖项。它有大量的参数。
- autodetect – 如果找到默认的构造函数,使用“自动装配用构造”; 否则,使用“按类型自动装配”。
- Spring自动装配支持5种模式
-
Spring注解
- @Component、@Controller、@Repository、@Service的区别:
- @Component将Java类标记成Bean,是一个通用型的注解。
- @Controller是SpringMVC的一个控制器注解。
- @Repository是用于Dao层的注解,和mybatis提供的@Mapper注解一样用dao层。
- @Service是用于服务层的注解。
- @Autowired和@Qualifier
- @Autowired默认注入方式为byType,对应属性required默认为true,默认情况下必须要求依赖对象必须存在。如果要允许null值,可以设置它的required属性为false。
- @Qualifier通常和@Autowired一起使用,当有多个实现时,通过@Qualifier注解来显式指定name值,指明要使用哪个具体的实现类。
- 和@Autowired有同样功能的@Resource注解。
- @Autowired注解是Spring提供的,而@Resource注解是J2EE本身提供的
- @Autowird注解默认通过byType方式注入,而@Resource注解默认通过byName方式注入
- @Component、@Controller、@Repository、@Service的区别:
-
Spring事务的隔离级别
- spring的事务隔离级别是有五种的,比数据库是多一种的。
- DEFAULT(默认):这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应。
- READ_UNCOMMITTED(读未提交)
- READ_COMMITTED(读已提交)
- REPEATABLE_READ(可重复读)
- REPEATABLE_READ(可重复读)
- spring的事务隔离级别是有五种的,比数据库是多一种的。
-
Spring事务的传播特性
- REQUIRED:默认的传播特性,业务方法需要在一个事务中运行,如果一个方法已经处在一个事务中那么就加入到这个事务中,否则就会创建一个事务。(如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。)
- NEVER:指定的业务方法绝对不能在事务范围内运行,如果业务方法在某个事务中执行,就会抛异常,只有业务方法没有任何事务才正常执行。(以非事务方式执行,如果当前存在事务,则抛出异常。 )
- MANDATORY:该属性指定业务方法只能在一个已经存在的事务中执行,业务方法不能自己发起自己的事务,如果业务方法不存在事务,容器就抛异常。(支持当前事务,如果当前没有事务,就抛出异常。)
- SUPPORTS:如果业务方法中已经在某个事务中被调用,则方法就成为事务的一部分,如果外部业务方法没有开启事务,supports该方法也会在没有事务的环境中执行。(支持当前事务,如果当前没有事务,就以非事务方式执行。)
- NOT_SUPPORTED:如果该业务方法在一个事务中被调用,那么当前的事务会被挂起,执行该业务方法,方法执行完毕唤醒被挂起的事务,如果业务方法不在一个事务中执行,该方法也不会开事务。不管是否在有无事务的环境中执行都不开启事务。(以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。)
- REQUIRES_NEW:不管是否存在事务,业务方法总会自己开启一个事务,如果在已有事务的环境中调用,已有事务会被挂起,新的事务会被创建,直到业务方法调用结束,已有事务才被唤醒。(新建事务,如果当前存在事务,把当前事务挂起。)
- NESTED:如果业务方法在一个事务中执行,就在这个事务中嵌套,如果没有事务按着required执行,开启单独的事务,这种事务有多个事务的保存点,内部事务的回滚对外部事务没有影响。(支持当前事务,新增Savepoint点,与当前事务同步提交或回滚。)