1.如何理解 IOC 和 DI ?
Ioc:inversion of control(控制反转)
它是一种控制思想,将创建对象的控制权转交给Spring容器
- 何为控制:指的是对象创建的权力
- 何为反转:创建对象的权力由开发者手中转交给IOC容器,开发者获取对象由主动转为被动获取
DI: dependency Injection(依赖注入)
DI是IOC的一种实现方式,是指IOC容器在运行期间,动态地将依赖对象注入到需要对象之中。
IoC 和 DI 是从不同的角度的描述的同一件事情,IOC是从开发者的视角,而DI是从IOC容器的视角来说
2.@Bean注解、@Component注解和@Configuration注解的关系?
- @Bean注解是加在方法上的,而@Component注解是加在类上的
通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中,可以在启动类使用@ComponentScan
注解指定类路径 后,会扫描并注册 指定路径下被@Component注解的类 到容器中
- @Configuration注解基于@Componet注解,该注解加在类上,一般作用于配置类,表明在一个类里可以声明一个或多个Bean方法
- @Component注解有多个修饰注解,这些注解都可以将类声明为bean:
@Component
:通用的注解,可标注任意类为 Spring 的组件。如果一个 Bean 不知道属于哪个层,可以使用@Component
注解标注。@Repository
:对应持久层即 Dao 层,主要用于数据库的 Dao 相关操作。@Service
:对应服务层,主要设计一些复杂的逻辑,从中调用 Dao 层。@Controller
:对应 Spring MVC 控制层,主要用来接受用户请求并调用 Service 层返回数据给前端页面。@Configuration
:声明该类为一个配置类,可以在此类中声明一个或多个@Bean
方法。
3.@Autowire注解和@Resource注解的区别?
- @Autowire:默认按数据类型来装配,默认情况下要求被依赖注入的对象必须存在
- @Resource:默认按数据的名称来装配,当找不到与名称相配的bean时会按类型装配
4.Bean有哪些作用域?
- singleton:单例作用域,在IOC容器中仅会存在一个实例,每次从中获取该Bean的话都是拿的同一个实例
- prototype:原型作用域,每次获取实例时,容器都会返回一个新的实例
- request:请求作用域,每次开始一次Http请求会都创建一个新的实例,实例在请求处理完后会及时的销毁
- session:会话作用域,同一个Http Session会话共享一个Bean,不同的Session使用不同的bean,对其他Session不可见
- application:全局作用域,限定Bean是在
ServletContext
的生命周期(级别)
5.如何理解AOP?
AOP:Aspect Orient Progress,面向切面编程。AOP的作用就是将那些与实际业务逻辑无关,但是很多业务模块中要用到的代码(公共行为)封装到一个模块,在需要时切入使用。从而减少大量的重复代码。
连接点 Joinpoint:程序执行过程中的任意位置。方法的执行前后,异常抛出之后等位置。
切点 Pointcut:在程序执行流程中,被织入的方法。(一个切点可以对应多个连接点)。需要在哪个方法执行前后进行织入,哪个方法就是切入点
通知 Advice:通知又叫增强,就是具体你要织入的代码方法。
通知包括:
- 前置通知:@Before ,切点也就是被织入的方法执行完前会执行通知
- 后置通知:@After,切点执行后会执行通知
- 环绕通知:@Round,可以自行决定通知执行的时机
- 异常通知:@AfterThrowing,切点执行抛出异常后才会执行通知
- 返回通知:@AfterReturning,切点执行正常返回后才会执行通知
切面 Aspect: 切点 + 通知就是切面,通常在一个类上加上@Aspect注解表明这是一个切面,在类中进行切点和通知设计
织入 Weaving:把通知应用到目标对象上的过程。
代理对象 Proxy:一个目标对象被织入通知后产生的新对象。
6.对SpringMVC的理解?
MVC是一种三层架构:
- Model:数据层,主要职责就是处理数据,比如Service/DAO层面的东西
- View:视图层,负责将Model层处理好的数据渲染后返回给前端
- Controller:控制层,主要负责处理请求数据的接发和解析,然后将数据交由Model层处理
7.SpringMVC的组件和执行流程?
Spring MVC框架是围绕DispatcherServlet来设计的,这个Servlet会把请求分发给各个处理器
- DispatcherServlet:Servlet调度器,将来自用户的请求进行调度分发给各个处理器
- HandlerMapping:映射处理器,每个进来的请求都需要对应的处理器负责处理,如何找到对应的处理器就是映射处理器的职责
- HandleAdapter:处理适配器,HandlerMapping和Handle之间的桥梁,HandlerMapping找到对应的Handler后,调度器会将参数交由HandleAdapter封装发送给Handler处理
- Handler:处理器,接收并处理来自适配器的封装数据,返回一个ModelAndView对象
- ViewResolver:视图解析器,接收并处理ModelAndView对象,返回一个View对象
执行流程:
- DispatcherServlet拿着接收到的前端请求对应URL,让HandlerMapping找到具体的Handler,返回给DispatcherServlet
- DispatcherServlet调用HandleAdapter进行数据封装,适配器然后去请求Handler处理,处理得到一个ModelAndView对象
- DispatcherServlet拿着这个对象传给ViewResolver进行解析,解析完成得到一个具体的视图View
- 之后DispatcherServlet将这个View进行渲染响应给前端
8.@Controller和@RestController的区别?
@Controller注解的方法下返回的字符串类型的页面路径
@RestController相当于是@Controller和@ResponseBody的结合,因此RestController注解的方法返回的是一个实体对象,前端获得的通常是json对象
9.Spring中有两个id相同的bean对象会报错吗?
在spring同一个配置文件中,不能存在id相同的两个bean,否则会报错。
在spring同一个配置文件中,不能存在id相同的两个bean,否则会报错。因为ioc容器在加载相同id的bean的时候,后加载的会覆盖先加载的bean。
实际上在Spring 3.X版本后,开始使用注解,而注入Bean的注解有@Resource和@Autowire两种。
前者按名字注入,如果找不到则按类型注入;后者按类型注入。
假设现在有两个Bean:
@Configuration
class MyClass{
@Bean(name = "user_service")
public ServiceA bean1(){
//省略
};
@Bean(name = "user_service")
punlic ServiceB bean2(){
//省略
}
}
然后尝试在userService类中注入:
@Resource("user_service")
private ServiceA servicea;
@Resource("user_service")
private ServiceB serviceb;
如果我们在同一个配置类里面声明多个相同名字的bean,在Spring IOC容器中只会注册第一个声明的Bean的实例。
后续重复名字的Bean就不会再注册了。
如果使用Resource注解,它是先根据名字来注入的,所以ioc拿的是ServiceA,这时给第二个注入的话就会发生类型转换的异常;如果使用Autowire注解,它是根据类型注入的,这时ioc只存在SerciceA类型的bean,所以会报类不存在的异常。