spring面试题目自我解答

本文详细解答了Spring面试中的常见问题,包括AOP、IOC、Bean的作用域、事务管理、设计模式、SpringMVC工作流程等关键知识点。通过深入探讨,揭示了Spring如何提高代码可维护性和灵活性,以及如何处理线程安全问题。
摘要由CSDN通过智能技术生成

文章目录

1. Aop 面向切面

是spring的一种编程思想。目的是把业务逻辑和系统逻辑区分开。我们专注的是业务逻辑,而系统逻辑不是我们关注的点,这就可以借助于Aop帮助我们完成。还是以保存数据库为例:我们关注的是增删改查,以查为例,我们关注的代码是用哪个字段去查,然而,操作数据库我们必须要先开启数据库,加载数据库驱动,完了还要关闭数据库,搞不好还要回滚。很繁琐,一急还容易给忘了,这些就属于系统逻辑。所以Aop就出现了,帮助我们开启关闭。我们关注与业务逻辑"查"就行了。
Aop需要的工具包是aspectj。常见的术语有分两类,一是:切点(apointcut),切面(aspect)。切点是哪个类或哪个方法需要加前后操作;切面是前后操作的内容。二是:前置通知(before),后置通知(after),环绕通知(around),异常通知(after-throwing)。前置通知是在切点执行前自动执行。后置通知就是在切点内容执行自动后执行。环绕通知就厉害了可以控制切点方法的执行。异常通知就是可以获取切点抛出的异常。
最后,对于AOP的使用,目前我见过和使用过得分两类,一个是加在配置文件中,一个通过注解是直接加在切点方法上。前者比较隐秘,但没有动源代码,没看该配置文件的人都不知道用了aop。后者比较明了,看到源码就知道这里加了aop,但动了源码。

2. IOC

就是控制反转,也可以说成依赖注入,两种说法是一个东西。它也是一种编程思想。即有A,B两个类,其中B类是A的一个属性,所以也可以说成A类依赖B类。传统的建类的方式是同时new连个类,然后把B赋值到A中。这种耦合性比较高,如果有类似B的类也要加入到A中,就要修改A类了。而控制反转是借助于接口创建依赖的类,即精简了代码,也提高了扩展性。就像下面的例子。

class A{
	private B b;

	public B getB() {
		return this.b;
	}

	public void setB(B b) {
		this.b = b;
	}
}
interface B{
	
}
class B1 implements B{
	
}
class B2 implements B{
	
}
	@Test
	public void TestDI(){
		A a=new A();
		System.out.println(a.getB());//null
		a.setB(new B1());
		System.out.println(a.getB());//test.B1@5b37e0d2
		a.setB(new B2());
		System.out.println(a.getB());//test.B2@4459eb14
	}

再者,要介绍的是依赖注入的两种方式,上面按个是属于setter方式注入,还有一种是构造器注入,即把依赖的类放入到构造函数参数中,当创建A类时会强制提醒创建依赖的对象。案例如下:

class A1{
	public  B b;

	public A1(B b) {
		this.b = b;
	}
	
}
interface B{
	
}
class B1 implements B{
	
}
class B2 implements B{
	
}
	@Test
	public void TestDI2(){
		A1 a1=new A1(new B1());
		System.out.println(a1.b);//test.B1@5b37e0d2
	}

这里A 就相当于一个容器,把想要的实例放在A中创建即可。
最后,要介绍的就是SpringIOC容器了(就是A的角色)。这是一个负责管理创建,管理,装配,配置对象的容器。创建A类只需要getBean这个类即可,至于A类的依赖类由spring容器负责自动创建,很方便。springIOC的实现常见的也有两种方式,一种是在xml文件中配置。如下:

<beans>
	<bean id ="B1" class ="test.B1">
	</bean>
	<bean id="A" class="test.A">
		<property name="B">
			<ref bean="B1"/>
		</property>
	</bean>
</beans>

这类方式的源码很复杂,主要是解析上面的xml文件和通过反射的方式递归创建依赖类。
另外一种是通过注解方式,形如:

@Service("A")
class A{
	@Autowired
	public B1 b1;
}
@Service("B1")
class B1{
}

两种方式使用的时候都是通过ApplicationContext.getBean(“A”)的方式创建A类的。

总结:IOC是一种让依赖的类自动注入创建的编程思想,对象给出他们的依赖,而不是自己创建和查找。它降低了代码耦合,增强了扩展性。可以通过构造器注入和setter注入。在springIoc容器中,让spring容器负责创建管理对象,可以通过在xml文件配置依赖类或者通过注解注入依赖类。最后通过getBean的方式加载类。

3. 什么是springBeans?

Beans就是通常配置在applicationContext.xml文件中的Beans节点了。他们构成了spring应用的主干类。这些bean被springIOC容器加载,这些bean默认都是单利的,可以通过设置prototypebean="false"做修改。

4. spring bean的几种作用域

singleton:即单利,一个springIOC只有一个实例
prototype:一个springIOC可以有多个实例
request:每个http请求 都会创建一个bena,该作用域仅在web的springApplicationContext情形下有效。
session:在一个httpSession中,一个bean对应一个实例,该作用域仅在web的springApplicationContext情形下有效。
global-session:在一个全局HTTPsession中,一个bean对应一个实例,该作用域仅在web的springApplicationContext情形下有效。

5. spring框架中的单利不是线程安全的。

6. bean的生命周期

先上个关于spring加载bean的代码

public class Hello Implements BeanNameAware,BeanFactoryAware,BeanPostProcessor,DisposableBean{
	@Override
	public void setBeanName(String arg0){
		System.out.println("haha "+arg0);//注意 这个arg0参数是来自配置文件中bean的id
		}
	public void init(){//这个是配置文件bean要执行的init方法
		System.out.println("laiba");
		}
	@Override
	public void setBeanFactory(BeanFactory arg0)throws BeansException{
		System.out.println("haiyoushui");
		}
	@Override
	public Object postProcessAfterInitialization(Object arg0,String arg1)throws BeansException{
		
		System.out.println("postafter"+arg1);
		return arg0;//这个要返回object,否则不能执行出postProcessBeforeInitialization方法内容。
		}
		@Override
		public Object postProcessBeforeInitialization(Object arg0,String arg1)throws BeansException{
		System.out.println("postbefore");
		}
		@Override
		public void destroy()throws Exception{
			System.out.println("end...");
				
			}
		}
public class SpringTest{
	public static void main(Stringp[] args){
		ApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");
		Hello hello=(Hello)context.getBean("hello");
		}
		}
applicationContext.xml配置文件中的bean配置:
<bean id ="hello" class="test.Hello" init-methond="init" destroy-method="destroy"/>
输出:
haha hello
haiyoushui
laiba
postbefore
postaftercfx

从结果中可以看出,先执行setBeanName()方法,这个方法是来自BeanNameAware接口的实现。然后执行setBeanFactory方法,它是来自BeanFactoryAware接口的实现。然后是init方法,这是配置在bean中的方法。最后分别是:postProcessBeforeInitialization和postProcessAfterInitialization方法,这是来自BeanPostProcessor接口的实现。
所以spring的生命周期总结如下:
1,首先spring容器从xml文件中读取bean的定义,并实例化,
2, spring根据bean的定义填充实例的所有属性。
3,如果bean实现了BeanNameAware接口,spring会传递bean的id给setBeanName.
4,如果bean实现了BeanFactoryAware接口,spring传递beanFactory给setBeanFactory方法
5,执行bean的init-method方法
6,接着是实现与bean相关联的前后置通知BeanPostProcessor,调用相应的before和after方法
7,正式使用该实例
8,如果bean实现了DisposableBean,它将调用destory方法。
总结上面的过程跟网上流行的稍微不同,一是,init-method是在前后置通知间进行的,但我测试的结果是在其前就已经执行了。二是,实例在正式使用前会检测一列的接口实现,上面并不完整。最后是我这里测试的destroy方法没用执行,不知道原因。姑且与网上的流行说法为准吧。

最后,面试的简而言之:创建bean实例,加载bean的属性和依赖,将bean实例传给后置处理器,调用init方法,使用bean,容器关闭时,调用bean的destroy方法销毁实例。

7. 什么是spring的内部bean?

就是一个bean仅被用作另一个bean的属性使用时,就是一个内部bean,即innerBean。这种bean通常匿名使用,并且其作用域是多例的。

8. spring如何注入一个集合?

spring提供了list(允许相同的值),set(不允许相同的值),hash(键值对),props(也是键值对,但键值都只能是string)这四种集合。

9. 什么是bean装配?

把spring容器中的bean组装到一起,并装载其依赖的bean

10. 什么是bean自动装配?

spring容器能够自动装配相互合作的bean。这个比较便利,不用再xml文件一个个配置各个bean的依赖,很简洁,是大部分项目的使用方式。配置形式如下:

<bean id="customer" class="test.Hello" autowire="byName"/>

10. spring可以注入null和空字符串

11. spring的注解装配方式默认是不开启的。需要在spring配置文件中配置<context:annotation-config />元素

12. spring支持的ORM:

hibernate iBatis JPA TopLink JDO ojb

13. spring支持的事务管理:

1,编程式事务管理 ;2,声明式事务管理。前者灵活,程序员自己写每个增删改查。后者通过注解或xml配置替程序员写事务管理部分,使之更关注与业务逻辑,也就是使用了aop。如使用mybatis,就是只用在xml中写好sql,并在xml声明。
举例:

在web-inf目录下创建个管理spring ORM的xml,加入以下:
<!--spring声明式事务的配置-->
<tx:advice id="txAdvice" transcation-manager="transcationManager">
	<tx:attributes>
		<!--给每种事务方式设置spring事务传播机制-->
		<tx:method name="save*" propagation="REQUIRED"/>
		<tx:method name="update*" propagation="REQUIRED"/>
		<tx:method name="delete*" propagation="REQUIRED"/>
		<tx:method name="find*" propagation="SUPPORTS"/>
		<tx:method name="select*" propagation="SUPPORTS"/>
	</tx:attributes>
</tx:advice>

<!-- 对于上面声明的事务所在的方法使用aop进行管理,也就是满足上以上面哪些save,update等开头的方法才会使用事务-->
<aop:config expose-proxy="true">
	<aop:pointcut expression="execution(* com.mybatis.service.impl.*.*(..))" id="txPointcut"/>
	<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>

如果在com.mybatis.service.impl包下有个类是:

public Student findone(String name){
...
}

那这个查询方法就会使用事务管理。而不用像编程式事务要把rollback写在代码中。

14. spring框架的有点有哪些?

轻量,spring基本版本大约2M;
控制反转,spring通过控制反转实现了解耦合;
面向切面编程
容器,springIOC容器可用来配置和管理对象实例;
MVC框架,是spring精心设计的框架,可很好的替代传统web框架;

15. spring模块有哪些?

coremodule,beanmodule,contextmodule,ormmodule,jdbcmodule,webmodule.

16. 关于spring的事务,即操作数据库的事务。

17. BeanFactory 和ApplicationContext的区别。

首先BeanFactory是bean集合的工厂,可用来创建bean实例,并管理bean的生命周期,调用初始化方法,根据请求分发bean功能。当然ApplicationContext也可以做到这些,可以说后者比前者的作用范围更广些。在次基础上ApplicationContext提供了统一的资源文件读取方式,支持国际化的文本消息。

18. ApplicationContext的实现方式有几种?

1,从classpath的xml配置中读取上下文配置。
ApplicationContext context=new ClassPathXmlApplication(“bean.xml”);
2,从本地文件系统中读取xml上下文配置。
Application context=new FileSystemXmlApplication(“bean.xml”);
3,由web应用的xml文件读取上下文,即在web.xml中配置上下文配置文件地址,有web容器读取。
4,AnnotationConfigApplicationContext(基于java配置启动容器)

19. spring配置应用到开发者的3中方式?

1,基于xml配置
就是常见的web.xml,applicationContext.xml的配置方式。可以配置spring支持的一系列如context,orm,beans,jdbc,app,mvc,aso等的标签
2,注解配置
注解装配在spring默认是关闭的。
在配置中加如下配置就可以使用注解装配模式了。然后使用@Required @Autowire等注解在实例中装配相应的属性,构造方法,变量等。

<beans>
	<context:annotation-config />
</beans>

3,java配置
是由@Configuration注解和@Bean注解来实现的,最后由AnnotationConfigApplicationContext类进行实例化。
明显这个@Configuration作用类似ApplicationContext.xml配置文件,@Bean就是其中的实体了。
案例如下:

@Configuration
public class AppConfig{
	@Bean 
	public MyService myService(){
		return new MyServiceImpl();
	}
public static void main(String[] args){
	ApplicationContext ctx=new AnnotationConfigApplicationContext(AppConfig.class);
	MyService myService=ctx.getBean(MyService.class);
	myService.doStuff();
	}

20. 对常见的注解@Required @Autowire @Qualifier的解释。

1, @Required
如果实体的一个属性在配置文件中没有配置,但是在实体中给该属性加了@Required注解,这是就会报异常。可见@Reuqired注解的作用是检查该属性是不是被正确设置。
案例如下:

配置文件:
<context:annotation-config />
<bean id="resultMessage" class="test.resultMessage">
	<property name="code" value="001" />
</bean>
public class ResultMessage{
	private String code;
	private String message;
	public String getCode(){
		return code;
	}
	@Required
	public void setCode(String code){
		this.code=code;
	}
	public String getMessage(){
		return message;
	}
	@Required
	public void setMessage(String message){
		this.message=message;
		}
public class SpringTest{
	public static void main(Stringp[] args){
		ApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");
		ResultMessage resultMessage=(ResultMessage)context.getBean("resultMessage");
		}
		}

2, @Autowire
这个没啥讲解的,是用来自动装配bean的关联依赖属性的。相当于配置文件中的property作用。
3,@Qualifier
根据bean的id装配指定的bean配置,比如一个类同时设置了两个属性值,那么取哪个呢?这是就根据@Qualifier(“beanId”),获取指定的配置。案例:

public class Customer{
	@Autowire
	private Person person;
	}
	
配置文件:
<bean id="customer" class="test.customer"/>
<bean id="personA" class="test.Person">
	<property name="name" value="first"/>
</bean>
<bean id="personB" class="test.Person">
	<property name="name" value="second"/>
</bean>

问题:上面配置中有个两个person,如果使用自动装配,那么会装载personA 还是personB呢?
这是就用到了@Qualifier

public calss Customer{
	@Autowired
	@Qualifier("personA")
	private Person person;
	}

21. spring中用到了哪些设计模式?

单例,代理,工厂(beanFactory),模板.

22. springMVC的优点

1,是spring的一个模块,可以与java的其他模块紧密结合
2,是基于组件的,无论是控制器还是视图都是java组件
3,支持各种是视图技术,不单单是jsp
4,支持各种资源请求的映射策略
5,易于扩展

23. springmvc的工作流程

1,用户发送请求到dispatcherServlet(中央处理器)
2,dispatcherServlet查询handleMapping,经handlerAdapter适配器找到处理请求的controller
3,controller分发到service做逻辑处理,返回modelAndView
4,dispatcherServlet,将modelAndView传给ViewReslover视图解析器,返回具体的view实体
5,dispatcherServlet做相应渲染后,返回给用户。

24. Springmvc的控制器是不是单例模式,如果是怎么解决线程安全问题

是单例,且不是线程安全的,因为如果加锁成同步的,会影响性能。解决方案是不要在controller层做逻辑处理,只把他当做一个分发器,转到service层处理。我觉着这就是为什么都建议不建议在controller做逻辑处理的根本原因吧!
至于controller为什么不是多例,我认为应该是前端用户点击的次数很多,而且很多点击只是做简单的转发,不涉及业务处理,那么没必要每次点击都new个控制器,很浪费堆内存,而且响应慢。再者业务逻辑都放置了service,这是是多利的,线程安全的。

25,springMVC与struct2的区别。

struct2是很遥远的框架了。
1,springMVC的入口时servlet前端控制器,struct2是filter过滤器。
2,springmvc是基于方法开发的,一个url对应一个方法,控制器是单利的,struct2是基于类开发的,参数是类的属性,只能设计成多利。

26,@Controller 是控制器注解

27. @RequestingMapping 是用来处理请求地址的注解,如果是作用在类上是所有方法的父地址

28 如果在拦截请求中,怎么拦截get方式提交的方法?

在@RequestingMapping 注解中加上method=RequestMothod.GET

29 怎么在方法里面得到Request或session?

直接在方法的形参中声明request,Springmvc就自动把request对象传入。同样的获取前台参数也是在方法形参中声明,但参数名要保持一致

30 springmvc的返回值是什么?

有很多种,可以使string,modelAndView
返回string会比较好。

31 怎么设定重定向和转发?

重定向,在返回值前加forward:形如forwar:user.do?name=method1"
转发,在返回值前加redirect 形如 redirect:http://www.baidu.com

32 springmvc 用什么对象从后台向前台传递数据?

通过modelMap对象,可以在这个对象里面用put方法把对象加到里面,然后前台就可通过el表达式拿到。

33 当控制器向AJAX返回特殊对象,如list,需要做什么处理?

加上@ResponseBody注解

34 spring事务传播机制,7种事务传播机制

spring事务也就是数据库的事务。复杂的sql有子查询等,转成spring中就是一个方法(父方法)调用另一个方法(子方法),两个方法中都有对数据库的操作,那么事务在多个方法中是如何传播的。
考虑两个问题:1,子方法的事务是用父方法的事务还是自己重新连接数据。2,如果把两个方法看为一体,父方法回滚字方法会不会也回滚?
传播机制:
1,REQUIRED (也是默认的事务方式)
使用:@Transactional(propagation=Propagaion.REQUIRED),还有一种方式是在xml中配置,在13. spring支持的事务管理中有介绍到。
定义:如果父方法有事务就加入,没有就创建一个。
比如说A(){inert()}方法调B(){delete()}方法,是个先插入后删除的过程。那么执行delete时就不用再去连接数据库了(如jdbc),最后两个一起commit。
2.NOT_SUPPORTED
定义:spring不为当前方法开启事务。
也就是直接插入删除,失败的话也不能回滚。
3,REQUIRES_NEW
不管是否存在事务,都创建一个新的事务。同时父方法中的事务不能提交,要等子方法执行完了再提交。父子方法各自commit提交一次,字事务先提交。
4,MANDATORY
必须在一个已有的事务中执行,否则报错。
也及时B方法执行delete是发现A没有事先开事务就报错。
5,NEVER
必须在一个没有的事务中执行。否则报错
也就是父方法不能开启事务
6,SUPPORTS
如果其他

35 spring容器管理的对象什么时候销毁

1,如果是单利的对象,启动的时候会调用构造方法创建对象,容器关闭的时候调用销毁方法。
2,如果是多利的对象,每次调用的时候用构造方法创建对象,容器不会管理这个bean,也不会销毁,通过垃圾回收机制回收。

36 spring容器用的是单利还是多例?

这种问题不能一概而论,有单利也有多例,默认是单例,对于多例,可以创建多个实例,可以创建中间对象做更多灵活性处理。

37 spring哪些类需要注入,哪些类需要new

这个不太好说,看网上的说的,感觉挺有道理的,说是需要直接new的通常是数据对象。需要注入的通常是跨层调用的类。
再者就是我们在springmvc的controller控制层会使用@Autowire注入service层接口,在service层注入dao层接口。使用的时候我们直接通过注入的变量就可以调用方法了,并没有new实现该接口的实现类。这里的三层就是跨层调用,对应的类也需要我们注入。
还有就是我也会使用spring容器帮我创建大对象,比如对象里面的层级很多,在做单元测试的时候,不得不先new里面的对象,再把对象赋值给外面的大对象。否则直接用new最外层的大对象就会报空指针。这时候可以使用spring容器getbean的方式加载,不过要在创建类的时候给每个类加上@Service注解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老马识途2.0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值