Spring IOC中bean的创建是利用反射+xml解析实现的,因此这里也围绕这个来做分析。
ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
Spring所有的工作由这一句代码开始,接下就去剖析这个类ClassPathXmlApplicationContext。
由上图的继承关系可以看到,所有的类都包含这个接口(BeanFactory)。从下面的源码 可以看到BeanFactory定义了 IOC 容器的最基本形式,并提供了 IOC 容器应遵守的的最基本的接口,也就是Spring IOC 所遵守的最底层和最基本的编程规范。在 Spring 代码中, BeanFactory 只是个接口,并不是 IOC容器的具体实现,但是 Spring 容器给出了很多种实现,如 DefaultListableBeanFactory 、 XmlBeanFactory 、ApplicationContext 等,都是附加了某种功能的实现。
public interface BeanFactory {
//这里是对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,
//如果需要得到工厂本身,需要转义
//转义符“&”用来获取FactoryBean本身
String FACTORY_BEAN_PREFIX = "&";
//根据bean的名字进行获取bean的实例,这是IOC最大的抽象方法
Object getBean(String name) throws BeansException;
//根据bean的名字和Class类型进行获取Bean的实例,和上面方法不同的是,bean名字和Bean 的class类型不同时候会爆出异常
T getBean(String name, Class requiredType) throws BeansException;
T getBean(Class requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
//检测这个IOC容器中是否含有这个Bean
boolean containsBean(String name);
//判断这个Bean是不是单利
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
//判断这个Bean是不是原型
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
//查询指定的bean的名字和Class类型是不是指定的Class类型
boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException;
//这里对得到bean实例的Class类型
Class> getType(String name) throws NoSuchBeanDefinitionException;
//这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来
String[] getAliases(String name);
}
从这个接口的函数名不难看出,这个接口是对应xml中bean的解析的。这里就不过多解释这些函数的意义了。
有一个类BeanDefinitionHolder,根据名称或者别名持有beanDefinition,它承载了beanName和BeanDefinition的映射信息。
BeanWrapper:提供对Javabean的分析和操作方法,单个或者批量获取和设置属性值,获取属性描述符,查询属性的可读性和可写性等。支持属性的嵌套设置,深度没有限制。
AbstractRefreshableApplicationContext:
接下进入loadBeanDefinition的实现:
进入loadBeanDefinitions(..)。
继续进入reader.loadBeanDefinitions(..)的实现:
继续loadDefinitions的实现直到到达下面这个实现:
这里直接进入解析单个bean的实现
都是加载bean的定义的,此时选择xml形式的实现,直接找到如下实现:
进入真正加载的这个方法。
进入bean的注册,
继续点击有关register这个单词的,直到下面这个类,很明显这个类就是遍历这个xml节点:
点击默认的,进入判断解析类型。
进入bean类型解析:
接下来,我们直接看他怎么解析的
看看怎么创建的?
进入一看这个类,原来就是包含一些删除,添加(注册)等等的操作的类嘛,说白了就是维护一个hashMap,然后查询获取bean咯。
1、Spring对bean进行实例化(相当于new)
2、Spring将值和bean的引用注入到Bean对应的属性中
3、如果Bean实现了BeanNameAware接口,Spring将Bean的id传递给setBeanName()方法(实现BeanNameAware接口主要是为了通过Bean的引用来获得Bean的id,一般业务中是很少用到Bean的id的)
4、如果实现了BeanFactoryAware接口,Spring将调用setBeanFactory(BeanFactory bf)方法并把BeanFactory容器实例作为参数传入。(实现BeanFactoryAware主要目的是为了获取Spring容器,如bean通过Spring容器发布事件等)
5、如果Bean实现了ApplicationContextAware接口,Spring容器将调用setApplicationContext()方法,把Bean所在的应用上下文的引用传入。(作用和BeanFactory类似为获取Spring容器,不同的是Spring容器在调用setApplicationContext()时会把自己作为参数传入。而Spring容器在调用setBeanFactory前需要程序员自己指定(注入)BeanFactory里的参数)
6、如果Bean实现了BeanPostProcessor接口,Spring将调用他们的postProcessBeforeInitialization(预初始化)方法。(作用是在Bean实例化创建成功后对其进行增强处理,比如对bean进行修改,增加功能等)
7、如果bean实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet方法,作用与配置文件中对bean使用init-method声明初始化的作用一样,都是在bean的全部属性设置成功后执行的初始化方法。
8、如果bean实现了BeanPostProcess接口,Spring将调用他们的postProcessAfterInitialization方法(后初始化),在bean初始化之后执行。
9、此时bean应准备就绪,可以本程序使用,bean将一直驻留在应用上下文中给应用使用,直到应用上下文被销毁。
10、如果bean实现了DispostbleBean接口,Spring将调用他的destroy方法,作用与在配置文件中对bean调用destroy-method属性的作用一样,都是在bean实例化销毁之前执行。
@Getter
public class User implements BeanNameAware,BeanFactoryAware,ApplicationContextAware,BeanPostProcessor,InitializingBean,DisposableBean {
private String name;
private Integer age;
public void setName(String name) {
System.out.println("2、填充属性");
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public User() {
System.out.println("1、实例化");
}
@Override
public void setBeanName(String s) {
System.out.println("3、BeanNameAware的setBeanName:name="+s);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("4、BeanFactoryAware的setBeanFactory。。");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("5、ApplicationContextAware的setApplication...");
}
@Override
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
System.out.println("6、bean初始化之前执行,beanname="+s);
return o;
}
@Override
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
System.out.println("8、bean初始化之后执行,beanname="+s);
return o;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("7、属性设置成功后执行的初始化方法");
}
@Override
public void destroy() throws Exception {
System.out.println("9、销毁bean方法");
}
}
Scope为原型,在容器初始化定义的bean创建之前,容器会自己去查找所有的beanPostProcessor进行创建,自定义的类,由于是实现了BeanPostProcessor接口,因此这时候会进行BeanPostProcessor的创建和注册,源码中,在注册BeanPostProcessor会进行getBean操作,即创建自定义的bean。由于默认的是单例模式,因此后面再次进行获取就不会再次调用postProcessBeforeInitialization()和postProcessAfterInitialization()方法,因为已经放入了spring缓存,直接获取,不需要实例,因此没有调用。如果你真的想使用的时候调用postProcessBeforeInitialization()和postProcessAfterInitialization()方法,将你的bean设置为原型模式(prototype),这样每次调用都会创建,因此初始化容器之后每次都会调用的。
AOP的好处:1、降低模块之间的耦合度2、更好的代码复用3、更容易扩展
1)AOP标签的定义解析是从NamespaceHandlerSupport的实现类开始解析的,这个实现类就是AopNamespaceHandler。至于为什么会是从NamespaceHandlerSupport的实现类开始解析的,这个的话我想读者可以去在回去看看Spring自定义标签的解析流程,里面说的比较详细。
2)要启用AOP,我们一般会在Spring里面配置
3)进入AspectJAutoProxyBeanDefinitionParser解析器后,调用AspectJAutoProxyBeanDefinitionParser已覆盖BeanDefinitionParser的parser方法,然后parser方法把请求转交给了AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary去处理
4)进入AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法后,先调用AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法,里面在转发调用给registerOrEscalateApcAsRequired,注册或者升级AnnotationAwareAspectJAutoProxyCreator类。对于AOP的实现,基本是靠AnnotationAwareAspectJAutoProxyCreator去完成的,它可以根据@point注解定义的切点来代理相匹配的bean。
5)AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法处理完成之后,接下来会调用useClassProxyingIfNecessary() 处理proxy-target-class以及expose-proxy属性。如果将proxy-target-class设置为true的话,那么会强制使用CGLIB代理,否则使用jdk动态代理,expose-proxy属性是为了解决有时候目标对象内部的自我调用无法实现切面增强。
6)最后的调用registerComponentIfNecessary 方法,注册组建并且通知便于监听器做进一步处理。
创建AOP代理流程
1、Spring容器启动,每个bean的实例化之前都会先经过AbstractAutoProxyCreator类的postProcessAfterInitialization这个方法,然后接下来是wrapIfNecessary
SpringMVC其实底层也是封装HttpServlet实现的,我们知道HTTPServlet的流程是,每个请求到达,调用该Servlet的service方法。因此SpringMVC也是类似的呀,接下来走起。
1、所有的MVC请求都交给DispatcherServlet这个类处理,然后调用doService方法,交给doDispatch方法
最后通过视图解析器解析渲染后返回给客户端。
描述:
1、用户向服务器发送请求,请求被Spring前端控制Servlet DispatcherServlet捕获
2、DispatcherServlet对请求URL进行解析,得到请求资源标识符,然后根据URI调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回。
3、DispatcherServlet根据获得的Handler,选择一个合适的HandlerAdapter。
4、提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。
在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
5、Handler执行完成后,向DispatcherServlet返回一个ModelAndView对象
6、根据返回的ModelAndView选择一个合适的ViewResolver返回给DispatcherServlet
7、ViewResolver结合Model和View,来渲染视图
8、将渲染结果返回给客户端
为什么Spring只使用一个Servlet(DispatcherServlet)来处理所有请求?
用于集中统一化对外的请求接口,便于更好的封装内部逻辑。
Spring为什么要结合使用HandlerMapping以及HandlerAdapter来处理Handler?
符合面向对象中的单一职责原则,代码架构清晰,便于维护,最重要的是代码可复用性高。如HandlerAdapter可能会被用于处理多种Handler。