其他分享
首页 > 其他分享> > 41_Spring01

41_Spring01

作者:互联网

学习目标

一、简介

1. 什么是Spring

2. Spring的发展历程

3. Spring的优势

4. Spring的体系结构

二、工厂模式解耦(理解)

1. 耦合性问题

1.1 耦合性问题现象

1.2 解耦的思路

2. 使用工厂模式解耦

需求描述

需求分析

1563205038328

需求实现

  1. 创建项目,导入依赖

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
    
  2. dao层代码

    • 接口
    package com.itheima.dao;
    
    public interface UserDao {
        void add();
    }
    
    
    • 实现类
    package com.itheima.dao.impl;
    
    import com.itheima.dao.UserDao;
    
    public class UserDaoImpl implements UserDao {
        public void add() {
            System.out.println("调用了UserDaoImpl的add方法~!");
        }
    }
    
    
  3. service层代码

    • 接口
    package com.itheima.service;
    
    public interface UserService {
        void add() throws Exception;
    }
    
    
    • 实现类
    package com.itheima.service.impl;
    
    import com.itheima.dao.UserDao;
    import com.itheima.dao.impl.UserDaoImpl;
    import com.itheima.factory.BeanFactory;
    import com.itheima.service.UserService;
    
    public class UserServiceImpl implements UserService {
        public void add() throws Exception {
            System.out.println("调用了UserServiceImpl的add方法~!");
    
            //以前的写法:
            /*UserDao userDao = new UserDao();
            UserDao userDao = new UserDaoImpl();
            userDao.add();*/
    
            //现在的写法:
            UserDao userDao = (UserDao) BeanFactory.getBean("ud");
            userDao.add();
        }
    }
    
    
  4. 配置文件beans.properties

在resource下面创建 beans.properties

us=com.itheima.service.impl.UserServiceImpl
ud=com.itheima.dao.impl.UserDaoImpl
  1. 工厂类BeanFactory
package com.itheima.factory;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;

/*
    这是专门用来创建对象的工厂类
        1. 使用静态代码块来读取beans.properties

        2. 提供一个静态方法,供外面的人调用获取对象
 */
public class BeanFactory {
    static Map<String , String> map = new HashMap<String , String>();

    //1. 在这里读取beans.properties文件
    static{

        //1. 读取外部的properties文件,只要写名字即可
        ResourceBundle resourceBundle = ResourceBundle.getBundle("beans");

        //2. 读取里面的内容
        Enumeration<String> keys = resourceBundle.getKeys();

        //3. 遍历每一个key value
        while(keys.hasMoreElements()){

            //4. 取出每一个key
            String key = keys.nextElement();

            //5. 得到每一个value
            String value = resourceBundle.getString(key);

            //6. 把key和value保存到map集合
            map.put(key , value );
        }

    }

    /**
     * 提供对象
     * @param name 名称
     * @return
     */
    public static Object getBean(String name) throws Exception {

        //1. 从map集合里面获取全路径
        String className = map.get(name);

        //2. 判定
        if(className != null){
            return Class.forName(className).newInstance();
        }

        return null;
    }
}

package com.itheima.test;

import com.itheima.factory.BeanFactory;
import com.itheima.service.UserService;
import org.junit.Test;

public class TestUserServiceImpl {

    @Test
    public void testAdd() throws Exception {

        //1. 问工厂要对象
       UserService us = (UserService) BeanFactory.getBean("us");
       us.add();
    }
}

小结

  1. 首先得有接口和实现类 : UserDao 和 UserDaoImpl , UserService 和 UserServiceImpl
  2. 使用properties配置文件来记录 ,别名和实现类的全路径
  3. 定义一个工厂类
    1. 在静态代码块里面读取配置文件,使用map集合来存映射关系
    2. 定义一个静态方法,只要有人来获取实例,那么就从map集合里面取出来全路径
    3. 使用反射技术来构建实例返回。

三、控制反转IOC【重点】

控制反转,把对象的创建工作交给框架(工厂 Spring),我们不需要自己去new这个对象,只管问工厂要。由原来的主动创建对象,变成自己被动接收 框架创建的对象。

IOC是Spring的核心之一,作用就是为了解耦,降低程序,代码间的耦合度。

1. 快速入门【重点】

需求描述

开发步骤

  1. 创建Maven项目,导入依赖坐标:Spring的依赖坐标
  2. 编写dao接口UserDao及实现UserDaoImpl
  3. 创建Spring核心配置文件,并配置UserDaoImpl (作用类似bean.properties)
  4. 测试:使用Spring的API,获取Bean实例对象

需求实现

1. 创建Maven项目,导入依赖坐标
 <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
2. 编写dao接口UserDao及实现UserDaoImpl
package com.itheima.dao;

public interface UserDao {
    void add();
}

package com.itheima.dao.impl;

import com.itheima.dao.UserDao;

public class UserDaoImpl implements UserDao {
    
   
    public  void add() {
        System.out.println("调用了UserDaoImpl的add方法~!~");
    }
}
3. 创建Spring核心配置文件,并配置UserDaoImpl

这个步骤的作用就是告诉spring,要创建哪个类的对象,并且给这个类起一个别名,方便以后我们问spring要对象。它的作用等于我们前面写的beans.properties

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
        在这里告诉spring要创建哪个类的对象,并且给这个对象起一个别名

        bean标签:
            作用: 用来托管(类)对象
            属性:
                id: 唯一标识,不能出现重复!
                class: 托管类的全路径
     -->
    <bean id="ud"  class="com.itheima.dao.impl.UserDaoImpl" />
</beans>
4. 使用Spring的API,获取Bean实例对象
package com.itheima.test;

import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUserDao {


    @Test
    public void testAdd(){

        //1. 创建工厂
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        //2. 问工厂要对象
        UserDao userDao = (UserDao) context.getBean("ud");

        //3. 调用方法
        userDao.add();
    }

}

小结

  1. 首先编写UserDao 和 UserDaoImpl
  2. 在pom.xml里面添加依赖
  3. 在resources下面,创建一个xml文件,名字随意。不要手动创建文件的方式。要选择xml配置文件的方式
  4. 在xml文件里面登记|注册|托管实现类
  5. 问工厂要实例

2. 配置文件详解【了解】

1. bean标签的基本配置

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>
  1. 介绍

    • 用于配置:把对象交给Spring进行控制 , spring会帮助我们创建对象。

    • 默认情况下,Spring是调用类的无参构造来创建对象的;如果没有无参构造,则不能创建成功

  2. 基本属性

    • id:唯一标识
    • class:bean的全限定类名

    了解:bean的id和name的区别

    1. 一个bean只能有一个id;一个bean可以有多个name
    2. bean的name值:多个name之间以, ; 空格 隔开,第1个name作为id,其它作为别名

2. bean标签的作用范围配置

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" scope="singleton"></bean>
取值 说明
singleton 默认,表示单例的,一个Spring容器里,只有一个该bean对象
prototype 多例的,一个Spring容器里,有多个该bean对象
request web项目里,Spring创建的bean对象将放到request域中:一次请求期间有效
session web项目里,Spring创建的bean对象将放到session域中:一次会话期间有效
globalSession web项目里,应用在Portlet环境/集群环境;如果没有Portlet/集群环境,那么globalSession相当于session(新版本中已删除)

3. bean生命周期相关方法的配置【了解】

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" 
      init-method="" destroy-method=""></bean>
package com.itheima.dao.impl;

import com.itheima.dao.UserDao;

public class UserDaoImpl implements UserDao {
    public UserDaoImpl(){
        System.out.println("创建对象了额~!!~");
    }

    public void add() {
        System.out.println("调用了UserDaoImpl的add方法~!");
    }

    //创建好对象的时候调用这个方法
    public  void init(){
        System.out.println("调用了UserDaoImpl的init方法~!");

    }

    //销毁对象的时候调用这个方法
    public  void destroy(){
        System.out.println("调用了UserDaoImpl的destroy方法~!");

    }
}

package com.itheima.test;

import com.itheima.dao.UserDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUserDaoImpl {

    //测试单例多例
    @Test
    public void testAdd2(){

        //1. 创建工厂
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        //2. 问工厂要对象
        UserDao userDao = (UserDao) context.getBean("ud");

        //3. 关闭工厂!
        context.close();
    }
}
    <!--
        在这里告诉spring要创建哪个类的对象,并且给这个对象起一个别名

        bean标签:
            作用: 用来托管(类)对象
            属性:
                id: 唯一标识,不能出现重复!
                class: 托管类的全路径
                name : 用于给对象起别名,标识以后可以用这个别名来找到对象
                     可以写多个值,使用 分号 , 逗号, 空格 ,tab 来间隔!【一般不用它!】

                scope: 用来设置创建的对象是单例的还是多例
                    singleton: 单例,默认是单例! 【大多数情况下,使用的都是单例对象】
                        何时创建:创建工厂的时候创建了对象
                        何时销毁:销毁工厂的时候,销毁对象
                    prototype: 多例
                        何时创建:问工厂要对象的时候,才创建对象
                        何时销毁:长时间不用之后,就由GC回收对象!
                init-method:
                    当对象初始化的时候,调用这个方法
                destroy-method:
                    当对象销毁的时候,调用这个方法
            spring创建类的对象,默认会执行该类的无参构造方法!

     -->
    <bean id="ud"  class="com.itheima.dao.impl.UserDaoImpl" scope="prototype" init-method="init" destroy-method="destroy"/>


4. bean实例化的三种方式【了解】

我们通常都是问Spring要对象,那么Spring怎么整出来对象的呢?有三种方式。算起来就只有两种办法创建对象:

  1. 由Spring来创建对象
  2. 由我们自己来创建对象,然后spring来拿我们的对象给需要的人。
1. 无参构造方法实例化 【spring创建对象】

UserDaoImpl 是由Spring创建的。

<bean id="ud" class="com.itheima.dao.impl.UserDaoImpl"></bean>
2. 工厂静态方法实例化

UserDaoImpl的由我们写好的StaticFactory的类来创建 , Spring工厂没干活,只是问我们的工厂要对象而已。

package com.itheima.factory;

import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;

/*
    使用工厂的静态方法来创建对象
 */
public class StaticFactory {

    /**
     * 创建UserDaoImpl的对象
     * @return
     */
    public static UserDao getBean(){
        System.out.println("来问StaticFactory要对象了~");
        return new UserDaoImpl();
    }
}

    <!--
        使用工厂的静态方法来创建对象
            1. spring工厂并不会去创建UserDaoImpl的对象。
            2. 当有方法拿着ud02来问spring的工厂要对象的时候,spring的工厂会
                找StaticFactory的getBean方法得到对象
            3. 然后把这个对象返回给我们的方法
     -->
   <bean id="ud02" class="com.itheima.factory.StaticFactory" factory-method="getBean"/>

3. 工厂非静态方法实例化

UserDaoImpl的由我们写好的InstanceFactory的类来创建 ,, Spring工厂没干活,只是问我们的工厂要对象而已。

package com.itheima.factory;

import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;

public class InstanceFactory {
    /**
     * 创建UserDaoImpl的对象
     * @return
     */
    public  UserDao getBean(){
        System.out.println("来问InstanceFactory要对象了~");
        return new UserDaoImpl();
    }

}

    <!--
        使用工厂的非静态方法来创建对象:
            1. spring的工厂并不会去创建UserDaoImpl的对象。
            2. 它创建了我们工厂的对象
            3. 当有方法拿着ud03来问spring的工厂要对象的时候,spring会拿着instanceFactory去找到工厂对象
                (这个工厂对象是由spring创建出来的),然后调用getBean方法,返回我们创建好的UserDaoImpl对象
      -->
    <bean id="instanceFactory" class="com.itheima.factory.InstanceFactory"/>
    <bean id="ud03" factory-bean="instanceFactory" factory-method="getBean"/>

  1. Spring工厂创建实例有三种方式: 默认的无参构造方式 | 静态工厂方式 | 实例工厂方式

  2. 只有无参构造的那种方式是spring创建对象,其他两种都是由我们自己来创建对象

  3. 我们使用spring的IOC ,目的就是为了把对象的创建工作交给Spring,后面这种工厂的方式,反而是我们来创建对象,所以一般不用这两种。

  4. 既然如此,都不怎么用后面得的两种方式了,为什么spring还要提供这两种入口呢?

    这个其实就是为了兼容, 就是为了兼容以前的旧项目,有的旧项目50年前的旧项目,那个没有spring,但是那个时候已经使用了工厂来创建实例了。

3. IOC小结

  1. IOC是什么? 控制反转,把对象的创建工作交给spring的工厂完成,只管问spring要对象即可
  2. 在applicationContext.xml里面注册。
  3. 默认创建的实例是单例,如果想要多例,需要配合scope属性,设置成prototype

四、依赖注入DI【重点】

托管类里面有什么属性需要完成赋值工作,把这个赋值的工作交给spring来做。由spring把属性需要用到的值赋值(注入)进来就称之为依赖注入。

我们通过Ioc把bean对象交给了Spring容器进行管理,降低了耦合性。

但是耦合性不能彻底消除,bean之间还是有一些依赖关系。比如:业务层userService要依赖于持久层userDao。

这样的依赖关系,可以交给Spring帮我们进行依赖的注入,而不用我们自己注入依赖

1. 快速入门 【重点】

需求描述

开发步骤

  1. 创建Maven项目,导入依赖坐标
  2. 编写dao层UserDaoUserDaoImpl、service层UserServiceUserServiceImpl
  3. 创建Spring核心配置文件,并配置bean和依赖注入
  4. 使用Spring的API,测试

需求实现

1. 创建Maven项目,导入依赖
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
</dependencies>
2. 编写dao层和service层代码
package com.itheima.dao;

public interface UserDao {
    void add();
}

package com.itheima.dao.impl;

import com.itheima.dao.UserDao;

public class UserDaoImpl implements UserDao {
    public void add() {
        System.out.println("调用了UserDaoImpl的add方法~!");
    }
}

package com.itheima.service;

public interface UserService {

    void add();
}
package com.itheima.service.impl;

import com.itheima.dao.UserDao;
import com.itheima.service.UserService;


/*
    需求: service里面的add方法要调用dao的add方法
    分析:
        1. 要想调用dao的add方法,必须持有UserDaoImpl的对象。
        2. 要想拥有UserDaoImpl的对象有两种办法:
            2.1 自己创建 ,自己new   【以前的做法】
                UserDao userDao  = new UserDaoImpl();
                userDao.add();
            2.2 让spring把userDaoImpl的对象给注入进来,注入给UserServiceImpl!【采用这种方式】
     步骤:
        1. 在UserServiceImpl里面定义属性 :  private UserDao userDao;
        2. 提供这个属性的set方法!
        3. 把UserServiceImpl和UserDaoImpl这两个类都交给spring托管。
        4. 在xml里面配置,告诉spring要把UserDao的对象注入到UserServiceImpl里面的这个属性 userDao身上!

 */

public class UserServiceImpl implements UserService {

    //1. 定义属性
    private UserDao userDao;

    //2. 提供set方法
    public void setUserDao(UserDao userDao) {
        System.out.println("来调用Set方法了·~");
        this.userDao = userDao;
    }

    public void add() {
        System.out.println("调用了UserServiceImpl的add方法~!");
        userDao.add();
    }
}

3. 创建Spring核心配置文件,并配置bean和依赖注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--1. 把UserDaoImpl交给spring管理-->
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>

    <!--2. 把UserServiceImpl交给spring管理-->
    <bean id="us" class="com.itheima.service.impl.UserServiceImpl">
        <!--告诉spring,把id名字叫做ud的对象,赋值给UserServiceImpl里面的userDao属性-->
        <property name="userDao" ref="userDao"/>
    </bean>

</beans>
4. 使用Spring的API,测试
package com.itheima.test;

import com.itheima.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUserServiceImpl {

    @Test
    public void testAdd(){

        //1. 创建工厂
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        //2. 问工厂要对象
        UserService us = (UserService) context.getBean("us");

        //3. 调用方法
        us.add();

    }

}

小结

  1. 有接口,有实现类

    1. 给属性提供set方法
    2. 在托管|登记类的时候,要添加property标签。如果注入的是对象,那么要使用ref属性,如果注入的是普通的数据,那么要使用value属性。

2. 三种常见注入方式

1. set方法注入(最常用)

1) 介绍

在类中提供需要注入的成员(依赖项)的set方法,在配置文件中注入属性的值

<bean id="" class="">
	<property name="属性名" value="属性值"></property>
    <property name="属性名" ref="bean的id"></property>
</bean>
2) 示例
package com.itheima.service.impl;

import com.itheima.dao.UserDao;
import com.itheima.service.UserService;


/*
    三种注入方式之一:  set方法
    要求:一定要提供属性的set方法!

 */

public class UserServiceImpl01 implements UserService {

    private String address;
    private UserDao userDao;

    public void setAddress(String address) {
        this.address = address;
    }
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void add() {
        System.out.println("调用了UserServiceImpl01的add方法~!"+address);
        userDao.add();
    }
}


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--1. 把UserDaoImpl交给spring管理-->
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>

    <!--
        2. 把UserServiceImpl01交给spring管理
            2.1 采用set方法完成属性的注入工作。
                property :  用来告诉spring,有哪些属性要赋值,代码里面一定要提供set方法
                    name :属性名
                    ref : 注入值,针对的是对象类型属性
                    value : 注入值,针对的是普通的属性(基本数据类型 &  字符串)
     -->
    <bean id="us" class="com.itheima.service.impl.UserServiceImpl01">
        <property name="userDao" ref="userDao"/>
        <property name="address" value="深圳"/>
    </bean>

</beans>

2. 构造方法注入

1) 介绍

在类中提供构造方法,构造方法的每个参数就是一个依赖项,通过构造方法给依赖项注入值。

<bean id="" class="">
	<constructor-arg name="构造参数名称" value="构造参数的值"></constructor-arg>
    <constructor-arg name="构造参数名称" ref="bean的id"></constructor-arg>
</bean>
2) 示例
package com.itheima.service.impl;

import com.itheima.dao.UserDao;
import com.itheima.service.UserService;


/*
    三种注入方式之一:  有参构造
    要求:一定要提供有参构造方法!

 */

public class UserServiceImpl02 implements UserService {

    private String address;
    private UserDao userDao;

    public UserServiceImpl02(String address, UserDao userDao) {
        this.address = address;
        this.userDao = userDao;
    }

    public void add() {
        System.out.println("调用了UserServiceImpl02的add方法~!"+address);
        userDao.add();
    }
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--1. 把UserDaoImpl交给spring管理-->
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>

    <!--
        2. 把UserServiceImpl02交给spring管理
            constructor-arg : 用于匹配有参构造函数,
                name: 参数名
                value : 给参数赋值,针对的是普通的参数(基本类型 &  字符串)
                ref : 给参数赋值, 针对的是对象的参数
     -->
    <bean id="us" class="com.itheima.service.impl.UserServiceImpl02">
        <constructor-arg name="address" value="深圳" />
        <constructor-arg name="userDao" ref="userDao"/>
    </bean>

</beans>

3. p名称空间注入

1) 介绍

p名称空间注入,本质仍然是set方法注入

在xml中引入p名称空间的约束

然后通过p:属性名称=""来注入简单数据、使用p:属性名称-ref=""注入其它bean对象,它的本质仍然是set方法注入

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="" class="" p:属性名="简单值" p:属性名-ref="bean的id"></bean>
    
</beans>
2) 示例
package com.itheima.service.impl;

import com.itheima.dao.UserDao;
import com.itheima.service.UserService;


/*
    三种注入方式之一:  p名称空间
    要求:一定要提供属性的set方法!

 */

public class UserServiceImpl03 implements UserService {

    private String address;
    private UserDao userDao;

    public void setAddress(String address) {
        this.address = address;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void add() {
        System.out.println("调用了UserServiceImpl03的add方法~!"+address);
        userDao.add();
    }
}

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--1. 把UserDaoImpl交给spring管理-->
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>

    <!--
        2. 把UserServiceImpl03交给spring管理

     -->
    <bean id="us" class="com.itheima.service.impl.UserServiceImpl03" p:address="中粮商务公园" p:userDao-ref="userDao"/>

</beans>

小结

  1. 注入方式有三种,set方法 ,构造方法注入,p名称空间
  2. 最常用的是set方法。
  3. 以后如果使用注解了,方法也不需要写了。

3. 注入集合数据

介绍

示例

代码
package com.itheima.service.impl;

import com.itheima.dao.UserDao;
import com.itheima.service.UserService;

import java.util.*;


/*
    注入集合数据: 数组、list、set、map、properties

 */

public class UserServiceImpl04 implements UserService {

    private String [] array;
    private List<String> list;
    private Set<String> set;
    private Map<String , String> map;
    private Properties properties;

    public void setArray(String[] array) {
        this.array = array;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    public void add() {
        System.out.println("调用了UserServiceImpl04的add方法~!");
        System.out.println("array="+Arrays.toString(array));
        System.out.println("list = " + list);
        System.out.println("set = " + set);
        System.out.println("map = " + map);
        System.out.println("properties = " + properties);
    }
}

配置注入数据
<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--1. 把UserDaoImpl交给spring管理-->
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>

    <!--
        2. 把UserServiceImpl04交给spring管理
     -->
    <bean id="userviceImpl" class="com.itheima.service.impl.UserServiceImpl"/>

    <bean id="us" class="com.itheima.service.impl.UserServiceImpl04">

        <!--1. 数组-->
        <property name="array">
            <array>
                <value>array01</value>
                <value>array02</value>
                <value>array03</value>
            </array>
        </property>

        <!--2. list-->
        <property name="list">
            <list>
                <value>list01</value>
                <value>list02</value>
                <value>list03</value>
            </list>
        </property>

        <!--3. set-->
        <property name="set">
            <set>
                <value>set01</value>
                <value>set02</value>
                <value>set03</value>
            </set>
        </property>

        <!--4. map-->
        <property name="map">
            <map>
                <entry key="key1" value="value1"/>
                <entry key="key2" value="value2"/>
                <entry key="key3" value="value3"/>
            </map>
        </property>

        <!--5. properties-->
        <property name="properties">
            <props>
                <prop key="username">张三</prop>
                <prop key="password">123456</prop>
            </props>
        </property>

    </bean>

</beans>

所有单列结构的数据集合,标签可以互换使用。例如:List、Set、数组等

所有键值对结构的数据集合,标签可以互换使用。例如:Map、Properties等

小结

  1. 所有的DI数据类型里面,最常用的是对象数据。
  2. 最常用的方式 set方法。
  3. 数组 、 list 、set写法基本一样, map 和 properties基本一样。

五、相关API介绍(了解)

1. ApplicationContext的继承体系

1563065014422

2. ApplicationContext

2.1 XmlBeanFactory 和 ApplicationContext的区别

2.2 ApplicationContext的实现类

2.2.1 ClassPathXmlApplicationContext
2.2.2 FileSystemXmlApplicationContext
2.2.3 AnnotationConfigApplicationContext

2.3 getBean()方法

方法 参数 返回值
getBean(String beanId) bean的id Object,bean对象
getBean(String beanId,Class beanType) bean的Class类型 bean对象
getBean(Class beanType) bean对象
getBeanDefinitionNames String[] 获取工厂管理的对象的名字
   package com.itheima.test;

import com.itheima.service.UserService;
import com.itheima.service.impl.UserServiceImpl04;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestApplicationContext {

    @Test
    public void testGetBean(){

        //1. 创建工厂
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext04.xml");

        //2. 问工厂要对象=getBean()

       /**/ //1. 按照id来找对象,没有问题的!
        UserService us = (UserService)context.getBean("us");
        us.add();

        //2. 按照真实的自己的类型来找对象!
        UserService us2 = context.getBean(UserServiceImpl04.class);
        us2.add();

        //3. 按照接口的类型来找对象!
        UserService us3 = context.getBean(UserService.class);
        us3.add();

    }

    // 得到所有对象的id值
    @Test
    public void testGetBeanNames(){

        //1. 创建工厂
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext04.xml");


        //2. 获取spring工厂里面的所有对象的id值。
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println("name = " + name);
        }

    }

}

六、CURD练习【了解】

需求描述

需求分析

  1. 准备工作:
    • 创建Maven的Java项目,配置坐标,引入依赖
    • 创建数据库
    • 创建JavaBean
  2. 编写代码:
    • 创建service和dao的接口和实现类,并添加上:查询全部、添加帐号、修改帐号、删除帐号的功能
  3. 配置文件:
    • 创建Spring核心配置文件,配置所有的bean
  4. 测试
    • 创建单元测试类,测试功能是否正常

需求实现

3.1 准备工作

  1. 准备数据库

需要先手动创建一个数据库: day41_spring,然后再运行下面的这段sql语句

create table t_account (id int primary key auto_increment , name varchar(25) , money int);
insert into t_account values(null , 'zs' , 1000);
insert into t_account values(null , 'ls' , 2000);
insert into t_account values(null , 'ww' , 3000);
  1. 创建Maven的Java项目,项目坐标自定,然后引入依赖如下:
<dependencies>
        <!-- 数据库驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <!-- c3p0连接池(也可以用其它连接池) -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>

        <!-- DBUtils工具包 -->
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.7</version>
        </dependency>

        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.2.RELEASE</version>
        </dependency>

        <!-- 单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
        </dependency>
    </dependencies>
  1. 创建JavaBean:Account类如下:

    package com.itheima.bean;
    
    import lombok.Data;
    
    @Data
    public class Account {
        private int id;
        private String name;
        private int money;
    }
    
    

3.2 编写代码

1) Service层代码如下:
  1. Service层接口:AccountService

    package com.itheima.service;
    
    import com.itheima.bean.Account;
    
    import java.sql.SQLException;
    import java.util.List;
    
    public interface AccountService {
        int add(Account account) throws SQLException;
        int delete(int id) throws SQLException;
        int update(Account account) throws SQLException;
        Account findById(int id) throws SQLException;
        List<Account> findAll() throws SQLException;
    }
    
    
  2. Service实现类:AccountServiceImpl

    package com.itheima.serivce.impl;
    
    import com.itheima.bean.Account;
    import com.itheima.dao.AccountDao;
    import com.itheima.serivce.AccountService;
    
    import java.sql.SQLException;
    import java.util.List;
    
    /*
        1. 把AccountServiceImpl 交给spring管理
        2. 让spring把AccountDaoImpl的对象给注入进来
            2.1 定义一个属性
            2.2 提供这个属性的set方法~
     */
    public class AccountServiceImpl implements AccountService {
    
        private AccountDao dao;
    
        public void setDao(AccountDao dao) {
            this.dao = dao;
        }
    
        public int add(Account account) throws SQLException {
            return dao.add(account);
        }
    
        public int delete(int id) throws SQLException {
            return dao.delete(id);
        }
    
        public int update(Account account) throws SQLException {
            return dao.update(account);
        }
    
        public Account findById(int id) throws SQLException {
            return dao.findById(id);
        }
    
        public List<Account> findAll() throws SQLException {
            return dao.findAll();
        }
    }
    
    
2) dao层代码如下:
  1. dao层接口:AccountDao

    package com.itheima.dao;
    
    import com.itheima.bean.Account;
    
    import java.sql.SQLException;
    import java.util.List;
    
    public interface AccountDao {
        int add(Account account) throws SQLException;
        int delete(int id) throws SQLException;
        int update(Account account) throws SQLException;
        Account findById(int id) throws SQLException;
        List<Account> findAll() throws SQLException;
    }
    
    
  2. dao实现类:AccountDaoImpl

    package com.itheima.dao.impl;
    
    import com.itheima.bean.Account;
    import com.itheima.dao.AccountDao;
    import org.apache.commons.dbutils.QueryRunner;
    import org.apache.commons.dbutils.handlers.BeanHandler;
    import org.apache.commons.dbutils.handlers.BeanListHandler;
    
    import java.sql.SQLException;
    import java.util.List;
    
    /*
        1. 把这个AccountDaoImpl这个类交给spring管理
        2. 这里也不想手动创建QueryRunner对象了,而是让spring来创建它的对象,
            但是spring创建对象,这个AccountDaoImpl想要用这个QueryRunner对象,咋办呢?
            让spring注入进来这个QueryRunner对象即可
    
            2.1 定义一个属性
    
            2.2 定义属性的set方法
     */
    public class AccountDaoImpl implements AccountDao {
    
        private QueryRunner runner;
        public void setRunner(QueryRunner runner) {
            this.runner = runner;
        }
    
        public int add(Account account) throws SQLException {
            //QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource());
            String sql = "insert into t_account values (null , ? , ?)";
            return runner.update(sql , account.getName() , account.getMoney());
        }
    
        public int delete(int id) throws SQLException {
            String sql = "delete from t_account where id = ?";
            return runner.update(sql , id);
        }
    
        public int update(Account account) throws SQLException {
            String sql = "update t_account set name = ? , money = ? where id = ?";
            return runner.update(sql , account.getName() , account.getMoney() , account.getId());
        }
    
        public Account findById(int id) throws SQLException {
            String sql = "select * from t_account where id = ?";
            return runner.query(sql ,  new BeanHandler<Account>(Account.class), id);
        }
    
        public List<Account> findAll() throws SQLException {
            String sql = "select * from t_account ";
            return runner.query(sql ,  new BeanListHandler<Account>(Account.class));
        }
    }
    
    

3.3 提供配置

  1. 创建Spring的核心配置文件: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">
    
        <!--1. 把AccountServiceImpl交给spring管理-->
        <bean id="as" class="com.itheima.serivce.impl.AccountServiceImpl">
            <property name="dao" ref="ad"/>
        </bean>
    
        <!--2. 把AccountDaoImpl交给spring管理-->
        <bean id="ad" class="com.itheima.dao.impl.AccountDaoImpl">
            <property name="runner" ref="runner"/>
        </bean>
    
        <!--3. 把QueryRunner交给spring管理-->
        <bean id="runner" class="org.apache.commons.dbutils.QueryRunner">
            <constructor-arg name="ds" ref="dataSource"/>
        </bean>
    
        <!--4. 把DataSource(其实就是连接池)交给spring管理-->
        <!--4.1 导入外部的properties文件-->
        <context:property-placeholder location="db.properties"/>
    
        <!--4.2 在下面使用properties的内容-->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="${db.driverClass}"/>
            <property name="jdbcUrl" value="${db.jdbcUrl}"/>
            <property name="user" value="${db.username}"/>
            <property name="password" value="${db.password}"/>
        </bean>
    
    
        <!--<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="com.mysql.jdbc.Driver"/>
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/day41_spring"/>
            <property name="user" value="root"/>
            <property name="password" value="root"/>
        </bean>-->
    </beans>
    

3.4 功能测试

  1. 编写单元测试类AccountTest如下:

    package com.itheima.test;
    
    import com.itheima.bean.Account;
    import com.itheima.serivce.AccountService;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import java.sql.SQLException;
    
    public class TestAccountServiceImpl {
    
        @Test
        public void testAdd() throws SQLException {
            //1. 创建工厂
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
            //2. 问工厂要对象
            AccountService as = (AccountService) context.getBean("as");
    
            //3. 调用方法
            Account a = new Account();
            a.setName("张三");
            a.setMoney(100);
    
            as.add(a);
    
        }
    
        @Test
        public void testDelete() throws SQLException {
            //1. 创建工厂
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
            //2. 问工厂要对象
            AccountService as = (AccountService) context.getBean("as");
    
            //3. 调用方法
            as.delete(4);
    
        }
    
        @Test
        public void testUpdate() throws SQLException {
            //1. 创建工厂
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
            //2. 问工厂要对象
            AccountService as = (AccountService) context.getBean("as");
    
            //3. 调用方法
    
            //3.1 先查询
            Account a = as.findById(3);
            a.setMoney(9999);
    
            //3.2 再修改
            as.update(a);
    
        }
    
        @Test
        public void testFindAll() throws SQLException {
            //1. 创建工厂
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
            //2. 问工厂要对象
            AccountService as = (AccountService) context.getBean("as");
    
            //3. 调用方法
            System.out.println(as.findAll());
    
        }
    
    }
    
    

补充

引入properties文件

如果需要在applicationContext.xml中引入properties文件:

driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://localhost:3306/day42_spring
user=root
password=root
<beans
       xmlns:名称空间="http://www.springframework.org/schema/名称空间"
       xsi:scehmaLocation="
          http://www.springframework.org/schema/名称空间
         http://www.springframework.org/schema/名称空间/spring-名称空间.xsd">
</beans>

context的标签,硬着头皮写出来就可以了,不要害怕!

   <!--导入进来db.properties-->
    <context:property-placeholder location="db.properties"/>

    <!--在下面使用 ${}来取值-->
    <bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${driverClass}"/>
        <property name="jdbcUrl" value="${jdbcUrl}"/>
        <property name="user" value="${user}"/>
        <property name="password" value="${password}"/>
    </bean>

分模块提供配置文件

在大型项目开发中,如果把所有的配置都写在一个配置文件applicationContext.xml中,会导致:

Spring提供了分模块配置的方式,即:每个模块|层提供一个配置文件,在核心配置文件中引入模块配置:

<import resource="classpath:applicationContext-service.xml"/>
<import resource="classpath:applicationContext-dao.xml"/>

小结

  1. 把dao和service都交给spring托管

    1. 在service里面注入进来dao
    2. dao里面要用到QueryRunner , QueryRunner也可以让Spring注入进来。
    3. 但凡是我们需要自己new对象,都交给spring来完成,然后注入进来即可。

七、Spring整合Junit【掌握】

​ 在上边的CURD中,单元测试类里还需要我们自己去创建ApplicationContext,并自己去获取bean对象。Spring提供了整合Junit的方法,让单元测试更简洁方便。

注解简介

注解 说明
@RunWith 用在测试类上,用于声明不再使用Junit,而是使用Spring提供的运行环境
@ContextConfiguration 用在测试类上,用于指定Spring配置类、或者Spring的配置文件

Spring提供了单元测试的运行环境:SpringJunit4ClassRunner,配置到@RunWith注解上:

@RunWith(SpringJunit4ClassRunner.class)

 <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

使用示例

步骤

  1. 在pom.xml文件中增加依赖:spring-testjunit

  2. 修改单元测试类

    1. 在单元测试类上增加注解:@RunWith(SpringJunit4ClassRunner.class)

      目的:使用Spring的单元测试运行器,替换Junit原生的运行器

    2. 在单元测试类上增加注解:@ContextConfiguration()

      目的:指定配置文件或配置类

    3. 在测试类里的依赖项上,直接使用@Autowired注入依赖

实现

  1. 在pom.xml文件中增加依赖:spring-testjunit

     <dependencies>
            <!-- Spring -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.1.2.RELEASE</version>
            </dependency>
    
            <!--spring单元测试的依赖-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>5.1.2.RELEASE</version>
            </dependency>
    
            <!--Junit的依赖-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
    
        </dependencies>
    
  2. UserService接口

package com.itheima.service;

public interface UserService {
    void add();
}
  1. UserServiceImpl实现类
package com.itheima.service.impl;

import com.itheima.service.UserService;

public class UserServiceImpl implements UserService {
    public void add() {
        System.out.println("调用了UserServiceImpl的add方法!~");
    }
}

  1. 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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="us" class="com.itheima.service.impl.UserServiceImpl"/>
</beans>
  1. 修改单元测试类
package com.itheima.test;

import com.itheima.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/*
    spring整合Junit
        1. 在类身上打注解 @RunWith 和 @ContextConfiguration

        2. @RunWith(SpringJUnit4ClassRunner.class)
            作用:
                2.1. 表示我们单元测试,使用的是spring提供的测试环境
                2.2. 这个测试环境会帮助我们自动的去创建spring的工厂
        3.@ContextConfiguration("classpath:applicationContext.xml")
            作用:
                3.1 告诉spring的单元测试环境,配置文件在哪里!

 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestUserServiceImpl02 {

    //让spring把UserServiceImpl的对象给注入进来
    //声明属性
    @Autowired
    private UserService us ;

    @Test
    public void testAdd(){
        //3. 调用方法
        us.add();

    }
}

小结

  1. 导入依赖

    1. 在测试类上打注解
    2. 直接在测试类里面使用@Autowired注入对象。

总结

IOC:

1. IOC是什么?
	控制反转,让spring帮助我们创建对象,我们只要问spring要对象即可
2. IOC怎么用?
	2.1 导入spring的依赖
	2.2 创建接口和实现类
	2.3 在resource下创建一个xml文件
		<bean id="us" class="类的全路径"/>
	2.4 单元测试里面
		a. 创建工厂

		b. 问工厂要对象

		c. 调用方法即可!

3. 细节:
	3.1 默认情况下,spring创建的对象是单例的!如果想做成多例的对象,需要搭配
		属性scope="prototype"

	3.2 默认情况下,spring创建类的对象,会执行该类的无参构造方法!

	3.3 spring创建单例对象是在工厂创建的时候,就创建对象了。但是如果是多例对象
		是需要对象的时候,才会创建。

DI:

1. 什么是DI?
	DI 就是依赖注入,让spring给托管类的属性,赋值!
2. 怎么用?

	2.1 定义属性
	2.2 提供属性的set方法
	2.3 在xml里面配置<property>标签

	<bean id="us" class="com.itheima.service.impl.UserServiceImpl">
		<property name="userDao" ref="ud"/>
		<property name="address" value="深圳"/>
	</bean>
3. 常用的方式:
	set方法
	有参构造
	p名称空间

4. 注入数据类型:
	简单数据类型
	对象数据类型
	集合数据类型

整合Junit:

@RunWith(SpringJunit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")

标签:Spring,dao,Spring01,41,import,com,public,itheima
来源: https://www.cnblogs.com/ofanimon/p/16182687.html