Spring(1)

Spring(1)


Spring框架学习

Spring框架概述

之前学习了struts2、Hibernate两大框架,知道了:
struts2是基于MVC模式的表现层框架,主要是作为控制层组件,还可影响Javabean、JSP。
Hibernate是基于ORM规则的持久层框架,简化了JDBC操作,使得用户可以采用面向对象的思想操作数据库数据。

下面来到Spring,Spring是什么呢(WHAT)?为什么要使用Spring(WHY)?具体要怎么操作呢(HOW)?
Spring提供了一个全面的、一站式的JavaEE解决方案,主要包括以下功能:
- 基于依赖注入(控制反转IoC)的核心机制
- 声明式的面向切面编程(AOP)支持
- 与多种技术整合
- 优秀的Web MVC框架

Spring是企业应用开发的一站式选择,贯穿了表达层、业务层、持久层,而且并不会取代原有的框架,而是以高度的可定制性与之无缝结合。

Spring具有以下优点:
1. 低侵入式的设计,无代码污染。
2. 独立与各种应用服务器。
3. IoC容器降低了业务对象替换的复杂性,降低了组件之间的耦合度。
4. AOP容器允许将一些通用任务如安全、事务、日志等进行集中式处理。
5. Spring中的ORM和Dao支持提供了与第三方持久层框架的良好整合,并简化了底层的数据库访问。
6. Spring的高度开放,并不会强制要求开发者完全依赖于Spring,可自由选择使用部分功能。

Spring分为六个模块,常用的有5个。
- Core
- AOP
- DAO(Jdbc、包含事务)
- ORM
- Web

环境搭建

1) 引入jar文件 (3.2版本) 【spring-core】

commons-logging-1.1.3.jar 【单独下载】
spring-beans-3.2.5.RELEASE.jar 【spring源码, bean节点管理】
spring-context-3.2.5.RELEASE.jar 【spring上下文类】
spring-core-3.2.5.RELEASE.jar 【IOC容器】
spring-expression-3.2.5.RELEASE.jar 【spring表达式】

注意:
使用的版本Spring3.2
在这个版本中,只有spring自身的核心功能,spring依赖的其他组件,需要单独下载。 例如:日志jar文件,就需要单独下载。
3.0版本之前包含组件自身和依赖的组件包、
3.0版本之后,依赖的组件包需要单独下载。

2) 新建applicationContext.xml , 源码中拷贝约束
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

</beans>        
3) 配置
<!-- 创建Dao实例 -->
<bean id="userDao" class="cn.ustb.dao.UserDao"></bean>

<!-- 创建Service实例 -->
<bean id="userService" class="cn.ustb.service.UserService">
    <property name="userDao" ref="userDao"></property>
</bean>

<!-- 创建Action实例 -->
<bean id="userAction" class="cn.ustb.action.UserAction">
    <property name="userService" ref="userService"></property>
</bean>
4) 测试
  1. 创建容器对象(加载applicationContext.xml配置文件)
    new ClassPathXMLApplication("applicationContext.xml");
  2. 获取对象
    getBean("name or id");
// 从IOC容器获取对象
@Test
public void testApp2() throws Exception {
    // 容器对象(加载applicationContext.xml配置文件)
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 获取对象
    UserAction userAction = (UserAction) ac.getBean("userAction");
    userAction.execute();
}

配置详解

<!-- 把对象加入IOC容器 -->

<!-- 
细节1:
    id 与   name:
        id 不能以数字开头,不能含有特殊符号, 不能有空格、逗号等;  id 不能重复!
        name 可以以数字开头,可以有特殊符合,如果name值重复,编译没有问题但运行报错!

<bean id="user" name="user2,user3 user4" class="cn.ustb.a_config.User"></bean>
<bean name="user5" class="cn.ustb.a_config.User"></bean>
<bean id="user6" class="cn.ustb.a_config.User"></bean>
<bean id="user6" class="cn.ustb.a_config.User"></bean>
-->

<!-- 细节2: (单例/多例)  -->
<!-- 
    scope="singleton"   默认表示单例!
           prototype    多例
    init-method=""      在创建完对象之后执行初始化方法
    destroy-method=""   在调用容器类的destroy()方法时候,对单例的对象有效!
    lazy-init="true"    延迟初始化 / 这个属性的设置只对单例有影响,对多例没有任何影响!
                        单例的对象默认是在创建容器的时候就创建所有单例的对象,如果希望在第一次访问的时候创建单例的对象,就设置延迟初始化
    Bean生命周期:
       bean在xml中配置,
          singleton  单例

            1) 创建对象
                 如果有配置延迟初始化,
                    lazy-init=true  如果单例的对象有配置延迟初始化, 在创建容器之后,在第一次从容器获取对象的时候
                                 创建单例的对象!
                如果没有配置或延迟初始化为默认值, 单例的对象会在创建容器的时候创建对象
            2) 执行初始化方法 , init-method配置的方法会执行
            3) 调用容器destroy() 方法时候,容器在销毁单例对象的实例的时候,会调用destroy-method对应的方法
               此时bean对象会被销毁!

          prototype  多例
             1) 每次在从容器获取对象的时候,都会创建新的对象
             2) 每次创建完对象后,就执行初始化方法
             3) java会回收不用资源(jvm gc)     
 -->
<bean id="user" 
    class="cn.ustb.a_config.User" 
    init-method="init" 
    destroy-method="destroy_" 
    lazy-init="false" 
    scope="prototype">
</bean>
创建对象的几种方式

创建对象的几种方式:
1) 调用无参数构造器
2) 调用有参数构造器
3) 工厂方法
* 静态方法
<bean id=”’ class=”” factory-method=””/>
* 非静态方法
<bean id=”factory” class=”..”>
<bean id=”” factory-bean=” factory” factory-method=”实例方法” />

4) 反射

<!--IOC容器, 创建对象 -->

<!-- 1) 调用无参数构造器 
<bean id="user1" class="cn.ustb.b_create_obj.User"></bean> -->

<!-- 2) 调用有参数构造器, 创建对象 -->
<!-- String str = new String("Jack"); -->
<bean id="str" class="java.lang.String">
    <constructor-arg value="Jack"></constructor-arg>
</bean>

<!-- 创建user对象,且赋值 -->
<!-- 
    value 当直接给属性值的时候使用value赋值
    ref   当引用的是IOC容器中的对象的时候,使用ref    
 -->
<bean id="user" class="cn.ustb.b_create_obj.User">
    <constructor-arg index="0" type="int" value="10000"></constructor-arg>
    <constructor-arg index="1" type="String" ref="str"></constructor-arg>

</bean>

<!--
    3) 工厂创建对象
        * 静态方法
        * 非静态方法
 -->

 <!-- * 工厂静态方法,创建对象 -->
 <!-- 
      class 指定工厂的类型;  
      factory-method: 工厂类的静态方法
  -->
 <bean id="user1" class="cn.ustb.b_create_obj.UserFactory" factory-method="getStaticInstace"></bean>


 <!-- * 非静态方法创建对象 -->
 <!-- 先创建工厂实例 -->
 <bean id="factory" class="cn.ustb.b_create_obj.UserFactory"></bean>
 <bean id="user" factory-bean="factory" factory-method="getInstace"></bean>

依赖注入(配置方式)

给对象属性赋值(Dependency Injection, 依赖注入),几种方式:

1) 构造函数赋值
<bean id="user1" class="cn.ustb.a_ioc.User" scope="prototype">
    <constructor-arg index="0" value="jake"></constructor-arg>
    <constructor-arg index="1" value="21221"></constructor-arg>
</bean>
2) set 方法注入值

普通字段赋值
+
集合属性 (list/map/property)

<!--IOC容器, 给对象属性赋值 -->
<bean id="user" class="cn.ustb.c_di.User">
    <property name="id" value="1000"></property>
    <property name="name" value="Jacky"></property>


    <!-- list 集合赋值 -->
    <property name="list">
        <list>
            <value>cn</value>
            <value>usa</value>
        </list>
    </property>
    <!-- map 集合赋值 -->
    <property name="map">
        <map>
            <entry key="cn" value="China"></entry>
            <entry key="usa" value="1234"></entry>
        </map>
    </property>
    <!-- Properties 对象赋值 -->
    <property name="prop">
        <props>
            <prop key="cn">China</prop>
            <prop key="usa">America</prop>
        </props>
    </property>
</bean>
3) 案例

Dao/service/action实例,处理依赖关系
1、常用的通过set方法注入
+
2、内部bean
+
3、p 名称空间增加约束:xmlns:p="http://www.springframework.org/schema/p"

<!-- 配置: 需要创建的对象、对象依赖关系处理 -->

<!-- 方式1:通过set方法注入,这种方式最常用!  -->
<bean id="userdao" class="cn.ustb.d_di2.UserDao"></bean>
<bean id="userService" class="cn.ustb.d_di2.UserService">
    <property name="userDao" ref="userdao"></property>
</bean>
<bean id="userAction" class="cn.ustb.d_di2.UserAction" scope="prototype">
    <property name="userService" ref="userService"></property>
</bean>



<!-- 方式2: 内部bean -->
<!-- 总结: 当创建的对象,不被容器其他地方引用的时候,可以这样写! 这样写不通用,内部对象只能用一次 -->
<!-- 这里,action如果是单例,内部bean默认就是单例;  action如果是多例,内部bean就是多例 -->
<bean id="userAction2" class="cn.ustb.d_di2.UserAction" scope="prototype">
    <property name="userService">
        <bean class="cn.ustb.d_di2.UserService">
            <property name="userDao">
                <bean class="cn.ustb.d_di2.UserDao"></bean>
            </property>
        </bean>
    </property>
</bean>


<!-- 方式3: p名称空间,给属性注入值  
    需要增加约束:xmlns:p="http://www.springframework.org/schema/p"
-->
<bean id="userDao" class="cn.ustb.d_di2.UserDao"></bean>
<bean id="userService" class="cn.ustb.d_di2.UserService" p:userDao-ref="userDao"></bean>
<bean id="userAction" class="cn.ustb.d_di2.UserAction" p:userService-ref="userService"></bean>
自动装配
<!-- 方式4:自动装配 (了解) -->
<!-- 
    a. default-autowire="byType"  配置到全局
        当前所有的bean都采用”根据类型自动装配“
    b. 配置到bean节点
        autowire="byName"  根据名称自动装配, 会去容器找指定名称的对象,注入到set方法的参数中!
        autowire="byType"  根据类型自动装配, 要确保改类型对应的对象在IOC容器中唯一,否则报错!

    总结:
        简化配置,但是维护麻烦!
 -->

<bean id="userDao" class="cn.ustb.e_autowire.UserDao" autowire="default"></bean>
<bean id="userService" class="cn.ustb.e_autowire.UserService"></bean>
<bean id="userAction" class="cn.ustb.e_autowire.UserAction"></bean>

依赖注入(注解方式)

注解汇总:

Class注解:
@Component 表示一个组件(类),把当前组件加入ioc容器,加入容器的组件的名称默认是类名第一个字母小写
@Component(“”) 指定加入ioc容器的组件类的类名

@Repository 标识是一个持久层的组件【DAO
@Service 标识是一个业务逻辑层的组件【Service
@Controller 标识是一个控制层的组件【Action

@Scope(“prototype”) 指定对象单例/多例【注解Class】

字段注解:
@Resource
1. 现根据字段名称(先id 再 name)查找。
2. 其次根据类型(Class)查找,如果该类型在ioc容器中有多个对象,报错。
3. 根据类型也没有找到对象,报错。

@Resource(name =“”) 会根据指定的名称去容器找对象自动注入

需要注意的一点细节:
  • Component+Resource足够了,只不过为了详细区分,将Component分出了持久层Repository、逻辑层Service、控制层Controller
  • Action因为是多例的,需要在Class上方注解@Scope(“prototype”)
  • Resource需要注解在setter的上方。
  • 最最最重要的,需要在bean.xml中配置开启注解扫描,即
    <context:component-scan base-package="cn.ustb.b_anno"></context:component-scan>
  • Resource无参的注解,现根据字段名查找,再根据类查找。
注解的示例

bean.xml:

<context:component-scan base-package="cn.ustb.b_anno"></context:component-scan>

Java:


@Component//可以带参@Component(name="userAction"),无参则默认类名首字母小写为组件名
@Scope("prototype")//声明多例,默认单例
public class UserAction {
    private UserService userService;

    public UserService getUserService() {
        return userService;
    }

    /*
     * Resurce要注解在setter方法之上
     */
    //@Resource(name="userService") //带参版
    @Resource //先根据userService的字段名在容器中查找,再根据class类型查找(若同一类型存在多个实例抛出异常),再找不到也抛出异常
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void save(){
        System.out.println("userAction save");
        userService.save();
    }
}
配置方式和注解方式的对比:

配置:便于维护,但是配置较多较繁琐。
注解:开发方便,几个字母就能搞定,简化配置。但是不利于后期维护,若修改对象创建关系需要修改源代码。


Spring与Struts2的整合

Spring与Struts2整合的关键点:将Action的创建交给Spring的IOC容器。因此需要引入Spring-Web的包。

struts2-spring-plugin-2.3.4.1.jar 【struts源码】 添加了struts2对spring的支持
spring-web-3.2.5.RELEASE.jar 【spring源码】添加了spring对struts的支持

整合的完整步骤:

1、引入jar包
  • Struts核心jar
  • Spring
    • Core 核心 (5个)
    • Web 对web支持 (2个)
2、配置文件
  • bean.xml 【spring的配置文件,基本没什么变化。】
  • struts.xml【struts的配置文件,Class不需要写全类名,和bean的id保持一致,action实例可以从ioc容器获取。】
  • web.xml【配置spring的核心过滤器(监听器),启动时创建IOC容器】
    • struts2核心过滤器
    • spring配置文件读取
    • spring监听器,启动时候,配置加载springIOC容器

web.xml配置:

<!-- 配置struts核心过滤器 -->
<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<!-- 配合SPring的核心过滤器,在启动服务器时加载spring配置,创建ioc容器 -->
<!-- 配置文件的位置 -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:bean-USER.xml</param-value>
</context-param>
<!-- 配置启动监听器,该类在spring-web包中 -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

将action的创建交给IOC容器。因此struts.xml中的class属性值为对应action在IOC中的id,而不再是类名。

需要注意的是,如果用到了注解,需要在bean.xml开启注解扫描

3、编写POJO、Action类。

需要再次强调的是,如果需要用到属性注入,在Action中的对象必须要new一下,除非在Spring中已经生成了该bean。

整合中出现过的问题:
1、action中的model注入部分为null

解决:model的不仅要设置setter方法,还要设置getter。并且要在Action中new一下。

2、action实例不了的原因,出现了nullpointer

原因:用到了注解,却忘记了在bean.xml中添加注解扫描。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值