注入方式
- 还有注解注入,官方推荐使用构造器注入,理由如上。
Spring内置Tomcat的原理
spring概述
加载、注册进去,此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 两个方法分别在 Bean 初始化之前和初始化之后得到执行。注意,到这里 Bean 还没初始化根据IOC里面的注册表实例化bean,放到一个BUFFER POOL里面 ,用到的时候回调用它
bean生命周期
1.Spring对bean进行实例化,调用bean的构造参数
2.设置对象属性,调用bean的set方法,将属性注入到bean的属性中
3.检查bean是否实现BeanNameAware、BeanFactoryAware、ApplicationContextAware接口,如果实现了这几个接口Spring会分别调用其中实现的方法。
BeanNameAware:setBeanName(String name)方法,参数是bean的ID
BeanFactoryAware:setBeanFactory(BeanFactory bf)方法,参数是BeanFactory容器
ApplicationContextAware:setApplicationContext(ApplicationContext context)方法,参数是bean所在的引用的上下文,如果是用Bean工厂创建bean,那就可以忽略ApplicationContextAware。
4.如果bean是否实现BeanPostProcessor接口,Spring会在初始化方法的前后分别调用postProcessBeforeInitialization和postProcessAfterInitialization方法
5.如果bean是否实现InitalizingBean接口,将调用afterPropertiesSet()方法
6.如果bean声明初始化方法,也会被调用
7.使用bean,bean将会一直保留在应用的上下文中,直到该应用上下文被销毁。
8.检查bean是否实现DisposableBean接口,Spring会调用它们的destory方法
9.如果bean声明销毁方法,该方法也会被调用
Bean的加载过程
怎么写配置类
- 写实体类
- 写DAO
- 写配置类
- 写Service
- 写测试
AnnotationConfigApplicationContext
@Configuration用于定义配置类,可替换XML配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器
@Autowired默认是按照byType进行注入的,但是当byType方式找到了多个符合的bean,又是怎么处理的?如果发现找到多个bean,则又按照byName方式比对(默认是该类的类名,且首字母是小写),如果还有多个,则报出异常。
解决方案:当创建了多个具有相同类型的 bean 时,并且想要用一个属性只为它们其中的一个进行装配,在这种情况下,可以使用 @Qualifier 注释和 @Autowired 注释通过指定哪一个真正的 bean 将会被装配来消除混乱。
也就是说,当发现有多个相同类型的bean时,仅仅使用@Autowired注释是不行的, 因为@Autowired默认是按照byType进行注入的。此时,要结合@Qualifier注释,按照byName方式进行对比。
说说Ioc容器的加载过程吧
- 刷新预处理
- 将配置信息解析,注册到BeanFactory
- 设置bean的类加载器
- 如果有第三方想再bean加载注册完成后,初始化前做点什么(例如修改属性的值,修改bean的scope为单例或者多例。),提供了相应的模板方法,后面还调用了这个方法的实现,并且把这些个实现类注册到对应的容器中
- 初始化当前的事件广播器
- 初始化所有的bean
- 广播applicationcontext初始化完成。
//来自于AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
//进行加锁处理
synchronized (this.startupShutdownMonitor) {
// 进行刷新容器的准备工作,比如设定容器开启时间,标记容器已启动状态等等
prepareRefresh();
// 让子类来刷新创建容器
// 这步比较关键,这步完成后,配置文件就会解析成一个个 Bean 定义,注册到 BeanFactory 中,
// 当然,这里说的 Bean 还没有初始化,只是配置信息都提取出来了,
// 注册也只是将这些信息都保存到了注册中心(说到底核心是一个 beanName-> beanDefinition 的 map)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
prepareBeanFactory(beanFactory);
try {
// 这里需要知道 BeanFactoryPostProcessor 这个知识点,
//Bean 如果实现了此接口,那么在容器初始化以后,Spring 会负责调用里面的 postProcessBeanFactory 方法。
// 这里是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化
// 具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类或做点什么事
postProcessBeanFactory(beanFactory);
// 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
invokeBeanFactoryPostProcessors(beanFactory);
// 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别
// 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 两个方法分别在 Bean 初始化之前和初始化之后得到执行。注意,到这里 Bean 还没初始化
registerBeanPostProcessors(beanFactory);
// 初始化当前 ApplicationContext 的 MessageSource
initMessageSource();
// 初始化当前 ApplicationContext 的事件广播器
initApplicationEventMulticaster();
// 从方法名就可以知道,典型的模板方法(钩子方法),
// 具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
onRefresh();
// 注册事件监听器,监听器需要实现 ApplicationListener 接口
registerListeners();
// 初始化所有的 singleton beans(lazy-init 的除外)
// 重点方法将会在下一个章节进行说明
finishBeanFactoryInitialization(beanFactory);
// 最后,广播事件,ApplicationContext 初始化完成
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + ex);
}
// 销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// 把异常往外抛
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
@Service和@Bean的区别
一个是把类交给spring管理 生命周期同spring 一个是把对象交给spring管理 声明周期可控
使用 AnnotationConfigApplicationContext 注册配置类
- Spring是通过递归的方式获取目标bean及其所依赖的bean的;
- Spring实例化一个bean的时候,是分两步进行的,首先实例化目标bean,然后为其注入属性。
结合这两点,也就是说,Spring在实例化一个bean的时候,是首先递归的实例化其所依赖的所有bean,直到某个bean没有依赖其他bean,此时就会将该实例返回,然后反递归的将获取到的bean设置为各个上层bean的属性的。
(可以利用Two Sum的缓存解法)
使用Spring框架的好处是什么?
Spring由哪些模块组成?
SpringIOC的理解
ClassPathXmlApplicationContext
这是东东是我们用来读文件的,可以读配置的文件的类。
public interface ResourceLoader {
String CLASSPATH_URL_PREFIX = "classpath:";
Resource getResource(String var1);
ClassLoader getClassLoader();
}
ResourceLoader干了三件事,定义了加载地址,第二,定义了资源加载的方法,第三,定义了类加载器。哦哦,原来如此,ResourceLoader就是IoC的灵魂嘛,负责就是找到资源和加载资源嘛。
BeanFactory 很明显就是类的工厂。这下子清晰了吧,我们的Resource经过ResourceLoader的调和,用ClassLoader加载,最后变成了BeanFactory。这又是一个粗路线了。
我们想想资源是不是都需要定义和约束,于是有了BeanDefinition,我们需要封装,于是有了各种**wrapper。
解释AOP模块
解释WEB 模块
核心容器(应用上下文) 模块。
什么是Spring IOC 容器?
IOC的优点是什么?
ApplicationContext通常的实现是什么?
Bean 工厂和 Application contexts 有什么区别?
可能是最漂亮的Spring事务管理详解
事务的传播特性
spring的事务传播行为通俗来讲是事务和事务之间的关系,比如serviceA#methodA()和serviceB#methodB()这两个方法定义了不同的事务,那么事务是事务之间嵌套使用的时候要用什么样的行为呢?这个就是spring替我们控制的事务传播行为,从枚举Propagation中我们可以看到一共有七种,分别是
- PROPAGATION_REQUIRED:Spring的默认传播级别,如果上下文中存在事务则加入当前事务,如果不存在事务则新建事务执行。
- PROPAGATION_SUPPORTS:如果上下文中存在事务则加入当前事务,如果没有事务则以非事务方式执行。
- PROPAGATION_MANDATORY:该传播级别要求上下文中必须存在事务,否则抛出异常。
- PROPAGATION_REQUIRES_NEW:该传播级别每次执行都会创建新事务,并同时将上下文中的事务挂起,执行完当前线程后再恢复上下文中事务。(子事务的执行结果不影响父事务的执行和回滚)
- PROPAGATION_NOT_SUPPORTED:当上下文中有事务则挂起当前事务,执行完当前逻辑后再恢复上下文事务。(降低事务大小,将非核心的执行逻辑包裹执行。)
- PROPAGATION_NEVER:该传播级别要求上下文中不能存在事务,否则抛出异常。
- PROPAGATION_NESTED:嵌套事务,如果上下文中存在事务则嵌套执行,如果不存在则新建事务。(save point概念)
spring依赖注入
什么是Spring的依赖注入?
有哪些不同类型的IOC(依赖注入)方式?
什么是Spring beans?
一个 Spring Bean 定义 包含什么?
解释Spring支持的几种bean的作用域。
Spring框架中的单例bean是线程安全的吗?
解释Spring框架中bean的生命周期
哪些是重要的bean生命周期方法? 你能重载它们吗?
什么是bean装配?
什么是bean的自动装配?
解释不同方式的自动装配 。
- No:不做任何操作
- byname:根据属性名自动装配,此选项将检查容器并根据名字查找与属性完全一致的bean, 并将其与属性自动装配
- byType:如果容器中存在一个与制定属性类型相同的bean, 那么将与该属性自动装配,如果存在多个该类型bean,那么抛出异常,并指出不能使用byType方式进行自动装配,如果没有找到相匹配的bean, 则什么事都不发生
- Constructor:与byType方式类似, 不同之处在于它应用于构造参数,如果容器中没有找到与构造器参数类型一致的bean,那么抛出异常
自动装配有哪些局限性 ?
spring注解
怎样开启注解装配?
谈谈@Required、 @Autowired、 @Qualifier注解。
spring数据访问
在Spring框架中如何更有效地使用JDBC?
使用Spring通过什么方式访问Hibernate?
Spring框架的事务管理有哪些优点?
Spring面向切面编程(AOP)
解释AOP
AOP底层原理
https://www.cnblogs.com/javazhiyin/p/10101044.html
Aspect 切面
在Spring AOP 中,关注点和横切关注的区别是什么?
通知
有几种不同类型的自动代理?
什么是织入。什么是织入应用的不同点?
springmvc
MVC执行过程
1.用户发送请求至前端控制器DispatcherServlet
2.DispatcherServlet收到请求调用处理器映射器HandlerMapping。
3.处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。
4.DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
5.执行处理器Handler(Controller,也叫页面控制器)。
6.Handler执行完成返回ModelAndView
7.HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet
8.DispatcherServlet将ModelAndView传给ViewReslover视图解析器
9.ViewReslover解析后返回具体View
10.DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。
11.DispatcherServlet响应用户。
什么是Spring的MVC框架?
DispatcherServlet
WebApplicationContext
什么是Spring MVC框架的控制器?
@Controller 注解
@RequestMapping 注解
Javaweb
servlet与Tomcat
Servlet生命周期
forward和redirect的区别
tomcat容器是如何创建servlet类实例?用到了什么原理?
什么是cookie?Session和cookie有什么区别?
Servlet安全性问题
Tomcat 有哪几种Connector 运行模式(优化)?
jsp
jsp静态包含和动态包含的区别
jsp有哪些内置对象?作用分别是什么?
jsp和servlet的区别、共同点、各自应用的范围?
写出5种JSTL常用标签
JSP是如何被执行的?执行效率比SERVLET低吗?
说出Servlet和CGI的区别?
简述JSP的设计模式。
SpringBoot自动装配原理
- @Configuration(@SpringBootConfiguration实质就是一个@Configuration)
- @EnableAutoConfiguration
- @ComponentScan
自动依赖过程总结
-
通过各种注解实现了类与类之间的依赖关系,容器在启动的时候Application.run,会调用EnableAutoConfigurationImportSelector.class的selectImports方法(其实是其父类的方法)–这里需要注意,调用这个方法之前发生了什么和是在哪里调用这个方法需要进一步的探讨
-
selectImports方法最终会调用SpringFactoriesLoader.loadFactoryNames方法来获取一个全面的常用BeanConfiguration列表
-
loadFactoryNames方法会读取FACTORIES_RESOURCE_LOCATION(也就是spring-boot-autoconfigure.jar 下面的spring.factories),获取到所有的Spring相关的Bean的全限定名ClassName,大概120多个
-
selectImports方法继续调用filter(configurations, autoConfigurationMetadata);这个时候会根据这些BeanConfiguration里面的条件,来一一筛选,最关键的是
@ConditionalOnClass,这个条件注解会去classpath下查找,jar包里面是否有这个条件依赖类,所以必须有了相应的jar包,才有这些依赖类,才会生成IOC环境需要的一些默认配置Bean -
最后把符合条件的BeanConfiguration注入默认的EnableConfigurationPropertie类里面的属性值,并且注入到IOC环境当中