Spring面试总结

介绍spring框架

Spring 为简化企业级应用开发而生的一个开源框架. 使用 Spring 可以使简单的 JavaBean 实现以前只有 EJB 才能实现的功能.
Spring 是一个 IOC(DI) 和 AOP 容器框架。

IOC(Inversion of Control,控制反转)

  • 其思想是反转资源获取的方向. 传统的资源查找方式要求组件向容器发起请求查找资源. 作为回应, 容器适时的返回资源. 而应用了 IOC 之后, 则是容器主动地将资源推送给它所管理的组件, 组件所要做的仅是选择一种合适的方式来接受资源. 这种行为也被称为查找的被动形式

DI(Dependency Injection ,依赖注入)

  • IOC 的另一种表述方式:即组件以一些预先定义好的方式(例如: setter 方法)接受来自如容器的资源注入. 相对于 IOC 而言,这种表述更直接。

AOP(Aspect-Oriented Programming, 面向切面编程)

  • 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, 面向对象编程) 的补充.
  • AOP 的主要编程对象是切面(aspect), 而切面模块化横切关注点.
  • 在应用 AOP 编程时, 仍然需要定义公共功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类. 这样一来横切关注点就被模块化到特殊的对象(切面)里.

具体描述 Spring:

  • 轻量级:Spring 是非侵入性的 ,您不应该被迫在您的业务或域模型中引入特定于框架的类和接口。但是,在某些地方,Spring Framework确实为您提供了将Spring Framework特定的依赖项引入代码库的选项
  • 依赖注入(DI — dependency injection、IOC)
  • 面向切面编程(AOP — aspect oriented programming)
  • 容器: Spring 是一个容器, 因为它包含并且管理应用对象的生命周期
  • 框架: Spring 实现了使用简单的组件配置组合成一个复杂的应用. 在 Spring 中可以使用 XML 和 Java 注解组合这些对象
  • 一站式:在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方类库 (实际上 Spring 自身也提供了展现层的 SpringMVC 和 持久层的 Spring JDBC)

关于IOC/DI更通俗的解释 https://www.cnblogs.com/liubin1988/p/8909610.html

Spring 中的核心模块

https://blog.csdn.net/saizzzzzz/article/details/51494458

Spring的优点

  1. 降低了组件之间的耦合性 ,实现了软件各层之间的解耦
  2. 可以使用容易提供的众多服务,如事务管理,消息服务等
  3. 容器提供单例模式支持
  4. 容器提供了AOP技术,利用它很容易实现如权限拦截,运行期监控等功能
  5. 容器提供了众多的辅助类,能加快应用的开发
  6. spring对于主流的应用框架提供了集成支持,如hibernate,JPA,Struts等
  7. spring属于低侵入式设计,代码的污染极低
  8. spring的DI机制降低了业务对象替换的复杂性
  9. Spring的高度开放性,并不强制应用完全依赖于Spring,开发者可以自由选择spring 的部分或全部

spring中的核心类有那些,各有什么作用?

省略

Spring中用到的设计模式

参考:https://www.cnblogs.com/kyoner/p/10949246.html

  1. 工厂设计模式

Spring使用工厂模式可以通过 BeanFactory ApplicationContext 创建 bean 对象。
BeanFactory 仅提供了最基本的依赖注入支持,ApplicationContext 扩展了BeanFactory ,除了有BeanFactory的功能之外还有额外更多功能
ApplicationContext的三个实现类:
ClassPathXmlApplication:把上下文文件当成类路径资源。
FileSystemXmlApplication:从文件系统中的 XML 文件载入上下文定义信息。
XmlWebApplicationContext:从Web系统中的XML文件载入上下文定义信息。

  1. 单例设计模式
  • 在我们的系统中,有一些对象其实我们只需要一个,比如说:线程池、缓存、注册表、日志对象。如果制造出多个实例就可能会导致一些问题的产生,比如:程序的行为异常、资源使用过量、或者不一致性的结果。
  • 使用单例模式的好处:
    对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销;
    由于new操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻GC压力,缩短GC停顿时间。
  • Spring中bean的作用域
    singleton: 单例的,容易只创建一次
    prototype : 每次请求都会创建一个新的 bean 实例。
    request : 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
    session : 每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。-
  • Spring实现单例的方式:
    xml:
    注解:@Scope(value = “singleton”)
  • Spring通过ConcurrentHashMap实现单例注册表的特殊方式实现单例模式。
  1. 代理设计模式
  • AOP(Aspect-Oriented Programming):面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
  • Spring AOP就是基于动态代理的,如果要代理的对象实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,Spring AOP会使用Cglib,这时候Spring AOP会使用Cglib生成一个被代理对象的子类来作为代理
  • Spring AOP 和 AspectJ AOP 有什么区别?
    Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。 Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)
  1. 模板方法
  • 模板方法模式是一种行为设计模式,它定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。 模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤的实现方式。
  • Spring 中 jdbcTemplatehibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。一般情况下,我们都是使用继承的方式来实现模板模式,但是 Spring 并没有使用这种方式,而是使用Callback 模式与模板方法模式配合,既达到了代码复用的效果,同时增加了灵活性。
  1. 观察者模式
  • 观察者模式是一种对象行为型模式。它表示的是一种对象与对象之间具有依赖关系,当一个对象发生改变的时候,这个对象所依赖的对象也会做出反应。Spring 事件驱动模型就是观察者模式很经典的一个应用。

  • Spring 事件驱动模型中的三种角色

  1. 事件角色
    Spring面试总结_第1张图片
    ApplicationEvent (org.springframework.context包下)充当事件的角色,这是一个抽象类,它继承了java.util.EventObject并实现了 java.io.Serializable接口。
    Spring 中默认存在以下事件,他们都是对 ApplicationContextEvent的实现(继承自ApplicationContextEvent):
    ContextStartedEvent:ApplicationContext 启动后触发的事件;
    ContextStoppedEvent:ApplicationContext 停止后触发的事件;
    ContextRefreshedEvent:ApplicationContext 初始化或刷新完成后触发的事件;
    ContextClosedEvent:ApplicationContext 关闭后触发的事件。

  2. 事件监听者角色
    ApplicationListener 充当了事件监听者角色,它是一个接口,里面只定义了一个 onApplicationEvent()方法来处理ApplicationEvent,在 Spring中我们只要实现 ApplicationListener 接口实现 onApplicationEvent() 方法即可完成监听事件
    什么是Spring beans?

  3. 事件发布者角色
    ApplicationEventPublisher 充当了事件的发布者,它也是一个接口。
    ApplicationEventPublisher 接口的publishEvent()这个方法在AbstractApplicationContext类中被实现,阅读这个方法的实现,你会发现实际上事件真正是通过ApplicationEventMulticaster来广播出去的。

  1. 适配器模式
  • 适配器模式(Adapter Pattern) 将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。
  • spring AOP中的适配器模式
    我们知道 Spring AOP 的实现是基于代理模式,但是 Spring AOP 的增强或通知(Advice)使用到了适配器模式,与之相关的接口是AdvisorAdapter 。Advice 常用的类型有:BeforeAdvice(目标方法调用前,前置通知)、AfterAdvice(目标方法调用后,后置通知)、AfterReturningAdvice(目标方法执行结束后,return之前)等等。每个类型Advice(通知)都有对应的拦截器:MethodBeforeAdviceInterceptorAfterReturningAdviceAdapterAfterReturningAdviceInterceptor。Spring预定义的通知要通过对应的适配器,适配成 MethodInterceptor接口(方法拦截器)类型的对象(如:MethodBeforeAdviceInterceptor 负责适配 MethodBeforeAdvice)。
  • spring MVC中的适配器模式
    在Spring MVC中,DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的 Handler。解析到对应的 Handler(也就是我们平常说的 Controller 控制器)后,开始由HandlerAdapter 适配器处理。HandlerAdapter 作为期望接口,具体的适配器实现类用于对目标类进行适配,Controller 作为需要适配的类。
  1. 装饰者模式
  • 装饰者模式可以动态地给对象添加一些额外的属性或行为。相比于使用继承,装饰者模式更加灵活。简单点儿说就是当我们需要修改原有的功能,但我们又不愿直接去修改原有的代码时,设计一个Decorator套在原有代码外面。其实在 JDK 中就有很多地方用到了装饰者模式,比如 InputStream家族,InputStream 类下有 FileInputStream (读取文件)BufferedInputStream (增加缓存,使读取文件速度大大提升)等子类都在不修改InputStream 代码的情况下扩展了它的功能。
  • Spring 中配置 DataSource 的时候,DataSource 可能是不同的数据库和数据源。我们能否根据客户的需求在少修改原有类的代码下动态切换不同的数据源?这个时候就要用到装饰者模式。Spring 中用到的包装器模式在类名上含有 Wrapper或者 Decorator。这些类基本上都是动态地给一个对象添加一些额外的职责

如何给Spring 容器提供配置元数据

  1. 基于XML的配置元数据
  2. 基于注解的配置元数据
  3. 基于Java的配置元数据。默认情况下,方法名就是Bean的名称。

什么是基于注解的配置元数据呢?

  • 比如web项目中的Contrller层,Service层,Dao层均有想用的注解对应,在对应的类上加上诸如@Controller,@Service@Repository@Component的注解。
  • 要注意的是,使用该种方式需要配合@ComponentScan来使用,如果使用的是SpringBoot,扫描组件的默认的路径为与Application.class同级的包

什么是基于Java的配置元数据呢?

  • 使用@Configuration注解需要作为配置的类,表示该类将定义Bean的元数据
  • 使用@Bean注解相应的方法,该方法名默认就是Bean的名称,该方法返回值就是Bean的对象。
  • AnnotationConfigApplicationContext或子类进行加载基于java类的配置。
  @Configuration
  class ApplicationContextConfig {
  @Bean
     public String message() {
        return "hello";
     }
  }
  
//然后还需要一个测试类,来查看配置是否成功

  public class ConfigurationTest {
    public static void main(String[] args) {
      AnnotationConfigApplicationContext ctx =new AnnotationConfigApplicationContext(ApplicationContextConfig.class);
      System.out.println(ctx.getBean("message"));
    }
  }

bean的装配

  1. 什么是bean装配?
  • 装配,或bean 装配是指在Spring 容器中把bean组装到一起,前提是容器需要知道bean的依赖关系,如何通过依赖注入来把它们装配到一起。
  1. 什么是bean的自动装配?
  • Spring 容器能够自动装配相互合作的bean,这意味着容器不需要和配置,能通过Bean工厂自动处理bean之间的协作。
  1. 自动装配的方式
  1. no:(默认)无自动装配。Bean引用必须由ref元素定义。不建议对较大的部署更改默认设置,因为明确指定协作者可以提供更好的控制和清晰度。在某种程度上,它记录了系统的结构。
  2. byName:按属性名称自动装配。Spring查找与需要自动装配的属性同名的bean。例如,如果bean定义按名称设置为autowire并且它包含一个master属性(即,它有一个 setMaster(…)方法),则Spring会查找名为bean的定义master并使用它来设置属性。
  3. byType::如果容器中只存在一个属性类型的bean,则允许属性自动装配。如果存在多个,则抛出致命异常,这表示您可能不会byType对该bean 使用自动装配。如果没有匹配的bean,则不会发生任何事情(该属性未设置)。
  4. constructor:类似byType但适用于构造函数参数。如果容器中没有构造函数参数类型的一个bean,则会引发致命错误。
  1. 自动装配的局限性是:
  • propertyconstructor-arg设置中的显式依赖项始终覆盖自动装配。不能自动连接简单属性,如基元、字符串和类(比如简单属性的数组)。
  • 自动装配不如显式装配精确。spring管理的对象之间的关系不再被显式地记录下来。
  • 可能无法为可能从Spring容器生成文档的工具提供接线信息。
  • 如果没有可用的唯一bean定义,则抛出异常。
  1. 构造方法注入和设值注入有什么区别?
  • . 通过setter方法设定依赖关系显得更加直观、自然。
  • . 在构造方法注入不支持大部分的依赖注入,因为在调用构造方法中必须传入正确的构造参数,否则的话为报错。

Spring Bean的作用域

  • Spring Framework支持六个范围,其中四个范围仅在您使用Web应用时才可用
Scope Description
singleton (默认)将单个bean定义范围限定为每个Spring IoC容器的单个对象实例。
prototype 将单个bean定义范围限定为任意数量的对象实例。
request 将单个bean定义范围限定为单个HTTP请求的生命周期。也就是说,每个HTTP请求都有自己的bean实例,它是在单个bean定义的后面创建的。仅在具有Web感知的Spring环境中有效。
session 将单个bean定义范围限定为HTTP的生命周期Session。仅在具有Web感知的Spring环境中有效。
application 将单个bean定义范围限定生命周期为ServletContext。仅在具有Web感知的Spring环境中有效。
websocket 将单个bean定义范围限定为生命周期为WebSocket。仅在具有Web感知的Spring环境中有效。

Spring框架中Bean的生命周期

参考:https://blog.csdn.net/w_linux/article/details/80086950

  • 实例化bean对象(通过构造方法或者工厂方法)。
  • 设置对象属性(setter等)(依赖注入)。
  • 如果Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。(和下面的一条均属于检查Aware接口)。
  • 如果Bean实现了BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身。
  • 将Bean实例传递给Bean的前置处理器的postProcessBeforeInitialization(Object var1, String var2)方法。
  • 调用Bean的初始化方法。
  • 将Bean实例传递给Bean的后置处理器的postProcessAfterInitialization(Object var1, String var2)方法。
  • 使用Bean。
  • 容器关闭之前,调用Bean的销毁方法。

初始化方法和销毁方法的指定:2种方式

  1. 在配置文件中指定
    init-method
    destroy-method
  2. 实现 InitializingBean接口,重写afterPropertiesSet()
    实现DisposableBean接口,重写destroy()

实现bean的前置处理器和后置处理器

往容器中添加一个实现BeanPostProcessor接口的对象,并重写postProcessBeforeInitialization(Object var1, String var2),postProcessAfterInitialization(Object var1, String var2)

获得bean的方式

  1. 使用ApplicationContext(可以自己实例ApplicationContext对象或 通过Spring提供的工具类WebApplicationContextUtils获取ApplicationContext对象)
  2. 实现接口ApplicationContextAware
  3. 继承自抽象类ApplicationObjectSupport

Spring 的内部 bean

  • 当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean,为了定义inner bean,在Spring 的 基于XML的 配置元数据中,可以在 或 元素内使用 元素,内部bean通常是匿名的,它们的Scope一般是prototype。

Spring的延迟加载

  • 默认情况下,ApplicationContext实现会急切地创建和配置所有单例 bean,作为初始化过程的一部分。通常,这种预先实例化是可取的,因为配置或周围环境中的错误是立即发现的,而不是几小时甚至几天后。当不希望出现这种情况时,可以通过将bean定义标记为延迟初始化来阻止单例bean的预实例化。延迟初始化的bean告诉IoC容器在第一次请求时创建bean实例,而不是在启动时。

  • 示例:

<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.something.AnotherBean"/>

Spring AOP

  • 面向方面编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP)。OOP中模块化的关键单元是类,而在AOP中,模块化单元是切面。方面实现了跨越多种类型和对象的关注点(例如事务管理)的模块化。
  • 在应用 AOP 编程时, 仍然需要定义公共功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类. 这样一来横切关注点就被模块化到特殊的对象(切面)里.

AOP术语

术语 解释
切面(Aspect) 就是切入点和通知的组合。
通知(Advice) 切面必须要完成的工作,指拦截后要做的事情
目标(Target) 被通知的对象
代理(Proxy) 被应用了增强后,产生了一个代理对象,AOP代理是JDK动态代理或CGLIB代理。
连接点(Joinpoint) 指的是可以被拦截到的点
切点(pointcut) 真正被拦截到的点

通知类型

  • 前置通知(before) - 在目标方法被调用之前调用通知功能
  • 返回通知(after-returning) - 在目标方法成功执行之后调用通知,出现异常则失效
  • 后置通知(after) - 在目标方法完成之后调用通知(不论程序是否出现异常)
  • 异常通知(after-throwing) - 在目标方法抛出异常后调用通知
  • 环绕通知(around) - 通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为

基于XML 方式的切面实现

  1. 定义一个service类,作为被通知的对象
public class Service {
    public void doService(){
        System.out.println("service.............");
    }
}
  1. 定义一个LoggingAspect类,作为切面
public class LoggingAspect {
    public void beforeAdvice() {
        System.out.println("beforeAdvice..........");
    }

    public void afterAdvice() {
        System.out.println("afterAdvice..........");
    }
 }
  1. 配置文件
   
    <bean id="service" class="com.spring.test.Service">bean>

    
    <bean id="loggingAspect" class="com.spring.test.LoggingAspect">bean>

    
    <aop:config>
        
        <aop:pointcut id="pointcut" expression="execution(* com.spring.test.Service.doService())">aop:pointcut>
        
        <aop:aspect ref="loggingAspect" order="2">
            <aop:before method="beforeAdvice" pointcut-ref="pointcut">aop:before>
            <aop:after method="afterAdvice" pointcut-ref="pointcut">aop:after>
        aop:aspect>
		
    aop:config>

基于注解的切面实现

  1. 定义一个service类,作为被通知的对象
@Component
public class Service {
    public void doService() {
        System.out.println("service.............");
    }
}
  1. 定义一个LoggingAspect类,作为切面
//将这个类声明为一个切面,需要放入到IOC容器中,再声明为一个切面
@Component
@Aspect
public class LoggingAspect {
    @Before("execution(* com.spring.test.Service.doService())")
    public void beforeAdvice() {
        System.out.println("beforeAdvice..........");
    }

    @After("execution(* com.spring.test.Service.doService())")
    public void afterAdvice() {
        System.out.println("afterAdvice..........");
    }
}
  1. 配置
    
	<context:component-scan base-package="com.spring.test">context:component-scan>
	
	
	<aop:aspectj-autoproxy>aop:aspectj-autoproxy>

ApplicationContext通常的实现

  • FileSystemXmlApplicationContext :此容器从一个XML文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。
  • ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。
  • AnnotationConfigApplicationContext :用于基于注解的配置
  • WebXmlApplicationContext:此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean。

BeanFactory和 Application contexts 有什么区别

  • ApplicationContext继承了BeanFactory,BeanFactory是Spring中比较原始的Factory,它不支持AOP、Web等Spring插件,而ApplicationContext不仅包含了BeanFactory的所有功能,还支持Spring的各种插件,还以一种面向框架的方式工作以及对上下文进行分层和实现继承。
  • BeanFactory是Spring框架的基础设施,面向Spring本身;而ApplicationContext面向使用Spring的开发者,相比BeanFactory提供了更多面向实际应用的功能,几乎所有场合都可以直接使用ApplicationContext而不是底层的BeanFactory。
  • BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化,这样,我们就不能发现一些存在的Spring的配置问题。而ApplicationContext则相反,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误。

ApplicationContext包还提供了以下的功能:

  1. 利用MessageSource进行国际化
  2. 强大的事件机制(Event)
  3. 底层资源的访问
  4. 对Web应用的支持

Spring中IOC 对象创建的过程。

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

  • 可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,首先系统解析xml文件,将xml文件的信息保存在一个Map中,然后利用编程语言的的反射编程,根据配置文件中给出的类的信息生成相应的对象。存放在容器中,提高灵活性和可维护性

Bean 的配置方式

  1. 通过全类名(反射)
  2. 通过工厂方法(静态工厂方法 & 实例工厂方法)factory-method 属性里指定工厂方法的名称. 最后, 使用 元素为该方法传递方法参数,在实例工厂情况下在 bean 的>code> factory-bean 属性里指定拥有该工厂方法的 Bean
  3. 实现FactoryBean接口,

什么是IOC,什么又是DI,他们有什么区别

  • IOC是控制反转:创建对象实例的控制权从代码控制剥离到IOC容器控制(之前的写法,由程序代码直接操控使用new关键字),实际就是你在xml文件控制,控制权的转移是所谓反转,侧重于原理。

  • DI是依赖注入:创建对象实例时,为这个对象注入属性值或其它对象实例,侧重于实现。

区别

  1. 它们是spring核心思想的不同方面的描述。

  2. 依赖注入和控制反转是对同一件事情的不同描述,从某个方面讲,就是它们描述的角度不同。依赖注入是从应用程序的角度在描述,可以把依赖注入描述完整点:应用程序依赖容器创建并注入它所需要的外部资源;而控制反转是从容器的角度在描述,描述完整点:容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源。

Spring注解

什么是基于Java的Spring注解配置? 给一些注解的例子

  • 基于Java的配置,允许你在少量的Java注解的帮助下,进行你的大部分Spring配置而非通过XML文件。

  • 以@Configuration 注解为例,它用来标记类可以当做一个bean的定义,被Spring IOC容器使用。另一个例子是@Bean注解,它表示此方法将要返回一个对象,作为一个bean注册进Spring应用上下文。

什么是基于注解的容器配置?

  • 相对于XML文件,注解型的配置依赖于通过字节码元数据装配组件,而非尖括号的声明。

  • 开发者通过在相应的类,方法或属性上使用注解的方式,直接组件类中进行配置,而不是使用xml表述bean的装配关系。

怎样开启注解装配?

  • 注解装配在默认情况下是不开启的,为了使用注解装配,我们必须在Spring配置文件中配置 元素。

常用注解

  1. @Autowired
    @Autowired 注解自动装配具有兼容类型的单个 Bean属性
    构造器, 普通字段(即使是非 public), 一切具有参数的方法都可以应用@Authwired 注解
    默认情况下, 所有使用 @Authwired 注解的属性都需要被设置. 当 Spring 找不到匹配的 Bean 装配属性时, 会抛出异常, 若某一属性允许不被设置, 可以设置 @Authwired 注解的 required 属性为 false

  2. @Qualifier
    当 IOC 容器里存在多个类型兼容的 Bean 时, 通过类型的自动装配将无法工作. 此时可以在 @Qualifier 注解里提供 Bean 的名称. Spring 允许对方法的入参标注 @Qualifiter 已指定注入 Bean 的名称

  3. @Resource
    要求提供一个 Bean 名称的属性,若该属性为空,则自动采用标注处的变量或方法名作为 Bean 的名称

  4. @Inject
    @Autowired 注解一样也是按类型匹配注入的 Bean, 但没有 reqired 属性

  5. @Component
    @Component ,用于标注一个普通的类
    @Controller 用于标注一个控制器类
    @Service 用于标注业务逻辑类
    @Repository 用于标注DAO数据访问类
    这几个注解没有什么区别,都是将bean加入到容器,主要用于区别不同的组件类,提高代码的可读性,

  6. @DepondsOn
    该注解也是配合@Component这类注解使用,用于强制初始化其他bean

  7. @Scope()
    该注解和@Component这一类注解联合使用,用于标记该类的作用域,默认singleton。也可以和@Bean一起使用,此时@Scope修饰一个方法。

spring事务

  • 事务是并发控制的单位,是用户定义的一个操作序列,这些操作的集合是不可分割的,要么全部都做,要么一个都不做

事物的ACID特性

特性 描述
原子性
Atomicity
表示事务内操作不可分割,要么都成功,要么都失败
一致性
Consistency
要么都成功,要么都失败,失败了要对事务内前面的操作要回滚,保证关系数据的完整性以及业务逻辑上的一致性。
隔离性
Isolation
一个事务开始后,不能被其他事物干扰,这里就涉及到隔离级别。
持久性
Durabuility
意味着在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。

Spring管理事务有几种方式?具体执行流程以及原理

答:有两种方式:

1、编程式事务,在代码中硬编码。(不推荐使用)

2、声明式事务,在配置文件中配置(推荐使用)

声明式事务又分为两种:

  1. 基于XML的声明式事务
<bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="dataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>    
        <property name="url" value="jdbc:mysql:///spring"/>    
        <property name="username" value="root"/>    
        <property name="password" value="tiger"/>    
    bean>    
<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	bean>
	
	<tx:advice id="TestAdvice" transaction-manager="transactionManager">
		
		<tx:attributes>
			<tx:method name="save*" />
			<tx:method name="del*" />
			<tx:method name="update*" />
			<tx:method name="add*"/>
			<tx:method name="*" />
		tx:attributes>
	tx:advice>
	<aop:config>
		
		<aop:pointcut id="services"
			expression="execution(* com.website.service.*.*(..))" />
		<aop:advisor pointcut-ref="services" advice-ref="TestAdvice" />
	aop:config>

tx:method的属性:

  • name 是必须的,表示与事务属性关联的方法名(业务方法名),对切入点进行细化。通配符()可以用来指定一批关联到相同的事务属性的方法。 如:'get’、‘handle*’、'on*Event’等等.

  • propagation 不是必须的 ,默认值是REQUIRED ,表示事务传播行为, 包括REQUIRED,SUPPORTS,MANDATORY,REQUIRES_NEW,NOT_SUPPORTED,NEVER,NESTED

  • isolation 不是必须的 默认值DEFAULT ,表示事务隔离级别(数据库的隔离级别)

  • timeout 不是必须的 默认值-1(永不超时)表示事务超时的时间(以秒为单位)

  • read-only 不是必须的 默认值false不是只读的 ,表示事务是否只读?

  • no-rollback-for 不是必须的 ,表示不被触发进行回滚的 Exception(s);

  • 任何 RuntimeException将触发事务回滚,但是任何 checked Exception将不触发事务回滚

  1. 基于注解的声明式事务
        
	<bean id="transactionManager" 
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource">property>
	bean>
	
	<tx:annotation-driven transaction-manager="transactionManager"/>
  • 使用@Transactional注解方法
@Transactional(propagation=Propagation.REQUIRES_NEW,
			isolation=Isolation.READ_COMMITTED,
			noRollbackFor={UserAccountException.class},
			rollbackFor = IOException.class,
			readOnly=false,
			timeout=3)
	public void purchase(String username, String isbn) {}

Spring事务隔离级别:

事物并发的相互影响脏读,不可重复读,幻读。

隔离级别 脏读 不可重复读 幻读
读未提交:Read Uncommited
读已提交:Read commited ×
可重复读:Repeatable Read × ×
可串行化:Serializable × × ×

spring的事务传播行为:

  • spring事务的传播行为说的是事务方法被另一个事务方法调用时, 事务应该如何传播。
传播属性 描述
PROPAGATION_REQUIRED 如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
PROPAGATION_REQUIRES_NEW 创建新事务,无论当前存不存在事务,都创建新事务。
PROPAGATION_SUPPORTS 支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。‘
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_MANDATORY 支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

Spring框架中的单例Beans是线程安全的么?

  • Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的Spring bean并没有可变的状态(比如Serview类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。
  • 最浅显的解决办法就是将多态bean的作用域由“singleton”变更为“prototype”。

Spring如何处理线程并发问题?

  • Spring使用ThreadLocal解决线程安全问题。

  • 我们知道在一般情况下,只有有状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态采用ThreadLocal进行处理,让它们也成为线程安全的状态,因为有状态的Bean就可以在多线程中共享了。

  • ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。

  1. 在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。
  2. 而ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
  3. 概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。

你可能感兴趣的:(面试整理)