面试之Spring
一、IoC
IoC(Inversion of Control):控制反转(是把传统上由程序代码直接操控的对象的生成交给了容器来实现, 通过容器来实现对象组件的装配和管理。所谓“控制反转”就是组件对象控制权的转移,从程序代码本身转移到了外部容器, 由容器来创建并管理对象之间的关系。),是Spring Core中最核心的部分,是通过依赖注入DI(Dependency Inversion)实现的。依赖注入的方式:
- Setter
- Interface
- Constructor
- Annotation(如@Autowired)
IoC容器的优势
- 避免了在各处使用new创建类,并且可以做到统一的维护
- 创建实例的时候不需要了解其中的细节
Spring IoC容器
Spring 框架的核心就是Spring容器,由容器来创建对象,并将它们装配在一起,配置并管理它们的完整生命周期, Spring容器使用依赖注入来管理组成应用程序的组件。容器通过读取提供的配置元数据(该元数据可以通过XML、Java注解或Java代码提供。)来接受对象进行实例化,配置和组装的命令。
Spring IoC支持的功能
- 依赖注入
- 依赖检查
- 自动装配
- 支持集合
- 指定初始化方法和销毁方法
- 支持回调方法
Spring IoC容器的种类
- BeanFactory
- 提供了IoC的配置机制
- 包含了Bean的各种定义,以便实例化Bean
- 建立Bean之间的依赖关系
- Bean生命周期的控制
- ApplicationContext(应用上下文):ApplicationContext接口扩展了BeanFactory接口,它在BeanFactory基础上,又继承了多个接口来提供了一些额外的功能。继承的接口如下:
- BeanFactory:能够管理、装配Bean
- ResourcePatternResolver:能够加载资源文件
- MessageSource:能够实现国际化等功能
- ApplicationEventPublisher:能够注册监听器实现监听机制
二、Spring Bean
面:谈谈Spring Bean的5个作用域?
Spring bean支持5种scope,默认是Singleton
。
Singleton
:每一个Spring IoC容器中仅存在一个单实例bean
<!--定义bean交给Spring IoC容器管理-->
<bean id="category" class="com.yunche.spring.pojo.Category" scope="singleton">
<!--为属性name注入初值"book"-->
<property name="name" value="book"/>
</bean>
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Category c1 = (Category) context.getBean("category");
Category c2 = (Category) context.getBean("category");
System.out.println(c1 == c2);
}/*Out put:
true
*/
}
Prototype
:每次从容器中请求调用bean时,都会返回一个新的实例
<!--定义bean交给Spring IoC容器管理-->
<bean id="category" class="com.yunche.spring.pojo.Category" scope="prototype">
<!--为属性name注入初值"book"-->
<property name="name" value="book"/>
</bean>
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Category c1 = (Category) context.getBean("category");
Category c2 = (Category) context.getBean("category");
System.out.println(c1 == c2);
}/*Out put:
false
*/
}
Request
:每次Http请求都会创建一个新的beanSession
:同一个HttpSession共享同一个bean,不同的HttpSession使用不同的beanGlobalSession
:同一个全局Session共享一个bean
Spring bean的生命周期
- Spring IoC容器找到关于bean的定义并实例化该bean
- Spring IoC容器对bean进行依赖注入
- 如果bean实现了
BeanNameAware
接口,则将该bean的id传给setBeanName()
方法 - 如果bean实现了
BeanFactoryAware
接口,则将BeanFactory
对象传给setBeanFactory()
方法 - 如果bean实现了
BeanPostProcessor
接口,则调用其postProcessBeforeInitialization()
方法 - 如果bean实现了
InitializingBean
接口,则调用其afterPropertySet()
方法 - 如果有何bean管理的
BeanPostProcessor
对象,则这些对象的postProcessAfterInitialization()
方法被调用 - 当销毁bean实例时,如果bean实现了
DisposableBean
接口,则调用其destory()
方法
三、AOP
- AOP(面向切面编程)是关注点分离技术(不同的问题交给不同的部分去解决)的体现
- 通用化功能代码的实现,对应的就是所谓的切面(Aspect)
- 将业务功能和切面代码分开后,架构变得高内聚低耦合
- 确保功能的完整性:切面最终需要被合并到业务中(Weave织入)
AOP的三种织入方式:
- 编译时织入:需要特殊的Java编译器,如AspectJ
- 类加载时织入:需要特殊的Java编译器,如AspectJ和AspectWerkz
- 运行时织入:Spring采用的方式,通过动态代理的方式,实现简单
AOP主要名词
- Aspect:通用功能的代码实现
- Target:被织入Aspect的对象
- Join Point:可以作为切入点的机会,所有方法都可以作为切入点
- Pointcut:Aspect实际被应用在的Join Point,支持正则
- Advice:类里的方法以及这个方法如何织入到目标方法的方式
- Weaving:AOP的实现过程
Advice的种类
- 前置增强(Before)
- 后置增强(AfterReturning)
- 异常增强(AfterThrowing)
- 最终增强(After)
- 环绕增强(Around)
面:能否写一个Spring AOP例子?
package com.yunche.springaop.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author yunche
* 被织入Aspect的对象--target
* @date 2019/04/01
*/
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello world";
}
}
package com.yunche.springaop.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* 切面Aspect--通用功能的实现,这里用于日志处理
* @author yunche
* @date 2019/04/01
*/
@Aspect
@Component
public class RequestLogAspect {
private static final Logger logger = LoggerFactory.getLogger(RequestLogAspect.class);
//Pointcut
@Pointcut("execution(public * com.yunche.springaop.controller..*.*(..))")
public void webLog() {
}
//前置增强 advice
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) {
//使用日志记录下用户的IP和请求的URL
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = attributes.getRequest();
logger.info("URL: " + request.getRequestURI());
logger.info("IP: " + request.getRemoteAddr());
}
//后置增强 advice
@AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(Object ret) {
//用于处理返回的结果
logger.info("RESPONSE: " + ret);
}
}
当访问http://localhost:8080/hello时,切面AOP的日志模块就会自动记录下相应的信息。
2019-04-01 15:53:57.857 INFO 9704 --- [nio-8080-exec-4] c.y.springaop.aspect.RequestLogAspect : URL: /hello
2019-04-01 15:53:57.858 INFO 9704 --- [nio-8080-exec-4] c.y.springaop.aspect.RequestLogAspect : IP: 0:0:0:0:0:0:0:1
2019-04-01 15:53:57.858 INFO 9704 --- [nio-8080-exec-4] c.y.springaop.aspect.RequestLogAspect : RESPONSE: Hello world
面:你知道AOP是怎么实现的吗?
答:AOP的实现有:JdkProxy和Cglib(通过修改字节码)
- 由AOPProxyFactory根据AdvisedSupport对象的配置来决定
- 默认策略如果目标是接口,则用JdkProxy来实现,否则用后者
- JdkProxy的核心:InvocationHandler和Proxy类
- Cglib:以继承的方式动态生成目标类的代理
- JDKProxy:通过Java的内部反射机制实现
- Cglib:借助ASM(动态修改字节码的框架)
- 反射机制在生成类的过程中比较高效
- ASM在生成类之后的执行过程中比较高效
Spring里的代理模式(接口+真实实现类+代理类)的实现
- 真实实现类的逻辑包含在了getBean方法里
- getBean方法返回的实际上是Proxy的实例
- Proxy实例是Spring采用JDK Proxy或CGLIB动态生成的
面:能否写一个通过动态代理的方式实现AOP?
package com.yunche.aop.aspect;
/**
* @ClassName: MyAspect
* @Description: 切面
* @author: yunche
* @date: 2018/10/09
*/
public class MyAspect {
public void start() {
System.out.println("模拟事务处理功能...");
}
public void end() {
System.out.println("程序结束后执行此处...");
}
}
package com.yunche.aop.jdk;
/**
* @ClassName: UserDao
* @Description:
* @author: yunche
* @date: 2018/10/09
*/
public interface UserDao {
void addUser();
}
package com.yunche.aop.jdk;
/**
* @ClassName: UserDaoImpl
* @Description:
* @author: yunche
* @date: 2018/10/09
*/
public class UserDaoImpl implements UserDao {
@Override
public void addUser() {
System.out.println("新增用户");
}
}
package com.yunche.aop.jdk;
import com.yunche.aop.aspect.MyAspect;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @ClassName: JdkProxy
* @Description: JDK代理类
* @author: yunche
* @date: 2018/10/09
*/
public class JdkProxy implements InvocationHandler {
/**
* 声明目标类接口
*/
private UserDao userDao;
/**
* 创建代理方法
*
* @param userDao
* @return
*/
public Object createProxy(UserDao userDao) {
this.userDao = userDao;
//1.类加载器
ClassLoader classLoader = JdkProxy.class.getClassLoader();
//2.被代理对象实现的所有接口
Class[] clazz = userDao.getClass().getInterfaces();
//3.使用代理类、进行增强,返回的是代理后的对象
return Proxy.newProxyInstance(classLoader, clazz, this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//声明切面
MyAspect myAspect = new MyAspect();
//指定位置程序执行前执行这个方法
myAspect.start();
//在目标类上调用方法
Object obj = method.invoke(userDao, args);
//指定位置程序执行结束后执行
myAspect.end();
return obj;
}
}
package com.yunche.aop.test;
import com.yunche.aop.jdk.JdkProxy;
import com.yunche.aop.jdk.UserDao;
import com.yunche.aop.jdk.UserDaoImpl;
/**
* @ClassName: JdkTest
* @Description:
* @author: yunche
* @date: 2018/10/09
*/
public class JdkTest {
public static void main(String[] args) {
//创建代理对象
JdkProxy jdkProxy = new JdkProxy();
//创建目标对象
UserDao userDao = new UserDaoImpl();
//从代理对象中获取增强后的目标对象
UserDao userDao1 = (UserDao) jdkProxy.createProxy(userDao);
//执行方法
userDao1.addUser();
}/*Output:
模拟事务处理功能...
新增用户
程序结束后执行此处...
*/
}
四、Spring MVC
Spring MVC的工作原理(DispatcherServlet的工作流程)
- 客户端的所有请求都交给前端控制器DispatcherServlet来处理,它会负责调用系统的其他模块来真正处理用户的请求。
- DispatcherServlet收到请求后,将根据请求的信息(包括URL、HTTP协议方法、请求头、请求参数、Cookie等)以及HandlerMapping的配置找到 处理该请求的Handler(任何一个对象可以作为请求的Handler),最后以HandlerExecutionChain对象形式返回。
- DispatcherServlet根据获得的Handler,选择一个合适的HandlerAdapter,它用统一的接口对各种Handler中的方法进行调用。
- Handler完成对用户请求的处理后,会返回一个ModelAndView对象给DispatcherServlet。
- DispatcherServlet借助ViewResolver完成从逻辑视图(ModelAndView是逻辑视图)到真实视图对象的解析工作。
- 当得到真实的视图对象后,DispatcherServlet会利用视图对象对模型数据进行渲染。
- 客户端得到响应,可能是一个普通的HTML页面,也可以是XML或JSON字符串,或图片、PDF文件。
参考资料
面试之Spring的更多相关文章
- 【面试】Spring事务面试考点吐血整理(建议珍藏)
Spring和事务的关系 关系型数据库.某些消息队列等产品或中间件称为事务性资源,因为它们本身支持事务,也能够处理事务. Spring很显然不是事务性资源,但是它可以管理事务性资源,所以Spring和 ...
- 回客科技 面试的 实现ioc 容器用到的技术,简述BeanFactory的实现原理,大搜车面试的 spring 怎么实现的依赖注入(DI)
前言:这几天的面试,感觉自己对spring 的整个掌握还是很薄弱.所以需要继续加强. 这里说明一下spring的这几个面试题,但是实际的感觉还是不对的,这种问题我认为需要真正读了spring的源码后说 ...
- 【面试】Spring问答Top 25
本文由 ImportNew - 一直在路上 翻译自 howtodoinjava.欢迎加入翻译小组.转载请见文末要求. 本人收集了一些在大家在面试时被经常问及的关于Spring的主要问题,这些问题有可能 ...
- 【面试】我是如何在面试别人Spring事务时“套路”对方的
“中国最好面试官” 自从上次写了一篇“[面试]我是如何面试别人List相关知识的,深度有点长文”的文章后,有读者专门加我微信,说我是“中国最好面试官”,这个我可受不起呀. 我只是希望把面试当作是一次交 ...
- 面试关于Spring循环依赖问题,我建议你这么答!
写在前面 在关于Spring的面试中,我们经常会被问到一个问题:Spring是如何解决循环依赖的问题的. 这个问题算是关于Spring的一个高频面试题,因为如果不刻意研读,相信即使读过源码,面试者也不 ...
- 面试:Spring面试知识点总结
Spring知识点总结 1. 简介一下Spring框架. 答:Spring框架是一个开源的容器性质的轻量级框架.主要有三大特点:容器.IOC(控制反转).AOP(面向切面编程). 2. Spring框 ...
- 【Java面试】Spring中 BeanFactory和FactoryBean的区别
一个工作了六年多的粉丝,胸有成竹的去京东面试. 然后被Spring里面的一个问题卡住,唉,我和他说,6年啦,Spring都没搞明白? 那怎么去让面试官给你通过呢? 这个问题是: Spring中Bean ...
- [Java面试五]Spring总结以及在面试中的一些问题.
1.谈谈你对spring IOC和DI的理解,它们有什么区别? IoC Inverse of Control 反转控制的概念,就是将原本在程序中手动创建UserService对象的控制权,交由Spri ...
- 面试准备--Spring(IoC)
Spring是为了解决企业应用开发的复杂性而创建的一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架. 1.IoC:控制反转(Inversion of Control)是一个重要的面向对象编 ...
随机推荐
- 洛谷 P1082 同余方程 —— exgcd
题目:https://www.luogu.org/problemnew/show/P1082 用 exgcd 即可. 代码如下: #include<iostream> #include&l ...
- Spark 大数据文本统计
此程序功能: 1.完成对10.4G.csv文件各个元素频率的统计 2.获得最大的统计个数 3.对获取到的统计个数进行降序排列 4.对各个元素出现次数频率的统计 import org.apache.sp ...
- bzoj2720: [Violet 5]列队春游(概率期望+组合数学)
Description Input Output Sample Input Sample Output HINT 数学题都这么骚的么……怎么推出来的啊……我是真的想不出来…… 首先,要算总的视 ...
- Luogu P1330 封锁阳光大学【Dfs】 By cellur925
题目传送门 这道题我们很容易去想到二分图染色,但是这个题好像又不是一个严格的二分图. 开始的思路:dfs每个点,扫与他相邻的每个点,如果没访问,染相反颜色:如果访问过,进行检查,如果不可行,直接结束程 ...
- SpringMVC分页查询无法直接将对象转换成json的解决办法(报org.springframework.http.converter.HttpMessageNotWritableException: No converter found for return value of type:错)
在用ajax获得分页数据时,无法将获取的值赋值给input标签,在修改用户信息时不显示用户已经注册的信息,百度可知 springmvc处理分页数据返回的对象时,无法直接将对象转换成json,会报org ...
- selenium通过autoit实现上传和下载
autoit安装目录如下: AutoIt Windows Info 用于帮助我们识Windows控件信息. Compile Script to.exe 用于将AutoIt生成 exe 执行文件. ...
- 获取select里面option所有的值
1.HTML结构 <select id="test"> <option value="option-1">option-1</op ...
- 阿里maven仓库地址
在国内访问Maven仓库,连接速度太慢.下面是将中央仓库替换成阿里云的中央仓库的方法. 第一种,统一修改仓库地址 可以直接修改Mavenconf文件夹中的setting.xml文件,或者在.m2文件夹 ...
- 一个DBA萌新的烦恼
莫名其妙也好机缘巧合也罢,现在我成为了一名MySQL DBA. 为什么: 1.为什么leader让我转到DBA? 首先,我本身学习运维管理的时候就接触过数据库(mysql,redis),算是自身的优势 ...
- WPF学习07:MVVM 预备知识之数据绑定
MVVM是一种模式,而WPF的数据绑定机制是一种WPF内建的功能集,两者是不相关的. 但是,借助WPF各种内建功能集,如数据绑定.命令.数据模板,我们可以高效的在WPF上实现MVVM.因此,我们需要对 ...