一、谈谈你对spring IOC和DI的理解,它们有什么区别?
IoC:Inverse of Control 反转控制的概念,就是将原本在程序中手动创建UserService对象的控制权,交由Spring框架管理,
简单说,就是创建UserService对象控制权被反转到了Spring框架
DI:Dependency Injection 依赖注入,在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件
IoC 和 DI的区别?
IoC 控制反转,指将对象的创建权,反转到Spring容器 , DI 依赖注入,指Spring创建对象的过程中,将对象依赖属性通过配置进行注入。
二、spring配置bean实例化有哪些方式?
(1)使用类构造器实例化
<bean id="bean1" class="cn.itcast.spring.b_instance.Bean1"></bean>
(2)使用静态工厂方法实例化(简单工厂模式)
<bean id="bean2" class="cn.itcast.spring.b_instance.Bean2Factory" factory-method="getBean2"></bean>
(3)使用实例工厂方法实例化(工厂方法模式)
<bean id="bean3Factory" class="cn.itcast.spring.b_instance.Bean3Factory"></bean>
<bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3"></bean>
三、BeanFactory 接口和 ApplicationContext 接口有什么区别 ?
①ApplicationContext 接口继承BeanFactory接口,Spring核心工厂是BeanFactory ,BeanFactory采取延迟加载,第一次getBean时才会初始化Bean, ApplicationContext是会在加载配置文件时初始化Bean。
②ApplicationContext是对BeanFactory扩展;
(1)底层资源的访问:ApplicationContext扩展了ResourceLoader(资源加载器)接口,从而可以用来加载多
个Resource,而BeanFactory是没有扩展ResourceLoader;
(2)国际化处理:BeanFactory是不支持国际化功能的;
(3)BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才
对该Bean进行加载实例化;而ApplicationContext则相反,它是在容器启动时,一次性创建了所有的Bean。
(4)对Web应用的支持:与BeanFactory通常以编程的方式被创建不同的是,ApplicationContext能以声明的
方式创建,如使用ContextLoader。
ContextLoader有两个实现:ContextLoaderListener(需要检查contextConfigLocation参数。如果不存在的
话,它将默认使用/WEB-INF/applicationContext.xml)和ContextLoaderServlet。
四、简单的说一下spring的生命周期?
①容器寻找Bean的定义信息并且将其实例化。
②受用依赖注入,Spring按照Bean定义信息配置Bean的所有属性。
③如果Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。
④如果Bean实现BeanFactoryAware 或者 ApplicationContextAware ,设置工厂setBeanFactory 或者上下文对象setApplicationContext;
⑤如果存在类实现BeanPostProcessor ,执行postProcessBeforeInitialization;
⑥如果Bean实现InitializingBean 执行 afterPropertiesSet;
⑦调用<bean init-method="init"> 指定的初始化方法 init;
⑧如果存在类实现 BeanPostProcessor,执行postProcessAfterInitialization;
⑨执行业务处理;
⑩如果Bean实现 DisposableBean 执行 destroy();
⑪调用<bean destroy-method="customerDestroy"> 指定销毁方法 customerDestroy。
五、简单的说一下Spring框架中Bean的生命周期?
Bean的生命周期:
(1)bean定义
在配置文件里面用<bean></bean>来进行定义。
(2)bean初始化,有两种方式初始化:
A.在配置文件中通过指定init-method属性来完成
B.实现org.springframwork.beans.factory.InitializingBean接口
(3)bean调用
有三种方式可以得到bean实例(构造方法、简单工厂方法、实例工厂方法),并进行调用
(4)bean销毁(与初始化类似)
销毁有两种方式
A.使用配置文件指定的destroy-method属性
B.实现org.springframwork.bean.factory.DisposeableBean接口
五、简单的说一下Spring框架中Bean的作用域?
Bean的作用域:
(1)singleton(单例)
当一个bean的作用域为singleton, 那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。
(2)prototype
Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean() 方法)时都会创建一个新的bean实例。根据经验,对所有有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用 (1)singleton作用域。
(3)request
在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例, 它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。
(4)session
在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
(5)global session
在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于 web的Spring ApplicationContext情形下有效。
六、Bean注入属性有哪几种方式?
(1)构造器注入,通过 <constructor-arg> 元素完成注入
(2)setter方法注入, 通过<property> 元素完成注入【开发中常用方式】
七、Spring如何处理线程并发问题?
Spring使用ThreadLocal解决线程安全问题。
ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。
在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使
用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象
锁等繁杂的问题,程序设计和编写难度相对较大。
而ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量
副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要
对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量
封装进ThreadLocal。
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
八、什么是AOP,AOP的作用是什么?
面向切面编程(拦截器框架),能够让我们在不影响原有功能的前提下,为软件横向扩展功能 。
image.png
九、spring的AOP通知有哪些类型?
(1)前置通知(Before advice):在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。
(2)返回后通知(After returning advice):在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
(3)抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。
(4)后通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
(5)环绕通知(Around Advice):包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。
十、介绍一下Spring的事物管理
事务就是对一系列的数据库操作(比如插入多条数据)进行统一的提交或回滚操作,如果插入成功,那么一起成功,如果中间有一条出现异常,那么回滚之前的所有操作。这样可以防止出现脏数据,防止数据库数据出现问题。
Spring中也有自己的事务管理机制,一般是使用TransactionMananger进行管理,可以通过Spring的注入来完成此功能。
spring提供的事务管理可以分为两类:编程式的和声明式的。编程式(主要使用transactionTemplate)的,比较灵活,但是代码量大,存在重复的代码比较多;声明式(使用TransactionProxyFactoryBean)的比编程式的更灵活。
十一、 spring注入的几种方式(循环注入)?
Spring容器中为一个bean配置依赖注入有三种方式:
1、使用属性的setter方法注入 这是最常用的方式;
<!-- 注册userService -->
<bean id="userService" class="com.lyu.spring.service.impl.UserService">
<!-- name对应userService 类中的setUserDao方法:默认拼接set -->
<property name="userDao" ref="userDaoMyBatis"></property>
</bean>
<!-- 注册mybatis实现的dao -->
<bean id="userDaoMyBatis" class="com.lyu.spring.dao.impl.UserDaoMyBatis"></bean>
2、使用构造器注入;
<!-- 注册userService -->
<bean id="userService" class="com.lyu.spring.service.impl.UserService">
//构造器注入
<constructor-arg ref="userDaoJdbc"></constructor-arg>
</bean>
<!-- 注册jdbc实现的dao -->
<bean id="userDaoJdbc" class="com.lyu.spring.dao.impl.UserDaoJdbc"></bean>
3、使用Filed注入(用于注解方式):
@Resource(配合注解@Qualifier(以byType方式查找到多个Bean时指定某个具体名称的Bean)使用);
@Autowired(注入自己编写的类用它即可,实际开发常用)
十二、spring如何实现事物管理的?
1、编程式事务管理(对基于 POJO 的应用来说是唯一选择)。
我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。
2、基于 TransactionProxyFactoryBean的声明式事务管理
3、基于 @Transactional 的声明式事务管理
4、基于Aspectj AOP配置事务
基于 TransactionProxyFactoryBean(事务代理对象)的声明式事务管理(每个管理的bean都必须被指定):
TransactionProxyFactoryBean的声明式事务管理
基于 @Transactional(事务注解驱动) 的声明式事务管理(会把所有的连接点都作为切点将事务织入进去):
基于 @Transactional 的声明式事务管理
基于Aspectj AOP配置事务(为连接点指定事务属性):
基于Aspectj AOP配置事务
十三、spring AOP的原理?
什么是AOP?
(Aspect Orient Programming)面向切面编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等。
AOP原理:
AOP实现的关键在于AOP框架自动创建的AOP代理,AOP代理主要分为静态代理和动态代理,
静态代理(编译阶段生成AOP代理类)的代表为AspectJ;而动态代理则以Spring AOP为代表。
静态代理:在编译阶段将Aspect织入Java字节码中, 运行的时候就是经过增强之后的AOP对象。
Spring AOP:AOP框架不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理(切点动态织入增强),并回调原对象的方法。
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。
JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。
JDK动态代理的核心是InvocationHandler接口和Proxy类。
CGLIB来动态代理:目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类;CGLIB(类库)是通过继承的方式做的动态代理;
因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
总结:
AspectJ在编译时就增强了目标对象,Spring AOP的动态代理则是在每次运行时动态的增强,生成AOP代理对象,区别在于生成AOP代理对象的时机不同;相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。
十四、springIOC?
IOC(控制反转):是一种设计思想,是spring的核心;对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系;
所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,
然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。
所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。
对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。
或者:控制反转IoC(Inversion of Control)是说创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方,比如转移交给了IoC容器。
DI(依赖注入):提升组件重用的频率;
IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;
即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。
十五、springMVC注解的意思?
1、@RequestMapping
处理请求地址映射的注解(将请求映射到对应的控制器方法中);可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
2、@RequestParam:绑定单个请求参数值
例如:public String requestparam4(@RequestParam(value="username",required=false) String username)
3、@PathVariable:绑定URI模板变量值
@PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上。
@RequestMapping(value="/users/{userId}/topics/{topicId}")
public String test(
@PathVariable(value="userId") int userId,
@PathVariable(value="topicId") int topicId)
}
4、@ModelAttribute
作用主要是当注解在方法参数上时会将注解的参数对象添加到Model中;
控制器中的@ModelAttribute方法是在同一控制器中的@RequestMapping方法被调用之前调用的。可以看做控制器的初始化。
5、SessionAttributes
默认情况下,ModelMap中的属性作用域是request级别,也就是说,当本次请求结束后,ModelMap 中的属性将销毁。
希望在多个请求中共享ModelMap中的属性,必须将其属性转存到session 中,这样 ModelMap 的属性才可以被跨请求访问。
//(1)将ModelMap中属性名为currUser的属性放到Session属性列表中,以便这个属性可以跨请求访问
@SessionAttributes("currUser")
public class Demo1Controller {
@RequestMapping(value="/getUser")
public String getUser(ModelMap model){
User user=new User();
user.setUser_name("zhangsan");
user.setUser_age(25);
user.setUser_email("zhangsan@sina.com");
//(2)向ModelMap中添加一个属性
model.addAttribute("currUser",user);
return "/demo/user";
}
//此处能使用(1)处放入model中的currUser属性,实现跨请求访问
@RequestMapping(value="/getUser1")
public String getUser1(ModelMap model){
User user=(User)model.get("currUser");
System.out.println(user.getUser_name());
System.out.println(user.getUser_age());
System.out.println(user.getUser_email());
return "demo/user1";
}
}
6、@Responsebody与@RequestBody
@Responsebody:将Java对象转成json对象;
@RequestBody:将json对象转成Java对象;
7、@Component
相当于通用的注解,当不知道一些类归到哪个层时使用,但是不建议。(可以替代Controller)
十六、可以注册bean的注解有哪些?
四种注解可以注册bean,每种注解可以任意使用,只是语义上有所差异:
@Component:可以用于注册所有bean
@Repository:主要用于注册dao层的bean
@Controller:主要用于注册控制层的bean
@Service:主要用于注册服务层的bean
描述依赖关系注解主要有两种
1、@Resource:
java的注解,默认以byName的方式去匹配与属性名相同的bean的id,
如果没有找到就会以byType的方式查找,如果byType查找到多个的话,
使用@Qualifier注解(spring注解)指定某个具体名称的bean。
@Resource
@Qualifier("userDaoMyBatis")
private IUserDao userDao;
public UserService(){
}
2、@Autowired:
spring注解,默认是以byType的方式去匹配类型相同的bean,
如果只匹配到一个,那么就直接注入该bean;
十七、服务失效踢出基于zookeeper的临时节点原理。
1、FileSystemXmlApplicationContext :此容器从一个XML文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。
2、ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。
3、WebXmlApplicationContext:此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean。
十八、哪种依赖注入方式你建议使用,构造器注入,还是 Setter方法注入?
你两种依赖方式都可以使用,构造器注入和Setter方法注入。
最好的解决方案是用构造器参数实现强制依赖,setter方法实现可选依赖。
十九、一个 Spring Bean 定义 包含什么?
一个Spring Bean 的定义包含容器必知的所有配置元数据,包括如何创建一个bean,它的生命周期详情及它
的依赖。
二十、 哪些是重要的bean生命周期方法? 你能重载它们吗?
有两个重要的bean 生命周期方法,第一个是setup , 它是在容器加载bean的时候被调用。
第二个方法是 teardown 它是在容器卸载类的时候被调用。
The bean 标签有两个重要的属性(init-method和destroy-method)。
用它们你可以自己定制初始化和注销方法。
它们也有相应的注解(@PostConstruct和@PreDestroy)。
二十一、什么是Spring的内部bean?
当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean,
为了定义inner bean,在Spring 的 基于XML的 配置元数据中,
可以在 <property/>或 <constructor-arg/> 元素内使用<bean/> 元素,
内部bean通常是匿名的,它们的Scope一般是prototype。
二十二、在 Spring中如何注入一个java集合?
Spring提供以下几种集合的配置元素:
1、<list>类型用于注入一列值,允许有相同的值。
2、<set> 类型用于注入一组值,不允许有相同的值。
3、<map> 类型用于注入一组键值对,键和值都可以为任意类型。
4、<props>类型用于注入一组键值对,键和值都只能为String类型。
二十三、什么是bean的自动装配?
装配,或bean 装配是指在Spring 容器中把bean组装到一起,前提是容器需要知道bean的依赖关系,如何通
过依赖注入来把它们装配到一起。
Spring 容器能够自动装配相互合作的bean,这意味着容器不需要<constructor-arg>和<property>配置,能通
过Bean工厂自动处理bean之间的协作。
有五种自动装配的方式,可以用来指导Spring容器用自动装配方式来进行依赖注入。
1、no:默认的方式是不进行自动装配,通过显式设置ref 属性来进行装配。
2、byName:通过参数名 自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byname,
之后容器试图匹配、装配和该bean的属性具有相同名字的bean。
3、byType::通过参数类型自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byType,
之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件(通过@qualifiler指定具体的bean),则抛出错误。
4、constructor:这个方式类似于byType, 但是要提供给构造器参数,如果没有确定的带参数的构造器参数
类型,将会抛出异常。
5、autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。
自动装配的局限性是:
1、基本数据类型:你不能自动装配简单的属性,如基本数据类型,String字符串,和类。
2、模糊特性:自动装配不如显式装配精确,如果有可能,建议使用显式装配。
二十四、AOP
面向切面的编程,或AOP, 是一种编程技术,
允许程序模块化横向切割关注点,或横切典型的责任划分,如日志和事务管理。
关注点(功能):是应用中一个模块的行为,一个关注点可能会被定义成一个我们想实现的一个功能。
横切关注点(系统功能):是一个关注点,此关注点是整个应用都会使用的功能,并影响整个应用,
比如日志,安全和数据传输,几乎应用的每个模块都需要的功能。因此这些都属于横切关注点。
连接点(方法):代表一个应用程序的某个位置,在这个位置我们可以插入一个AOP切面,它实际上是个应用程序执行Spring AOP的位置。
切入点(功能放置的位置):是一个或一组连接点,通知将在这些位置执行。可以通过表达式或匹配的方式指明切入点。
引入:引入允许我们在已存在的类中增加新的方法和属性
目标对象:被一个或者多个切面所通知的对象。它通常是一个代理对象。也指被通知(advised)对象。
织入(过程):织入是将切面和到其他应用类型或对象连接或创建一个被通知对象的过程。
Spring切面可以应用五种类型的通知:
1、before:前置通知,在一个方法执行前被调用。
2、after: 在方法执行之后调用的通知,无论方法执行是否成功。
3、after-returning: 仅当方法成功完成后执行的通知。
4、after-throwing: 在方法抛出异常退出时执行的通知。
5、around: 在方法执行之前和之后调用的通知。
二十五、BeanFactory和ApplicationContext有什么区别?
applicationcontext扩展了BeanFactory的功能
1、提供了支持国际化的文本消息
2、统一的资源文件读取方式
3、已在监听器中注册的bean的事件
三种较常见的 ApplicationContext 实现方式:
1、ClassPathXmlApplicationContext:从classpath的XML配置文件中读取上下文,并生成上下文定义。应用程序上下文从程序环境变量中取得。
2、FileSystemXmlApplicationContext :由文件系统中的XML配置文件读取上下文。
3、XmlWebApplicationContext:由Web应用的XML文件读取上下文。
二十六、Spring框架中的单例Beans是线程安全的么?
Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。
但实际上,大部分的Spring bean并没有可变的状态(比如Service类和DAO类),所以在某种程度上说Spring的
单例bean是线程安全的
如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。最浅显的解决办法就
是将多态bean的作用域由“singleton”变更为“prototype”。
二十七、spring如何进行回滚?
不回滚的原因:
1、声明式事务配置切入点表达式写错了,没切中Service中的方法;
2、Service方法中,把异常给try catch了,但catch里没有手动抛出RuntimeException异常;
3、Service方法中,抛出的异常不属于运行时异常(如IO异常),因为Spring默认情况下是捕获到运行时异常就回滚;
如何回滚:
1、如果采用编程式事务,一定要确保切入点表达式书写正确;
2、如果Service层会抛出不属于运行时异常也要能回滚,那么可以将Spring默认的回滚时的异常修改为Exception,这样就可以保证碰到什么异常都可以回滚
① 声明式事务,在配置里面添加一个rollback-for,代码如下:rollback-for="java.lang.Exception"
② 注解事务,直接在注解上面指定,代码如下:@Transactional(rollbackFor=Exception.class)
3、如果在Service层用了try catch,在catch里面再抛出一个 RuntimeException异常,这样出了异常才会回滚
4、直接在catch后面写一句回滚代码
二十八、spring的单利模式实现原理
单例注册表+双重检测机制实现的(既不是饿汉式也不是懒汉式)
二十九、
三十、
网友评论