跳至主要內容

spring

HeChuangJun约 6741 字大约 22 分钟

1. Spring是什么?特性?

  • Spring是一个轻量级、非入侵式的控制反转(IoC)和面向切面(AOP)的框架。
  • IoC和DI的支持:管理对象生命周期和依赖关系
  • AOP编程的支持:面向切面编程可以实现对程序进行权限拦截、运行监控等切面功能。
  • 声明式事务的支持:支持通过配置就来完成对事务的管理,而不需要通过硬编码的方式。
  • 快捷测试的支持:支持Junit注解测试Spring程序。
  • 快速集成功能:方便集成各种优秀框架
  • 复杂API模板封装:对JDBC、JavaMail等提供了模板化的封装,降低应用难度

2. Spring有哪些模块?

  • Spring Core:Spring 核心,它是框架最基础的部分,提供 IoC 和依赖注入 DI 特性。
  • Spring Context:Spring 上下文容器,它是 BeanFactory 功能加强的一个子接口。
  • Spring Web:它提供 Web 应用开发的支持。
  • Spring MVC:它针对 Web 应用中 MVC 思想的实现。
  • Spring DAO:提供对 JDBC 抽象层,简化了 JDBC 编码,同时,编码更具有健壮性。
  • Spring ORM:它支持用于流行的 ORM 框架的整合,比如:Spring + Hibernate、Spring + iBatis、Spring + JDO 的整合等
  • Spring AOP:即面向切面编程,它提供了与 AOP 联盟兼容的编程实现。

3. Spring常用注解?

  • Web:
    • @Controller:组合注解(组合了@Component注解),应用在MVC层(控制层)。
    • @RestController:@Controller和@ResponseBody的组合注解,注解在类上则该Controller的所有方法都默认加上了@ResponseBody。
    • @RequestMapping:用于映射Web请求,包括访问路径和参数。Restful接口根据请求类型使用不同的注解:@GetMapping、@PostMapping、@PutMapping、@DeleteMapping
    • @ResponseBody:将返回值放在response内,通常返回json数据。
    • @RequestBody:将request的参数放在request体中
    • @PathVariable:用于接收路径参数,比如@RequestMapping(“/hello/{name}”)申明的路径,将注解放在参数中前,即可获取该值,通常作为Restful的接口实现方法。
  • 容器:
    • @Component:将类变为Spring管理的Bean。
    • @Service:组合注解(组合了@Component注解),应用在service层(业务逻辑层)。
    • @Repository:组合注解(组合了@Component注解),应用在dao层(数据访问层)。
    • @Autowired:Spring提供的工具(由Spring的依赖注入工具(BeanPostProcessor、BeanFactoryPostProcessor)自动注入)。
    • @Qualifier:用于区分两个以上相同类型的Bean
    • @Configuration:声明当前类是一个配置类(相当于一个Spring配置的xml文件)
    • @Value:可用在字段,构造器参数跟方法参数指定默认值,支持#{}跟${}方式。一般将SpringbBoot中的application.properties配置的属性值赋值给变量。
    • @Bean:注解在方法上,声明当前方法的返回值为一个Bean。返回的Bean对应的类中可以定义init()方法和destroy()方法,然后在@Bean(initMethod=”init”,destroyMethod=”destroy”)定义,在构造之后执行init,在销毁之前执行destroy。
    • @Scope:定义采用什么模式创建Bean(方法上,得有@Bean)包括:Singleton、Prototype、Request、Session、GlobalSession。
  • AOP:
    • @Aspect:声明一个切面(类上)使用@After、@Before、@Around定义建言(advice),可直接将拦截规则(切点)作为参数。
      • @After:在方法执行之后执行(方法上)。
      • @Before:在方法执行之前执行(方法上)。
      • @Around:在方法执行之前与之后执行(方法上)。
      • @PointCut:声明切点在java配置类中使用@EnableAspectJAutoProxy注解开启Spring对AspectJ代理的支持(类上)。
  • 事务:@Transactional:在要开启事务的方法上使用,即可声明式开启事务。

5. Spring中都用到了哪些设计模式?

  • 工厂模式—使用工厂模式通过BeanFactory、ApplicationContext创建bean对象。
  • 代理模式—SpringAOP功能功能就是通过代理模式来实现的,分为动态代理和静态代理。
  • 单例模式—Spring中定义的Bean默认为单例模式。
  • 模板方法—解决代码重复的问题。比如RestTemplate、JmsTemplate、JdbcTemplate。
  • 观察者模式:Spring事件驱动模型就是观察者模式很经典的一个应用。
  • 适配器模式:SpringAOP的增强或通知(Advice)使用到了适配器模式、SpringMVC中也是用到了适配器模式适配Controller。
  • 策略模式:Spring中有一个Resource接口,它的不同实现类,会根据不同的策略去访问资源。
  • 前端控制器—Spring提供了DispatcherServlet来对请求进行分发。
  • 视图帮助(ViewHelper)—Spring提供了一系列的JSP标签,高效宏来辅助将分散的代码整合在视图里。
  • 依赖注入—贯穿于BeanFactory/ApplicationContext接口的核心理念。

12. 什么是ioc控制反转?好处?

  • Inverse Of Control反转控制:将对象的生命周期交给spring容器管理
  • 它将最小化应用程序中的代码量
  • 它以最小的影响和最少的侵入机制促进松耦合
  • 支持即时的实例化和延迟加载Bean对象
  • 易于测试,因为不需要单元测试用例中的任何单例或JNDI查找机制。

16. spring的di

  • dependency Injection依赖注入,是ioc的实现方式
    • 注入方式:set/属性方法注入、构造方法注入、字段注入
    • 注入类型:值类型注入(8大基本数据类型)、引用类型注入 将依赖对象注入
set方法注入
<bean  name="user" class="cn.itcast.bean.User" >
	<!--值类型注入: 为User对象中名为name的属性注入tom作为值 -->
	<property name="name" value="tom" ></property>
	<!-- 引用类型注入: 为car属性注入下方配置的car对象 -->
	<property name="car"  ref="car" ></property>
	<!--数组类型注入: 如果数组中只准备类一个值(对象),直接使用value|ref-->
	<property name="arr" value="tom"></property>
	<property name="arr">
		<array>
			<value>tom</value>
			<ref bean="user"/>
		<array>
	</property>
	<!-- List类型注入:如果list中只准备类一个值(对象),直接使用value|ref-->
	<property name="list" value="jack"></property>
	<property name="list">
		<list>
			<value>jack</value>
			<ref bean="user"/>
		<list>
	</property>
	<!-- Properties类型注入 -->
	<property name="prop">
		<props>
			<prop key="driverClass">com.jdbc.mysql.Driver</prop>
		<props>
	</property>
	<!-- Map类型注入 -->
	<property name="map">
		<map>
			<entry key="url" value="jdbc:mysql:///crm"></entry>
		<map>
	</property>
</bean>
<!-- 将car对象配置到容器中 -->
<bean name="car" class="cn.itcast.bean.Car" >
	<property name="name" value="兰博基尼" ></property>
</bean>


构造函数注入
<bean name="user2" class="cn.itcast.bean.User" >
	<!-- name属性: 构造函数的参数名  index属性: 
	构造函数的参数索引 type属性: 构造函数的参数类型-->
	<constructor-arg name="name" index="0" type="java.lang.Integer" value="999"></constructor-arg>
	<constructor-arg name="car" index="1" ref="car"></constructor-arg>
</bean>

14. 简述Spring IoC的实现机制?

  • 原理:工厂模式加反射机制
  • a. 加载配置文件,解析成BeanDefinition放在Map里
  • b. BeanFactory调用getBean的时候,从BeanDefinition所属的Map里,拿出Class对象进行实例化,如果有依赖关系,将递归调用getBean方法 —— 完成依赖注入。

13. 说说applicationContext&BeanFactory

  • BeanFactory接口:创建并管理各种类的对象。每次在获得对象时才会创建对象.最常用的是XmlBeanFactory,根据XML文件中内容创建相应Bean
  • ApplicationContext建立在BeanFactoty基础上。每次容器启动时就会创建容器中配置的所有对象.并提供更多功能
    • 1、ClassPathXmlApplicationContext :从 ClassPath 的 XML 配置文件中读取上下文,并生成上下文定义。应用程序上下文从程序环境变量中取得。
    • 2、FileSystemXmlApplicationContext :由文件系统中的XML配置文件读取上下文
    • 3、XmlWebApplicationContext :由Web应用的XML文件读取上下文。在 Spring MVC 使用
    • 4、Spring Boot 的ConfigServletWebServerApplicationContext

17. Spring容器启动阶段会干什么?

  • IoC容器工作的过程可以划分两个阶段
  • 容器启动阶段:加载配置,分析配置信息,装配到BeanDefinition,其他后处理
  • Bean实例化阶段:实例化对象,装配依赖, 生命周期回调, 对象其他处理, 注册回调接口

18. Spring Bean在容器的生命周期是什么样的?

  • 实例化Bean对象:
    • 根据配置中Bean Definition中实例化Bean对象(通过XML,Java注解或Java Config代码提供)
  • 属性赋值:Aware相关的属性,注入到Bean对象
    • 如果Bean实现BeanNameAware接口,则工厂通过传递Bean的beanName调用setBeanName(String name)方法
    • 如果Bean实现BeanFactoryAware接口,工厂通过传递自身的实例来调用setBeanFactory(BeanFactory beanFactory)方法
  • 初始化
    • @PostConstruct
    • 如果存在与Bean关联的任何BeanPostProcessor,则调用#preProcessBeforeInitialization(Object bean, String beanName) 方法。
    • 如果Bean实现InitializingBean接口,则会调用#afterPropertiesSet() 方法。
    • 如果Bean指定init方法(例如 的 init-method 属性),那么将调用该方法。
    • 如果存在与Bean关联的任何 BeanPostProcessor,则调用#postProcessAfterInitialization(Object bean, String beanName) 方法。
  • 销毁:
    • @PreDestroy
    • 如果Bean实现DisposableBean接口,当 spring 容器关闭时,会调用 #destroy() 方法。
    • 如果bean指定destroy方法(例如 的 destroy-method 属性),那么将调用该方法。
      beanlife.png

15. Spring有哪些自动装配的方式?

  • byName根据名称进行自动匹配
  • byType根据类型进行自动匹配
  • constructor spring根据bean构造函数入参类型自动装配
  • autodetect 如果Bean提供了默认的构造函数,则采用byType,否则采用constructor。

4. spring中的bean作用域scope类型√

  • singleton(默认):被标识为单例的对象,在spring容器中只存在一个实例
  • prototype:被标识为多例的对象,每次获取都会创建新对象
  • request:web环境下.对象与request生命周期一致.
  • session:web环境下,对象与session生命周期一致.
  • Application:对象与Web Application生命周期一致,只能在同一个webapplication中获取

8. spring框架中的单例bean是线程安全的吗?√

  • 如果单例Bean是无状态的,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。
  • 如果bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。解决办法就是将多态bean的作用域由“singleton”变更为“prototype”或者将变量放入ThreadLocal中

6. 如何解决spring bean中的循环依赖?√为何使用三级缓存解决循环依赖而不是二级缓存?

  • 单例模式下Spring可以解决哪些情况的循环依赖
    • 多例模式不支持,无限创建对象
    • AB均采用构造器注入,不支持。直接抛出BeanCurrentlylnCreationException异常。
    • AB均采用setter注入,支持
    • AB均采用属性自动注入,支持
    • A中注入的B为setter注入,B中注入的A为构造器注入,支持
    • B中注入的A为setter注入,A中注入的B为构造器注入,不支持
    • 第四种可以,第五种不可以的原因是Spring在创建Bean时默认会根据自然排序进行创建,所以A会先于B进行创建。
  • spring通过三级缓存解决循环依赖,
    • singletonObjects 一级缓存。保存实例化、属性赋值、初始化完成的bean实例
    • earlySingletonObjects 二级缓存 。保存实例化完成的bean实例
    • singletonFactories 三级缓存,用于保存bean创建工厂,以便后面有机会创建代理对象
  • 实例化过程
    • A实例化并把A的ObjectFactory加入第三级缓存
      • A填充属性需要注入B -> B实例化并把B的ObjectFactory加入第三级缓存
      • B填充属性需要注入A -> 从第三级缓存移除A对象,A代理对象加入第二级缓存(此时A还是半成品,B注入的是A代理对象)
      • B属性注入完成,创建B代理对象(此时B是完成品) -> 从第三级缓存移除B对象,B代理对象加入第一级缓存
      • A填充属性注入B代理对象,从第二级缓存移除A代理对象,A代理对象加入第一级缓存
  • 如果没有AOP的话确实可以两级缓存就可以解决循环依赖的问题,如果加上AOP,两级缓存是无法解决的,不可能每次执行singleFactory.getObject()方法都给我产生一个新的代理对象,所以还要借助另外一个缓存来保存产生的代理对象

7. @Autowired 的实现原理?

  • 在Bean的初始化阶段,会通过Bean后置处理器来进行前置和后置的处理。@Autowired功能是通过后置处理器
    AutowiredAnnotationBeanPostProcessor来完成的
  • Spring在创建bean的过程中,最终会调用到doCreateBean()方法,在doCreateBean()方法中会调用populateBean()方法,来为bean进行属性填充,完成自动装配等工作。
  • 在populateBean()方法中一共调用了两次后置处理器,第一次是为了判断是否需要属性填充,如果不需要进行属性填充,那么就会直接进行return,如果需要进行属性填充,那么方法就会继续向下执行,后面会进行第二次后置处理器的调用,这个时候,就会调用到AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues()方法,在该方法中就会进行@Autowired注解的解析,然后实现自动装配
//属性赋值
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
          //…………
          if (hasInstAwareBpps) {
              if (pvs == null) {
                  pvs = mbd.getPropertyValues();
              }

              PropertyValues pvsToUse;
              for(Iterator var9 = this.getBeanPostProcessorCache().instantiationAware.iterator(); var9.hasNext(); pvs = pvsToUse) {
                  InstantiationAwareBeanPostProcessor bp = (InstantiationAwareBeanPostProcessor)var9.next();
                  pvsToUse = bp.postProcessProperties((PropertyValues)pvs, bw.getWrappedInstance(), beanName);
                  if (pvsToUse == null) {
                      if (filteredPds == null) {
                          filteredPds = this.filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                      }
                      //执行后处理器,填充属性,完成自动装配
                      //调用InstantiationAwareBeanPostProcessor的postProcessPropertyValues()方法
                      pvsToUse = bp.postProcessPropertyValues((PropertyValues)pvs, filteredPds, bw.getWrappedInstance(), beanName);
                      if (pvsToUse == null) {
                          return;
                      }
                  }
              }
          }
         //…………
  }

//先调用 findAutowiringMetadata()方法解析出 bean 中带有@Autowired 注解、@Inject 和@Value 注解的属性和方法。然后调用 metadata.inject()方法,进行属性填充。
  public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
      //@Autowired注解、@Inject和@Value注解的属性和方法
      InjectionMetadata metadata = this.findAutowiringMetadata(beanName, bean.getClass(), pvs);

      try {
          //属性填充
          metadata.inject(bean, beanName, pvs);
          return pvs;
      } catch (BeanCreationException var6) {
          throw var6;
      } catch (Throwable var7) {
          throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", var7);
      }
  }

19. spring的AOP以及实现方式,通知类型

  • AOP(Aspect-Oriented Programming),面向切面编程:通过动态代理将通知织入目标对象.把一些业务逻辑中的相同代码抽取到一个独立的模块中,提高代码的可重用性。
  • 实现方式
    • 动态代理(优先):基于接口,被代理对象必须要实现接口,才能产生代理对象.
    • cglib代理:基于继承,对目标对象进行继承代理.目标对象不被final修饰。通过ASM读取目标类的字节码,然后修改字节码生成新的类
  • 应用:用于增强方法,权限认证、日志、事务、参数校验
  • 常用术语
    • Joinpoint(连接点):目标对象中,被拦截到的方法
    • Poincut(切入点):目标对象,已经增强的方法。pointcut 的作用就是提供一组规则(使用 AspectJ pointcut expression language 来描述) 来匹配joinpoint, 给满足规则的 joinpoint 添加 Advice
    • Advice(通知/增强):指拦截到连接点之后要执行的增强代码
      • 前置通知(Before advice):在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。ApplicationContext 中在 < aop:aspect > 里面使用 < aop:before > 元素进行声明;
      • 后置通知(After advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。ApplicationContext 中在 < aop:aspect > 里面使用 < aop:after > 元素进行声明。
      • 返回后通知(After return advice :在某连接点正常完成后执行的通知,不包括抛出异常的情况。ApplicationContext 中在 < aop:aspect > 里面使用 << after-returning >> 元素进行声明。
      • 环绕通知(Around advice):在 join point 前和 joint point 退出后都执行的 advice。ApplicationContext 中在 < aop:aspect > 里面使用 < aop:around > 元素进行声明。
      • 抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。ApplicationContext 中在 < aop:aspect > 里面使用 < aop:after-throwing > 元素进行声明。
    • Target(目标对象):被代理的对象
    • Weaving(织入):将 aspect 和其他对象连接起来, 并创建 adviced object 的过程.
    • Proxy(代理):将通知织入到目标对象之后,形成代理对象 Advice + Target Object = Advised Object = Proxy 。
    • aspect(切面):切入点+通知 可以简单地认为, 使用 @Aspect 注解的类就是切面。

22. spring事务配置,处理方式?

  • 声明式事务:基于AOP,通过使用注解@Transactional或基于XML的配置事务,从而事务管理与业务代码分离。但无法用到代码块级别
  • 编程式事务:通过TransactionTemplate和PlatformTransactionManager编码的方式实现事务管理,需要在代码中显式的调用事务的获得、提交、回滚。灵活性高,但维护困难
public class AccountService {
    private TransactionTemplate transactionTemplate;

    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }

    public void transfer(final String out, final String in, final Double money) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                // 转出
                accountDao.outMoney(out, money);
                // 转入
                accountDao.inMoney(in, money);
            }
        });
    }
}

24. Spring 的事务隔离级别?

  • Spring的接口TransactionDefinition中定义了表示隔离级别的常量,当然其实主要还是对应数据库的事务隔离级别:
  • ISOLATION_DEFAULT:使用后端数据库默认的隔离界别,MySQL 默认可重复读,Oracle 默认读已提交。
  • ISOLATION_READ_UNCOMMITTED:读未提交
  • ISOLATION_READ_COMMITTED:读已提交
  • ISOLATION_REPEATABLE_READ:可重复读
  • ISOLATION_SERIALIZABLE:串行化

27. 事务传播行为?有什么用?√

  • 事务的传播行为propagation(service方法调用另外一个service方法的时候,仅限于不同类方法间相互调用)
  • 事务的传播机制是指在一个事务中,对于多个事务性操作之间的关系和协调的处理方式。它决定了在一个事务方法中调用其他事务方法时,事务的范围和属性等。
  • 支持当前事务
    • PROPAGATION_REQUIRED如果当前存在事务,则使用该事务。如果当前没有事务,就新建一个(默认)!!!
    • PROPAGATION_SUPPORTS如果当前存在事务,则使用该事务。如果当前没有事务,就不使用事务
    • PROPAGATION_MANDATORY如果当前存在事务,则使用该事务。如果当前没有事务,抛出异常
  • 不支持当前事务的情况
    • PROPAGATION_REQUIRES_NEW创建一个新的事务,如果有事务存在,挂起当前事务,
    • PROPAGATION_NOT_SUPPORTED以非事务方式运行,如果有事务存在,挂起当前事务
    • PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常
    • PROPAGATION_NESTED如果当前事务存在,则创建一个事务作为当前事务的嵌套事务来运行,如果当前没有事务,则等价PROPAGATION_REQUIRED
    • 以 PROPAGATION_NESTED 启动的事务内嵌于外部事务中(如果存在外部事务的话),此时,内嵌事务并不是一个独立的事务,它依赖于外部事务的存在,只有通过外部的事务提交,才能引起内部事务的提交,嵌套的子事务不能单独提交。其实嵌套的子事务就是保存点的一个应用,一个事务中可以包括多个保存点,每一个嵌套子事务。另外,外部事务的回滚也会导致嵌套子事务的回滚。
  • 事务传播机制是使用 ThreadLocal 实现的,所以,如果调用的方法是在新线程中的,事务传播会失效。
  • 在 Spring 中,只有通过 Spring 容器的 AOP 代理调用的公开方法(public method)上的@Transactional注解才会生效。Spring 默认使用基于 JDK 的动态代理(当接口存在时)或基于 CGLIB 的代理(当只有类时)来实现事务。这两种代理机制都只能代理公开的方法。

28. 声明式事务实现原理了解吗?

  • Spring的声明式事务管理是通过AOP(面向切面编程)和代理机制实现的。
  • 第一步,在Bean初始化阶段创建代理对象:
    • Spring容器在初始化单例Bean的时候,会遍历所有的BeanPostProcessor实现类,并执行其postProcessAfterInitialization方法。
    • 在执行postProcessAfterInitialization方法时会遍历容器中所有的切面,查找与当前Bean匹配的切面,这里会获取事务的属性切面,也就是@Transactional注解及其属性值。
    • 然后根据得到的切面创建一个代理对象,默认使用JDK动态代理创建代理,如果目标类是接口,则使用JDK动态代理,否则使用Cglib。
  • 第二步,在执行目标方法时进行事务增强操作:
    • 当通过代理对象调用Bean方法的时候,会触发对应的AOP增强拦截器,声明式事务是一种环绕增强,对应接口为MethodInterceptor,事务增强对该接口的实现为TransactionInterceptor
    • 事务拦截器TransactionInterceptor在invoke方法中,通过调用父类TransactionAspectSupport的invokeWithinTransaction方法进行事务处理,包括开启事务、事务提交、异常回滚等。

29. 声明式事务在哪些情况下会失效?

  • @Transactional应用在非public修饰的方法上。因为在SpringAOP代理时,TransactionInterceptor(事务拦截器)在目标方法执行前后进行拦截,DynamicAdvisedInterceptor(CglibAopProxy的内部类)的intercept方法或JdkDynamicAopProxy的invoke方法会间接调用AbstractFallbackTransactionAttributeSource的computeTransactionAttribute方法,获取Transactional注解的事务配置信息。
protectedTransactionAttributecomputeTransactionAttribute(Methodmethod,Class<?>targetClass){
  //Don'tallowno-publicmethodsasrequired.
  if(allowPublicMethodsOnly()&&!Modifier.isPublic(method.getModifiers())){
    return null;
  }
}
  • @Transactional注解属性propagation设置错误
    • TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行;错误使用场景:在业务逻辑必须运行在事务环境下以确保数据一致性的情况下使用SUPPORTS。
    • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:总是以非事务方式执行,如果当前存在事务,则挂起该事务。错误使用场景:在需要事务支持的操作中使用NOT_SUPPORTED。
    • TransactionDefinition.PROPAGATION_NEVER:总是以非事务方式执行,如果当前存在事务,则抛出异常。错误使用场景:在应该在事务环境下执行的操作中使用NEVER。
  • @Transactional注解属性rollbackFor设置错误
    • rollbackFor用来指定能够触发事务回滚的异常类型。Spring默认抛出未检查unchecked异常(继承自RuntimeException的异常)或者Error才回滚事务,其他异常不会触发回滚事务。
  • 同一个类中方法调用,导致@Transactional失效
    • 由SpringAOP代理造成的,因为只有事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象来管理。

9. spring注册bean的几种方式

  • 直接编码
  • 配置文件 xml的bean标签
  • 注解
    • @Component、@Service、@Controller
    • @Bean
  • java config

10. spring中的@Required、@Autowired、@Qualifier注解的作用?

  • @Required注解,应用于Bean属性setter方法。表示属性必须注入否则抛出 BeanInitializationException 异常。
  • @Autowired用于在setter方法,构造函数,具有任意名称或多个参数的属性或方法上自动装配 Bean
  • @Qualifier指定id自动装配哪个bean

11. 解释什么叫延迟加载?

  • 容器启动之后默认会创建所有作用域为单例的Bean,但是有的业务场景不需要提前创建。此时设置lazy-init="true"。容器启动之后不会默认创建作用域为单例的Bean,而是在获得该Bean时才创建

20. java热部署

  • spring-boot-devtools、Spring Loaded实现原理,nio的WatchService监听文件夹变化,同时实现classLoader的findclass方法重新将class加载进内存

21. Spring容器创建过程

AbstractApplicationContext调用refresh()方法通过调用obtainFreshBeanFactory()方法创建Bean工厂AnnotatedBeanDefinitionReader扫描注解doScan方法和XmlBeanDefinitionReader的doLoadBeanDefinitions方法sax方式解析xml将其封装成document对象,使用BeanDefinitionReaderUtils.registerBeanDefinition并注册到BeanDefinitionRegistry缓存中
然后调用postProcessBeanFactory调用子类的BeanFactory的后置处理器,然后调用invokeBeanFactoryPostProcessors()执行后置处理器
第三注册BeanPostProcessors()到BeanFactory中
第四注册监听器
第五实例化所有的Bean放到singletonObjects单例池里面

23. @Transactional 注解有哪些属性?如何使用?

  • 属性:propagation事务传播行为,isolation事务隔离级别、rollbackFor导致事务回滚的异常类数组、timeout事务超时回滚、readonly读写或只读事务
  • @Transactional 可用在接口、接口方法、类、类方法上。只被应用到 public 方法上,方法级别注解覆盖类级别的注解。

25. Spring 事务如何和不同的数据持久层框架(Spring JDBC、Hibernate、Spring JPA、MyBatis)做集成?

  • Spring通过org.springframework.transaction.PlatformTransactionManager进行事务管理管理
public interface PlatformTransactionManager {
  // 根据事务定义 TransactionDefinition ,获得 TransactionStatus 。 
  //为什么不是创建事务呢?因为如果当前如果已经有事务,则不会进行创建,一般来说会跟当前线程进行绑定。
  //为什么返回TransactionStatus对象?因为TransactionStatus 中包含事务属性和事务的其它信息,例如是否只读、是否为新创建的事务等等
  TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
  //为什么根据 TransactionStatus 情况,进行提交?例如说,带@Transactional注解的A方法,会调用 @Transactional 注解的B方法
  //在B方法结束调用后,会执行PlatformTransactionManager#commit(TransactionStatus status) 方法,此处事务是不能、也不会提交的
  //而是在A方法结束调用后,执行PlatformTransactionManager#commit(TransactionStatus status) 方法,提交事务
  void commit(TransactionStatus status) throws TransactionException;
  // 为什么根据 TransactionStatus 情况,进行回滚?原因同上
  void rollback(TransactionStatus status) throws TransactionException;
}
  • 不同的数据持久层框架,会有其对应的PlatformTransactionManager实现类,都基于AbstractPlatformTransactionManager这个骨架类。
    • HibernateTransactionManager,和Hibernate5事务管理做集成。
    • DataSourceTransactionManager,和JDBC事务管理做集成。也适用于MyBatis、Spring JDBC等等
    • JpaTransactionManager,和JPA事务管理做集成。

26. 为什么在Spring事务中不能切换数据源?

  • 在Spring的事务管理中,数据库连接会和当前线程所绑定,即使设置了另外一个数据源,使用的还是当前的数据源连接。
  • 而且多个数据源且需要事务的场景会带来多事务一致性的问题
  • 推荐除非了读写分离所带来的多数据源,其它情况下,建议只有一个数据源

30. 拦截器与过滤器区别√

  • 拦截器是基于java的反射机制的,而过滤器是基于函数回调。
  • 拦截器不依赖与servlet容器,过滤器依赖servlet容器。
  • 拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
  • 拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
  • 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
  • 拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。

31. spring区分环境

  • spring.profiles.active=dev----application-dev.properties