源码地址:https://download.csdn.net/download/u013636987/11387400
上一篇:系列二:struts2参数传递
Spring功能介绍
我们先不讨论Spring的好处,毕竟我个人觉得用久和用惯了,就会发现框架的方便还有代码的整洁。
那么Spring作用是什么,简单来说他就是一个工厂,你要生产什么产品,告诉他规格还有参数,他就帮你生产出产品。
我们都知道java是面向对象的编程,我们通常流程是先构造对象,然后实例化对象,然后使用new创建对象,然后就可以在某个方法里面使用这个对象了。而你只要告诉Spring创建对象的名称和值,这个工程就会自动帮你完成new创建对象,也就是说先构造对象,然后实例化对象,然后配置好xml给到工厂。然后你就可以某个类里面去set或者构造方法中获取这个被工厂生产出来的对象。
如下在配置文件中配置了property name="customerService" ,其中property表示set依赖注入
<!-- 配置客户模块 -->
<!-- 强调:以后配置Action,必须是多例的 -->
<!-- 客户功能配置 -->
<bean id="customerAction" class="com.customer.action.CustomerAction" scope="prototype">
<property name="customerService" ref="customerService"/>
</bean>
<bean id="customerService" class="com.customer.service.CustomerServiceImpl">
<property name="customerDao" ref="customerDao"/>
</bean>
然后就可以在class=com.customer.action.CustomerAction的这个类中直接set
// 提供service的成员属性,提供set方法
private CustomerService customerService;
public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}
你会发现不用去new一个CustomerService对象。这一步Spring已经帮你做好了,你可以直接调用customerService的方法。
这个就是Spring中的控制反转技术(IoC) ,简单来说就是程序把创建对象的控制权反转给Spring工厂,由此进行对象的创建和依赖关系的维护。
Spring启动流程和核心组件
Spring中的jar包,如下,其中有三个核心jar包,core,context,beans。core包侧重于帮助类,操作工具,beans包更侧重于bean实例的描述。context更侧重全局控制,功能衍生。
简化的总体结构
core-》Context -》Bean
core的ResourceLoader加载资源,Resource接口屏蔽资源提供者,提供资源
--------->Context 继承了 ResourceLoader 接口,获取资源--------->
ApplicationContext 是 Context 的顶级父类,他除了能标识一个应用环境的基本信息外,他还继承了五个接口,这五个接口主要是扩展了 Context 的功能。如下
1、AnnotationConfigApplicationContext:从一个或多个基于Java配置类中加载Spring应用上下文。
2、AnnotationConfigWebApplicationContext:从一个或多个基于java的配置类中加载Spring Web应用上下文。
3、ClassPathXmlApplicationContext:从类路径下的一个或多个xml配置文件中加载上下文定义,把应用上下文定义文件作为类资源。
4、FileSystemXMLApplicationContext:从文件系统下的一个或多个xml配置文件中加载上下文定义。
5、xmlWebApplicationContext:从Web应用的一个或多个xml配置文件中加载上下文定义。
--------->ApplicationContext 继承了 BeanFactory 创建bean---------->
Bean 的创建时典型的工厂模式,他的顶级接口是 BeanFactory
BeanFactory 有三个子类:ListableBeanFactory、HierarchicalBeanFactory 和 AutowireCapableBeanFactory。但终的默认实现类是 DefaultListableBeanFactory。实现多接口是为了区分在 Spring 内部操作对象传递和转化时,对对象的数据访问所做的限制。例如 ListableBeanFactory 接口表示这些 Bean 是可列表的,HierarchicalBeanFactory 表示的是这些 Bean 是有继承关系的,也就是每个 Bean 有可能有父 Bean。AutowireCapableBeanFactory 接口定义 Bean 的自动装配规则。这四个接口共同定义了 Bean 的集合、Bean 之间的关系、以及 Bean 行为
Spring启动流程
首先,对于一个web应用,其部署在web容器中,web容器提供其一个全局的上下文环境,这个上下文就是ServletContext,其为后面的spring IoC容器提供宿主环境;
contextLoaderListener监听事件
其次,在web.xml中会提供有contextLoaderListener。在web容器启动时,会触发容器初始化事件,此时contextLoaderListener会监听到这个事件,其contextInitialized方法会被调用,在这个方法中,spring会初始化一个启动上下文,这个上下文被称为根上下文,即WebApplicationContext,这是一个接口类,确切的说,其实际的实现类是XmlWebApplicationContext。这个就是spring的IoC容器,其对应的Bean定义的配置由web.xml中的context-param标签指定。在这个IoC容器初始化完毕后,spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE为属性Key,将其存储到ServletContext中,便于获取;
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
此部完成后spring已经通过classpath:applicationContext.xml读到了配置文件,完成对bean的解析和配置,如果有组件工厂,生成相对应的Factory,如下生成session的持久化工厂。
<!-- LocalSessionFactoryBean加载配置文件 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!-- 先加载连接池 -->
<property name="dataSource" ref="dataSource"/>
<!-- 加载方言,加载可选 -->
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<!-- 引入映射的配置文件 -->
<property name="mappingResources">
<list>
<value>com/customer/model/Customer.hbm.xml</value>
<value>com/login/model/Login.hbm.xml</value>
<value>com/logger/model/Logger.hbm.xml</value>
<value>com/authorization/model/Authorization.hbm.xml</value>
</list>
</property>
</bean>
启动servlet或者封装了servlet的struts2或spring mvc
contextLoaderListener监听器初始化完毕后,开始初始化web.xml中配置的Servlet,这个servlet可以配置多个,
例如spring mvc为DispatcherServlet,这个servlet实际上是一个标准的前端控制器,用以转发、匹配、处理每个servlet请求。DispatcherServlet上下文在初始化的时候会建立自己的IoC上下文。在建立DispatcherServlet自己的IoC上下文时,会利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先从ServletContext中获取之前的根上下文(即WebApplicationContext)作为自己上下文的parent上下文。有了这个parent上下文之后,再初始化自己持有的上下文。这个DispatcherServlet初始化自己上下文的工作在其initStrategies方法中可以看到,大概的工作就是初始化处理器映射、视图解析等。这个servlet自己持有的上下文默认实现类也是xmlWebApplicationContext。初始化完毕后,spring以与servlet的名字相关(此处不是简单的以servlet名为Key,而是通过一些转换,具体可自行查看源码)的属性为属性Key,也将其存到ServletContext中,以便后续使用。这样每个servlet就持有自己的上下文,即拥有自己独立的bean空间,同时各个servlet共享相同的bean,即根上下文(上面初始化的上下文)定义的那些bean。
但是此项目并没有用到spring mvc,本项目是配置好struts2,然后把本来应该struts2自己创建的action反转给spring创建。
spring配置文件中配置
<bean id="customerAction" class="com.customer.action.CustomerAction" scope="prototype">
<property name="customerService" ref="customerService"/>
</bean>
struts2配置文件中配置
<action name="customer_*" class="customerAction" method="{1}">
因为struts2已经配置好了,拦截器已经启动,当jsp页面向服务器发出请求,被ActionServlet拦截。ActionServlet根据用户的请求在struts配置文件中查找与之对应的Action(Spring创建的),同时将用户的数据填充给对应的ActionForm,然后将ActionForm一起分发给Action进行处理,Action会自动调用相应的方法,将从ActionForm里面获取用户填写的数据。
综上所述:
spring作为核心业务层,通过bean创建控制层的action,本身的service,还有持久层的session。然后通过依赖注入。session注入service,service注入action。达到对象的创建和依赖关系的维护目的。从而实现MVC: Model + View + Controller(数据模型+视图+控制器)
<!--sessionFactory注入customerDao,customerDao注入customerService,customerService注入customerAction-->
<bean id="customerDao" class="com.customer.dao.CustomerDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="customerService" class="com.customer.service.CustomerServiceImpl">
<property name="customerDao" ref="customerDao"/>
</bean>
<bean id="customerAction" class="com.customer.action.CustomerAction" scope="prototype">
<property name="customerService" ref="customerService"/>
</bean>