Java面试——Spring

本文详细介绍了Spring框架的核心概念,包括其模块组成,特别是核心容器(ApplicationContext)的作用。Spring的IoC控制反转通过BeanFactory和ApplicationContext管理对象,而AOP则实现了面向切面编程。此外,文章还讨论了SpringAOP与AspectJ的区别,并解释了各种事务管理类型,特别是@Transactional注解的使用及其可能导致事务失效的情况。最后,概述了Spring事务的传播级别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、spring简介
spring是一款轻量级开源框架,在java应用开发过程提供全面的基础架构支持,让开发者只需要专注于程序开发本身。
核心是Ioc控制反转和AOP面向切面编程。

1.1Spring由哪些模块组成
由20个模块、1300个文件组成,这些模块被整合在六个模块中:核心容器、AOP和设备支持、数据访问与集成、Web、消息、测试。

1.2讲解spring的核心容器(spring context)模块
1)【容器是用来装Bean的,Bean是Spring中的基础组件,Bean是一个非常广义的概念,任何Java对象,Java组件都被当作bean处理】这段本回答不用说,知道就行。
spring框架提供了多个容器的实现,这些实现可分为两套体系:一套是早期的BeanFactory体系,另一套是现在常用的ApplicationContext体系。
BeanFactory是容器最基础的实现类,它定义了容器的基本功能;ApplicationContext可称为应用上下文,它继承了BeanFactory,除了有Beantory的功能外,还提供了其他服务,所有我们现在基本不单独使用BeanFactory而是使用ApplicationContext。
另外,二者还有一个区别:ApplicationContext在容器启动时,一次性创建了所有的bean;而BeanFactory在容器启动时并未创建bean,直到第一次访问某个bean时才创建目标bean。
2)ApplicationContext继承了六个接口来扩展自身功能,同时它又有非常多的实现类,其中比较常用的实现有:WebXmlApplicationContext,ClassPathXmlApplication,FileSystemXmlApplicationContext。

1.3Spring框架中都用到了哪些设计模式?
1)工厂模式:BeanFactory是工厂模式的一个实现,用来创建对象实例;
2)单例模式:Spring配置文件定义的Bean默认为单例模式;
3)代理模式:Spring的AOP功能的实现用到了代理模式;
4)模版方法模式:用来解决代码重复的问题,比如RestTemplate模版类、JmsTemplate模版类、JpaTemplate模版类;
5)观察者模式:定义对象间那种一对一的依赖关系,当一个对象的状态发生改变时,所有依赖对于它的对象都会得到通知并自动更新。

2、Ioc/Ioc容器
Ioc控制反转,所谓“反转”、是指把传统上由程序代码直接操控的对象交给容器管理,即对象控制权的转移——从程序代码转移到了外部容器;Ioc容器负责对象的创建、装配和管理,它控制着对象的整个生命周期。

2.1Ioc实现的机制——>工厂模式 + 反射机制

3、AOP
AOP面向切面编程,它是指将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可复用的模块,这个模块被命名为“切面”。
这样做,可以减少系统中重复的代码,同时提高系统的可维护性,可用于权限管理、日志、事务处理等方面。

4、SpringAOP和AspectJ AOP有什么区别?
它们的代理模式不同:AspectJ采用静态代理(也叫“编译时增强”),静代是AOP框架会在编译阶段将切面织入到Java字节码中,运行时就是增强后的AOP对象。springAOP使用的是动态代理,动代是指AOP框架不会去修改字节码,而是在每次运行时在内存中为目标生成一个AOP对象,这个对象包含了目标对象的全部方法,并且在特定切点做了增强处理。

5、AOP的几个编程术语:
1)切面(Aspect):泛指交叉业务,就是对主业务逻辑的一种增强,比如权限管理、日志、事务等;
2)连接点(JoinPoint):指织入切面的方法;
3)切入点(PointCut):指一个或多个连接点的集合,即通过切入点指定一组方法为连接点;
4)目标对象(Target):指要被增强的对象;
5)通知(Advice):用来指定切面执行的时间点,比如@Brfare指定在方法执行前执行叫前置通知;@AfterReturning指定在方法执行后执行叫后置通知;@Around指定在方法执行前后各执行一次叫环绕通知;@AfterThrowing指定在方法抛出异常后执行叫异常通知;@After无论方法是否执行成功,也就是无论方法是否在执行过程抛异常都执行叫最终通知。

注:被标记为final的方法不能作为切入点或连接点,因为这种方法不能被修改,也就不能被增强。

6、DI有几种方式?
1)基于xml的di,有设值注入和依赖注入两种
1】设值注入——简单类型

<bean id="j01" class="com.xxx.yyy...">
        <property name="name" value="豪洋学校"/>
        <property name="xuefei"  value="1800"/>
</bean>

2】设值注入——引用类型

<bean id="f01" class="com.xxx.zzz...">
		<property name="name" value="张三"/>
        <property name="school"  ref="j01"/>
</bean>

3】构造注入——简单、引用,和上边类似,写一个例子

<bean id="config01" class="com.xxx.ccc...">
        <constructor-arg name="name" value="李四"/>
        <constructor-arg name="school"  ref="j01"/>
</bean>

注:使用构造注入,要保证顺序与构造器中参数顺序一致

4】引用类型自动注入---->可以通过标签的autowire属性开启引用类型自动注入,自动注入可以省去上面例子中的

或者

a>自动注入,如果是通过byName方式,要求调用类中属性名、要与被调用类的id值相同,例如:

<bean id="zuto01" class="com.xxx.aaa..." autowire="byName">
        <property name="name" value="张三"/>
</bean>

这个例子中,学生对象虽然没有用设值注入的方式注入学校,但是开启了引用类型自动注入,系统会根据学校bean的id自动匹配、自动注入。

b>自动注入,如果通过byType方式,要求调用类中的属性,与被调用类class名同源(同源指被调用类与调用类属性相同,或是属性类的子类、实现类),而且若被调用类是属性类的子类、实现类,则要求唯一(即该属性类没有其他子类、实现类),否则容器会分不清该注入哪个而出错。

2)基于注解的di
1】通过以下几个注解,将类放入容器
@Component(id=“xxx”)——通用
@Controller——springMVC的注解,专用于控制器
@Service——业务逻辑层
@Repository——持久层

2】通过以下几个注解,将bean注入对象

@value——注入简单类型

@Autowired——注入引用类型;单独使用是按照byType的方式自动注入

@Autowired
@Qualifier(id=“id值”)——两注解联合使用可按byName方式自动注入

@Resource——JDK的注解,默认是按照byType自动注入引用类型;
@Resource(name=“id值”),按照byName方式自动注入引用类型

3】@Autowired注解有一个required的属性,默认值为true,此时表示当注入失败、即没有找到与之匹配的类时,程序会终止运行(报错);
若将required值设为false,则匹配失败也正常运行,此时未匹配的属性值为null。

7、Spring支持的事务管理类型
编程式事务管理类型:通过编程管理事务,灵活、但难以维护(指的是那种通过if(a账户扣款失败),则(b账户加款也要失败),这种形式保证事务原子性的方法);
声明式事务管理:将业务代码和事务管理分离,通过xml配置和注解来管理事务。

7.1 @Transactional注解
使用@Transactional注解,就是使用了Spring最爽的功能之一:声明式事务管理。
这个注解有几个关键属性要搞懂:
transactionManager:指定事务管理器,主要用于多事务管理器情况下指定,要用那个事务管理器、值就写它的bean名称;
isolation:指定事务的隔离级别;
propagation:指定事务的传播行为;
timeout:指定事务的超时时间;
rollbackFor :指定能够触发事务回滚的异常类型,可以指定多个,默认是在RuntimeException和Error上回滚;
noRollbackFor:指定不触发回滚的异常类型,不回滚事务、而是抛出异常,也是可以指定多个;
timeout:指定事务的超时时间,单位为秒。

7.1使用@Transactional注解,那些情况下事务会失效?
1)底层数据库不支持事务;
2)在非public修饰的方法使用:此注解如果不是标注在public修饰的方法上并不会抛出异常,但是会导致事务失效。
@Transactional注解使用的是AOP,在使用动态代理的时候只能针对public方法进行代理,源码依据在AbstractFallbackTransactionAttributeSource类中的computeTransactionAttribute方法中,如下:

protected TransactionAttribute computeTransactionAttribute(Method method,
    Class<?> targetClass) {
        // Don't allow no-public methods as required.
        if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
        return null;
}

3)异常被 " 踹死了 ":这种情况小白是最容易犯错的,在整个事务的方法中使用try-catch,导致异常无法抛出,自然会导致事务失效。伪代码如下:

@Transactional
public void method(){
  try{
    //插入一条数据
    //更改一条数据
  }catch(Exception ex){
    return;
  }
}

4)方法中调用同类的方法:简单的说就是一个类中的A方法(未标注声明式事务),在内部调用了B方法(标注了声明式事务),这样会导致B方法中的事务失效,代码如下:

public class Test{
  public void A(){
    //插入一条数据
    //调用B方法
    B();
  }
  
  @Transactional
  public void B(){
    //插入数据
  }
}

错误原因是,Spring在扫描Bean的时候会自动为标注了@Transactional注解的类生成一个代理类(proxy),当有注解的方法被调用的时候,实际上是代理类调用的,代理类在调用之前会开启事务,执行事务的操作(SpringAOP的动态代理);但是同类中的方法互相调用,相当于this.B(),此时的B方法并非是代理类调用,而是直接通过目标类对象直接调用,所以注解会失效。
5)rollbackFor属性设置错误;
6)noRollbackFor属性设置错误;
7)propagation属性设置错误, 默认的事务传播属性是Propagation.REQUIRED,但是一旦配置了错误的传播属性,也是会导致事务失效,如下三种配置将会导致事务失效:
Propagation.SUPPORTS
Propagation.NOT_SUPPORTED
Propagation.NEVER

8、spring事务的实现方式和原理
本质上就是数据库对事务的支持;数据库事务的提交和回滚是通过bin log或者redo log实现的。

9、Spring事务的几种传播级别
1)propagation_required:默认传播级别,若已存在事务则支持当前事务;若不存在,则开启一个新的事务;
2)propagetion_supports:若已存在事务则支持当前事务;若不存在,则使用非事务的方式执行;
3)propagation_mandatory:若已存在事务则支持当前事务;若不存在,则抛出异常;
4)propagation_not_supported:总是使用非事务方式执行,并挂起任何存在的事务;
5)propagation_requires_new:总是开启一个新事务;如果一个事务已经存在,则将这个存在的事务挂起;
6)propagation_never:使用非事务方式执行;如果当前存在事务,则抛出异常;
7)propagation_nested:如果当前存在事务,则嵌套在事务内执行;如果当前不存在事务,则按propagation_required属性执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值