Spring(2)

Spring day02

1. 注入补充【了解】

1.1 注入null值

需要显式的为一个属性赋null值时,需要使用null子标签。

<bean id="addr" class="com.jsd.entity.Address">
    <constructor-arg value="硅谷"/>
    <constructor-arg><null></null></constructor-arg>
</bean>

1.2 内部bean

当一个bean只为另外一个bean使用时,可以写成内部bean的形式。
示例:

<bean id="p" class="com.jsd.entity.Person">
        <property name="personId" value="1"/>
        <property name="personName" value="xiaohei"/>
        <property name="addr" ref="addr"/>
</bean>
<bean id="addr" class="com.jsd.entity.Address">
        <property name="city" value="郑州"/>
        <property name="street" value="文化路"/>
</bean>

内部bean:

<bean id="p" class="com.jsd.entity.Person">
        <property name="personId" value="1"/>
        <property name="personName" value="xiaohei"/>
        <property name="addr">
            <bean class="com.jsd.entity.Address">
                <property name="city" value="郑州"/>
                <property name="street" value="文化路"/>
            </bean>
        </property>
    </bean>

2. FactoryBean技术(创建复杂对象)

在这里插入图片描述

使用FactoryBean技术创建复杂对象。

FactoryBean的使用步骤:

准备工作:pom.xml导入mysql-connector-java依赖

 <dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <version>5.1.48</version>
</dependency>
  1. 定义一个用于创建复杂对象的类,必须实现FactoryBean接口
   public class ConnectionFactoryBean implements FactoryBean<Connection> {
       @Override
       // 用于返回 创建的复杂对象
       public Connection getObject() throws Exception {
           Class.forName("com.mysql.jdbc.Driver");
           String url = "jdbc:mysql://localhost:3306/shuju?useUnicode=true&characterEncoding=utf-8";
           String username = "root";
           String password = "root";
   
           return DriverManager.getConnection(url,username,password);
       }
   
       @Override
       //返回 复杂对象的类型(类对象)
       public Class<?> getObjectType() {
           return Connection.class;
       }
   
       @Override
       //决定复杂对象是不是单例
       public boolean isSingleton() {
           return false;
       }
   }
  1. 配置上一步定义的FactoryBean
   <!--getBean("conn")获取不是ConnectionFactoryBean类型的对象,获取getObject()返回的复杂对象 -->
   <bean id="conn" class="com.jsd.factory.ConnectionFactoryBean"/>

注意:

  1. 复杂对象的单例控制,由isSingleton()方法返回值决定
  2. 通过getBean("&id属性"),可以获取自定义的FactoryBean对象

3. Spring的IOC和DI

IOC(Inversion of Control)控制反转、反转控制

DI(Dependency Injection)依赖注入

IOC:属性的赋值权力从代码反转到Spring框架中。

DI:Spring通过依赖注入完成属性赋值。

控制:对于类中依赖(属性)的赋值的控制权。

传统的正向控制:
请添加图片描述
问题:类和类之间强耦合。
请添加图片描述

IOC和DI对同一件事,不同角度的描述。IOC更加偏重思想,DI更加偏重于实现手段。

IOC:属性的赋值权力从代码反转到Spring框架中。

DI:Spring通过依赖注入完成属性赋值。

4 Spring Bean的生命周期(概念重点)

对象的生命周期:对象从生到死的过程。

Spring工厂中Bean的生命周期并不像想象的那么简单,Spring对工厂中的Bean的生命周期进行了细致的划分,并允许开发者通过编码或配置的方式定制Bean在生命周期的各个阶段的操作。

  1. 初始化阶段:在对象创建后,进行一些初始化操作,比如对属性值的检查
  2. 销毁阶段:在回收对象之前,执行一些销毁操作,比如资源的释放

4.1 初始化阶段

在Spring工厂创建对象并为属性赋值后就进入到了Bean的初始化阶段,Spring会自动调用Bean的初始化方法。在初始化方法中可以做一些初始化操作,比如对刚创建的对象进行检查操作。而初始化方法可以由开发者实现接口或者配置的方式定义。

实现InitializingBean接口

public class XxxServiceImpl implements XxxService, InitializingBean {
    private XxxDao xxxDao;

    public XxxServiceImpl() {
        System.out.println("XxxServiceImpl()");
    }

    public XxxDao getXxxDao() {
        return xxxDao;
    }

    public void setXxxDao(XxxDao xxxDao) {
        System.out.println("XxxServiceImpl.setXxxDao");
        this.xxxDao = xxxDao;
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("XxxServiceImpl.afterPropertiesSet");
        if(xxxDao == null){
            throw new RuntimeException("xxxDao must not be null");
        }
    }
    ...
}

通过Bean标签的init-method属性

public class XxxServiceImpl implements XxxService, InitializingBean {
    private XxxDao xxxDao;

    public XxxServiceImpl() {
        System.out.println("XxxServiceImpl()");
    }

    public XxxDao getXxxDao() {
        return xxxDao;
    }

    public void setXxxDao(XxxDao xxxDao) {
        System.out.println("XxxServiceImpl.setXxxDao");
        this.xxxDao = xxxDao;
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("XxxServiceImpl.afterPropertiesSet");
        if(xxxDao == null){
            throw new RuntimeException("xxxDao must not be null");
        }
    }

    private void initMethod(){
        System.out.println("XxxServiceImpl.init");
    }
    ...
}
<bean id="xxxDao" class="com.jsd.dao.impl.XxxDaoImpl"/>
<bean id="xxxService" class="com.jsd.service.impl.XxxServiceImpl" init-method="initMethod">
    <property name="xxxDao" ref="xxxDao"/>
</bean>

InitializingBean接口和init-method属性的应用场景的区别:

接口方式:开发简单,一次实现,该类型的所有Bean配置都自动生效。

init-method属性:对于旧代码而言无需修改,即可完成对旧代码的配置。

实战中,二者一般不会同时出现,如果同时出现执行顺序:先接口中的方法,后init-method属性配置的方法。

4.2 销毁阶段

在关闭Spring工厂时,Spring会销毁其创建的对象,此时就进入到了Bean的销毁阶段。在此阶段,Spring会自动调用Bean的销毁方法,在对象销毁前执行一些操作,比如释放资源。

实现DisposableBean接口

public class XxxServiceImpl implements XxxService, InitializingBean, DisposableBean{
    ...
     @Override
    public void destroy() throws Exception {
        System.out.println("XxxServiceImpl.destroy");
    }
}

@Test
public void testInitializingBean(){
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    ctx.close();
}

通过Bean标签的destroy-method属性

public class XxxServiceImpl implements XxxService, InitializingBean, DisposableBean{    ...     @Override    public void destroy() throws Exception {        System.out.println("XxxServiceImpl.destroy");    }        public void destroyMethod(){        System.out.println("XxxServiceImpl.destroyMethod");    }}
<bean id="xxxService" class="com.jsd.service.impl.XxxServiceImpl" init-method="initMethod" destroy-method="destroyMethod">    <property name="xxxDao" ref="xxxDao"/></bean>

实战中,二者一般不会同时出现,如果同时出现执行顺序:先接口中的方法,后destroy-method属性配置的方法。

注意:Spring创建的Bean如果是多例,那么销毁阶段对其不起作用。

5 BeanPostProcessor(后置Bean处理)

BeanPostProcessor可以对Spring工厂中所有的Bean实例化后,对Bean对象再次加工处理。

编码

User.java

package com.jinshida.entity;

import java.io.Serializable;

public class User implements Serializable {
    private Integer userId;
    private String username;
    private String password;

    public User() {
    }

    public User(Integer userId, String username, String password) {
        this.userId = userId;
        this.username = username;
        this.password = password;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    

    @Override
    public String toString() {
        return "User{" +
                "userId=" + userId +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

MyBeanPostProcessor.java

public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override    //在初始化阶段前调用    
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("MyBeanPostProcessor.postProcessBeforeInitialization");
        if (bean.getClass() == User.class) {
            User user = (User) bean;
            user.setPassword("654321");
        }
        return bean;
    }

    @Override    //在初始化阶段后调用    
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("MyBeanPostProcessor.postProcessAfterInitialization");
        return bean;
    }
}

配置

<bean id="u" class="com.jsd.entity.User" init-method="initMethod">
        <property name="userId" value="1"/>
        <property name="username" value="xiaohei"/>
        <property name="password" value="123456"/>
    </bean>
    <bean class="com.jsd.factory.MyBeanPostProcessor"/>

请添加图片描述

BeanPostProcessor可以对Spring中配置的所有Bean进行统一处理,并且Spring中可以配置多个BeanPostProcessor。

6 Spring配置文件的拆分

6.1 applicationContext.xml的拆分

一个复杂的企业应用会拆分成多个模块,不同模块中有各自的spring配置,最终还需要聚合在一起。

<import resource="classpath:datasource/a.xml"/>

classpath:JVM寻找类的起始路径,可以认为java、resources都是classpath。

6.2 Spring配置文件的xsd(了解)

XML的格式约束文件有2种:DTD(Document Type Definition)和XSD(XML Schema Definition)。XSD和DTD一样用来约束配置文件,DTD编写简单,XSD功能强大。

一般地,简单的配置文件用dtd约束(如Struts2的配置文件,MyBatis的配置文件),复杂的配置文件使用xsd约束(如Spring)。

  1. xsd的基本使用
    请添加图片描述

  2. 在一个配置文件中使用多个xsd

    Spring不同的模块定义了不同的xsd文件,在一个Spring配置文件中使用多个模块的功能,也就要在配置文件中使用多个xsd。

请添加图片描述
使用步骤:

  1. 在跟标签中添加xmlns:前缀=“其它xsd的命名空间”
  2. 在xsi:schemaLocation=“添加路径对”
  3. 使用其它xsd中定义的标签需要添加前缀:

示例:
请添加图片描述

6.3 Spring 配置文件properties的拆分

程序中关于数据库的参数配置,一般都抽取到jdbc.properties文件中。Spring的applicationContext.xml中关于数据库的配置也一样要抽取。

  1. 将数据库参数抽取到jdbc.properties中

    driverClassName=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/jsd?useUnicode=true&characterEncoding=utf-8user=rootpassword=root
    
  2. 在Spring的配置文件中读取jdbc.properties

    <!-- 读取配置文件 使用context.xsd定义property-placeholder标签读取jdbc.properties文件--><context:property-placeholder location="classpath:jdbc.properties"/>
    
  3. 在需要使用参数的地方,通过${参数名}获取参数值

    <bean id="conn" class="com.jsd.factory.ConnectionFactoryBean" >    <property name="url" value="${url}"/>    <property name="driverClassName" value="${driverClassName}"/>    <property name="username" value="${user}"/>    <property name="password" value="${password}"/></bean>
    

注意:${username}会优先读取操作系统的用户名,jdbc.properties中必须改名

7 Spring整合Struts2

准备工作:创建好一个可运行的struts2项目。

Struts2+MyBatis项目开发步骤:

  1. 搭建开发环境

    1. 新建web项目

    2. 导入依赖

      数据库驱动依赖

      mybatis依赖

      servlet+jsp+jstl依赖

      struts2依赖

    3. 配置文件+工具类

      jdbc.properties

      log4j.properties

      mybatis-config.xml

      mapper.xml

      struts.xml

      MyBatisUtils.java

    4. 配置文件初始化

      mybatis-config.xml

      web.xml:开启struts2框架

  2. 建表

  3. 实体类

  4. dao

  5. service

  6. test

  7. Action+jsp

  8. 集成测试

7.1 整合效果

请添加图片描述

Spring整合Struts2的效果:

在Spring配置文件中配置Service和Action的Bean,其中Action的bean的scope要配置为"prototype",由Spring工厂创建Struts2需要的Action和Service.

struts.xml中action的class属性不再配置全类名(也就是不再由Struts2框架通过反射创建Action),而是配置action的id(使用Spring创建的Action对象)

7.2 实战

请添加图片描述

导入spring-webstruts2-spring-plugin依赖

<!-- spring对javaweb开发的支持 版本和spring-context保持一致--><dependency>    <groupId>org.springframework</groupId>    <artifactId>spring-web</artifactId>    <version>4.3.26.RELEASE</version></dependency><!-- 负责黏合Spring和Struts2框架 --><dependency>    <groupId>org.apache.struts</groupId>    <artifactId>struts2-spring-plugin</artifactId>    <version>2.3.16.3</version></dependency>
  1. tomcat启动应用时,自动创建Spring工厂

    web.xml

    <context-param>    <param-name>contextConfigLocation</param-name>    <param-value>classpath:applicationContext.xml</param-value></context-param><listener>    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
    
  2. Struts2从Spring工厂中获取Action

    applicationContext.xml

    <bean id="userService" class="com.jsd.service.impl.UserServiceImpl"/><bean id="userAction" class="com.jsd.action.UserAction" scope="prototype">    <property name="userService" ref="userService"/></bean>
    

    struts.xml

    <package name="day02" extends="struts-default" namespace="/day02">    <!-- 		class配置的是spring配置文件中Action的id	-->    <action name="showAllUsers" class="userAction" method="showAllUsers">        <result name="success">/showAllUsers.jsp</result>    </action></package>
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值