以下是初识Spring做的笔记,对框架各个模块做一个简单介绍,后续会更新重要模块的细节,敬请期待!
源码阅读
ctrl+f12 , 查看类中所有方法
ctrl+alt+u , 查看类的继承图
alt+f7:查看方法引用位置
ctrl+f11:显示bookmark标记情况,土黄色代表该字符已被占用,输入或者点击1代表在此位置书签为1
shift+f11:显示所有书签,左栏是我打过书签的类、行信息,右边是代码详情
alt+f8:启用Evaluate窗口,当我们想看返回值,无法声明变量查看该变量的时候(源码不可更改)
Spring源码阅读笔记及DEMO:
https://github.com/seaswalker/spring-analysis
Spring源码理解总结
https://www.zhihu.com/question/48427693/answer/723146648
谈一下对spring的理解
Spring是一个轻量及框架,在我们整个开发过程中所有的框架生产几乎都依赖于Spring, Spring帮我们起到了一个IOC容器的作用,用来承载我们整体的bean对象,它帮进行了整个对象从创建到销毁整个生命周期的管理. 我们在使用Spring的时候, 可以使用配置文件, 也可以使用注解的方式来进行相关实现, 但是, 当我们程序开始启动之后, 我要把注解或者配置文件定义好的那些bean对象转换成一个BeanDefinition, 然后要完成BeanDefinition的解析和加载过程. 当获取到这些完整的对象之后, 对整个BeanDefinition进行实例化操作, 使用反射的方式来创建对象, 创建完对象时,只是在堆里开辟了一块空间, 还需要完成后续的一系列初始化操作. 这些操作包括Aware接口的相关\初始化方法的操作\执行AOP的postProcessor\BeanDefinition的BeanFactoryProcessor来实现相关的扩展工作, 当整体对象都创建完成后, 对象就可以直接调用了.
源码解析
-
BeanDefinitionReader作为一个接口,用来被实现处理从配置文件或注解生成对应的BeanDefinition的
-
BeanFactory接口, 用于获取BeanDifinition被BeanFacotryPostProcessor实现类处理后的对象, 对其通过反射进行实例化
-
Aware接口的作用
为了使得某些自定义对象能够方便的获取到容器对象, 如果想在自定义的普通对象里面, 获得applicationContext /BeanFactoryAware /BeanClassLoaderAware 等容器对象, 那么需要实现对应的接口, 实现里面的set方法, 在Bean初始化时会调用该方法.
-
PostProcessor后置处理器
- BeanFactoryPostProcessor, 完成对BeanFactory相关信息的修改或扩展
- BeanPostProcessor, 完成对Bean的修改或扩展工作
-
BeanPostProcessor作用
在接口中有postProcessBeforeInitialization和postProcessAfterInitialization方法, 在初始化时会被调用其实现类
其中AOP是实现的AbstractAutoProxyCreator.在postProcessAfterInitialization中
//此方法是真正创建AOP代理的地方,首先查看是否在earlyProxyReferences里存在, 如果有说明处理过了,不存在就考虑是否要包装(代理) @Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { //获取当前bean的key,如果beanName部位空,则以BeanName为key,如果FactoryBean类型 //前面会添加&符号, 如果beanName为空, 则以当前bean对应的class为key Object cacheKey = getCacheKey(bean.getClass(), beanName); //判断当前bean是否正在被代理,如果正在被代理则不进行封装了 if (this.earlyProxyReferences.remove(cacheKey) != bean) { //如果需要被代理,则需要封装指定的bean return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
createProxy()方法中使用了AopProxy接口实现类: CglibAopProxy和JdkDynamicAopProxy,根据被代理对象是否实现了接口来选择不同的实现
//判断是否被处理过,是否需要跳过, 跳过的话直接放进advisedBeans里,表示不进行代理 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { //如果已经处理过,直接返回 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } //advisedBean缓存了已经进行处理的bean,如果缓存中存在,可以直接返回 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } //isInfrastructureClass()用于判断当前bean是否为Spring系统自带的bean,自带的bean不需要代理; //shouldSkip()用于判断当前bean是否应该被略过 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { //对当前bean进行缓存 this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. //获取当前bean的Advices和Advisors Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { // 缓存当前bean的代理状态 this.advisedBeans.put(cacheKey, Boolean.TRUE); // 根据获取到的Advices和Advisors为当前bean生成代理对象 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); //缓存生成的bean的类型, 并且返回生成的代理bean this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
refresh方法
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. //前戏, 做容器刷新前的准备工作 // 1. 设置容器的启动时间 // 2. 设置活跃状态为true // 3. 设置关闭状态为false // 4. 获取Environment对象, 并加载当前系统的属性值到Environment对象中 // 5. 准备监听器和事件的集合对象, 默认为空的集合 prepareRefresh(); // Tell the subclass to refresh the internal bean factory. // 创建容器对象:DefaultListableBeanFactory // 加载xml配置文件的属性值到当前工厂中, 最重要的就是BeanDifinition ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. // beanFactory的准备工作,对各种属性进行填充 prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. // 子类覆盖方法做额外的处理,此处我们自己一般不做任何扩展工作, 但是web中的代码是有具体实现的 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. //调用各种beanFactory处理器 invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. //注册bean处理器, 只是注册功能,真真调用的是getBean方法 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. // 国际化处理 initMessageSource(); // Initialize event multicaster for this context. // 初始化事件监听多路广播器 initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. // 留给子类来初始化其他bean onRefresh(); // Check for listener beans and register them. // 在所有注册的bean中查找listner bean, 注册到消息广播器中 registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. // 实例化剩下所需的单实例(懒加载的) finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
SpringMVC
springmvc处理json: https://www.cnblogs.com/hujingwei/p/5351378.html
使用HttpMessageConverter
-使用@RequestBody/@ResponseBody
-使用HttpEntity<T>/ResponseEntity<T>作为方法的入参或返回值。
当处理方法使用到@RequestBody/@ResponseBody或HttpEntity<T>/ResponseEntity<T>时,Spring首先根据请求头或响应头的Accept属性选择匹配的HttpMessageConverter,进而根据参数类型或泛型类型的过滤得到匹配的HttpMessageConverter,若找不到,就会报错。
dispatcherServlet, 在adapter的hanler方法中会返回ModelAndView, 其中用到了 ContentNegotiatingViewResolver ,“内容协商视图解析器”,其实就是根据返回什么类型的视图,就协商使用哪种视图解析器。如果返回jsp就使用InternalResourceViewResolver视图解析器,如果返回JSON格式就使用MappingJackson2JsonView来处理。
返回jsp或thymleaf视图时会找到静态页面地址,然后处理绑定对象, 将内容放到响应体中一起返回.如果是json视图, 则只会返回被序列化为JSON的对象作为响应体.
Spring在请求进行的各个生命周期都有钩子, 可以通过实现或继承或用@Bean重写的方式来扩展增强.