目录

一、spring概述

1.1、Spring是什么

1.2、 Spring体系编辑

二、 优质程序代码的书写原则

2.1、耦合与内聚

2.2、耦合和内聚代码示例

2.3、耦合的弊端:

2.4、如何实现解耦?

三、IOC的相关概念

四、 基于XML的IOC环境搭建

五、Spring中IOC容器(API)

5.1、bean工厂的结构

5.1.1 ApplicationContext: 应用上下文 接口  饿汉加载模式

5.1.2 BeanFactory: 懒汉式延迟加载

5.2、创建Bean对象的三种方式

5.2.1 通过工厂对象的方法来创建(静态及非静态)

5.3、Bean对象的作用范围

5.3.1 单例bean测试:

5.3.2 多例bean测试:

 5.4、Bean对象的生命周期

六、Spring中的DI(依赖注入)

6.1、 IOC和DI区别

6.2、注入数据的方式和类型

6.2.1 有参构造注入

6.2.2 setter方式注入

6.2.3 setter注入其他bean类(User.class)

6.2.4 setter注入数组、集合、配置

七、扩展:单例延迟加载


一、spring概述

1.1、Spring是什么

Spring是分层的JavaSE/EE应用full-stack(全栈)轻量级开源框架;

java限制同样参数只有第一次有效_mybatis

①Spring框架是J2EE企业级应用的轻量级开源框架,提供了表现层springmvc和持久springJDBC(JDBCTemplate),以及业务层的事务管理等企业级应用解决方案;

②Spring还能将开源世界中众多优秀的第三方框架进行集成(比如mybatis等),成为了越来越受欢迎的J2EE企业级应用框架;

③Spring是以IOC(Inversion Of Control)控制反转和AOP(Aspect Oriented Programming)面向切面编程为核心;

1.2、 Spring体系

java限制同样参数只有第一次有效_java_02

 源码下载地址: https://repo.springsource.org/libs-release-local/org/springframework/spring/

二、 优质程序代码的书写原则

2.1、耦合与内聚

  • 耦合(Coupling):代码书写过程中所使用技术的结合紧密度(程序之间的依赖程度),用于衡量软件中各个模块之间的互联程度
  • 内聚(Cohesion):代码书写过程中单个模块内部各组成部分间的联系,用于衡量软件中各个功能模块内部的功能联系
  • 程序书写的目标:高内聚,低耦合
  • 就是同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却不要那么紧密

2.2、耦合和内聚代码示例

//耦合:程序代码之间的依赖关系
   public class UserService(){
       public List<User> getAllUser(){
          /**
           * getAllUser方法的执行需要依赖UserDao类,
           * 我们称,getAllUser方法与UserDao类之间有耦合
           **/
            UserDao userDao=new UserDao();
            return userDao.findAll();
       }
    } 
   public class UserDao(){
      	 public List<User> findAll(){ 
             //do something and return list
       }
    } 

//内聚:一个方法只做一件事情(一个类只聚合一个业务属性集)
  	//反例: 此方法不符合高内聚思想
  	public int compute(int i,int j,String label){
  		if("+".equals(label)){
           return i+j;
        }else if("-".equals(label)){
           return i-j;
        }else{
            //do something....
        }
	}
	//例子:
	public int add(int i,int j){
      return i+j;
    }
	public int sub(int i,int j){
      return i-j;
    }
    //......

思考:以下代码存在哪些耦合问题?

public class Demo {
    public static void findAll() throws Exception {
        // jdbc操作数据库
        //1.注册驱动: 将mysql提供的驱动类加载到内存中,并交个DriverManager管理
        DriverManager.registerDriver(new Driver()); // 注册了2次,且存在耦合
        //Class.forName("com.mysql.jdbc.Driver"); // 反射方式,注册驱动
        // 将驱动的全限定名设置到配置文件中,通过读取配置文件,获取实现类的全限定名,从而实现解耦.
        // 实现解耦后,当修改驱动时,无需修改任何java代码,只需要修改配置文件即可
        //2.获取连接
        String url = "jdbc:mysql://localhost:3306/spring_116";
        String username = "root";
        String password = "root";
        Connection conn = DriverManager.getConnection(url, username, password);
        //3.编写sql语句
        String sql = "select * from account ";
        //4.获取语句执行者
        PreparedStatement pst = conn.prepareStatement(sql);
        //5.执行sql并返回结果集
        ResultSet rs = pst.executeQuery();
        //6.处理结果集
        while (rs.next()){
            int id = rs.getInt("id");
            String name = rs.getString("name");
            float money = rs.getFloat("money");
            System.out.println(id+ " : "+name+" : "+money);
        }
        //7.关闭连接
        rs.close();
        pst.close();
        conn.close();
    }
}

说明:

  • 耦合: 程序代码之间的依赖关系
  • 低耦合: 降低程序代码之间的依赖关系,从而方便维护扩展和重用
  • 解耦合: 在java程序代码中,耦合是不可能完全解开的,我们所说的"解耦合"指的是解开程序编译期的耦合

2.3、耦合的弊端:

独立性差 可重用性不高 维护成本高

2.4、如何实现解耦?

①原始方案:服务层与持久层存在紧耦合;

java限制同样参数只有第一次有效_java限制同样参数只有第一次有效_03

 ②加入工厂模式后,服务层与持久层完成解耦,但是工厂类与持久层存在紧耦合;

java限制同样参数只有第一次有效_java_04

③通过工厂模式和静态资源配置将代码的耦合降到最低;  

java限制同样参数只有第一次有效_mybatis_05

最终方案:工厂+配置文件解耦

bean多实例-工厂类代码

/**
 * bean工厂: 专门用于创建Bean对象(java对象)
 */
public class BeanFactory {

    // 用于存放解析到的全限定名
    private static Map<String,String> urlMap = new HashMap<>();
    static {
        // 1.解析配置文件,获取配置文件中配置的全限定名
        // ResourceBundle: jdk提供的工具,专门用于解析properties配置文件
        ResourceBundle bundle = ResourceBundle.getBundle("beans");
        // 获取properties配置文件中所有的key
        Enumeration<String> keys = bundle.getKeys();
        while (keys.hasMoreElements()){
            // 获取下一个key
            String key = keys.nextElement();
            // 根据key获取对应的全限定名
            String value = bundle.getString(key);
            // 存放到map集合中
            urlMap.put(key,value);
        }
        // 测试是否解析到了数据
        for (String key:urlMap.keySet()){
            System.out.println(key+" : "+urlMap.get(key));
        }
    }

    // 反射创建类对象
    public static Object getBean(String id) {
        try {
            // 根据id获取对应的类的全限定名
            String className = urlMap.get(id);
            // 反射创建类对象
            Object obj = Class.forName(className).newInstance();
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

bean单实例-工厂代码

/**
 * bean工厂: 专门用于创建Bean对象(java对象)
 */
public class BeanFactory1 {

    // 用于存放创建的bean对象(容器)
    private static Map<String,Object> beansMap = new HashMap<>();
    // 用于存放解析到的全限定名
    private static Map<String,String> urlMap = new HashMap<>();
    static {
        // 1.解析配置文件,获取配置文件中配置的全限定名
        // ResourceBundle: jdk提供的工具,专门用于解析properties配置文件
        ResourceBundle bundle = ResourceBundle.getBundle("beans");
        // 获取properties配置文件中所有的key
        Enumeration<String> keys = bundle.getKeys();
        while (keys.hasMoreElements()){
            // 获取下一个key
            String key = keys.nextElement();
            // 根据key获取对应的全限定名
            String value = bundle.getString(key);
            // 存放到map集合中
            urlMap.put(key,value);
        }
        // 测试是否解析到了数据
        for (String key:urlMap.keySet()){
            System.out.println(key+" : "+urlMap.get(key));
        }
    }


    // 反射创建类对象
    public static Object getBean(String id) {
        try {
            // 先从bean容器中获取对象
            Object obj = beansMap.get(id);
            if(obj==null){
                // 根据id获取对应的类的全限定名
                String className = urlMap.get(id);
                // 反射创建类对象
                obj = Class.forName(className).newInstance();
                // 将创建好的bean对象存放到beansMap容器中
                beansMap.put(id,obj);
            }
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

立即加载的方式创建

/**
 * bean工厂: 专门用于创建Bean对象(java对象)
 */
public class BeanFactory2 {

    // 用于存放创建的bean对象(容器)
    private static Map<String,Object> beansMap = new HashMap<>();
    // 用于存放解析到的全限定名
    private static Map<String,String> urlMap = new HashMap<>();
    static {

        try {
            // 1.解析配置文件,获取配置文件中配置的全限定名
            // ResourceBundle: jdk提供的工具,专门用于解析properties配置文件
            ResourceBundle bundle = ResourceBundle.getBundle("beans");
            // 获取properties配置文件中所有的key
            Enumeration<String> keys = bundle.getKeys();
            while (keys.hasMoreElements()){
                // 获取下一个key
                String key = keys.nextElement();
                // 根据key获取对应的全限定名
                String value = bundle.getString(key);
                // 存放到map集合中
                urlMap.put(key,value);
                // 立即加载的思想创建bean对象
                Object obj = Class.forName(value).newInstance();
                // 将创建好的对象存放到beansMap容器中
                beansMap.put(key,obj);
            }
            // 测试是否解析到了数据
            // for (String key:urlMap.keySet()){
            //     System.out.println(key+" : "+urlMap.get(key));
            // }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    // 反射创建类对象
    public static Object getBean(String id) {
        try {
            // 先从bean容器中获取对象
            Object obj = beansMap.get(id);
            if(obj==null){
                // 根据id获取对应的类的全限定名
                String className = urlMap.get(id);
                // 反射创建类对象
                obj = Class.forName(className).newInstance();
                // 将创建好的bean对象存放到beansMap容器中
                beansMap.put(id,obj);
            }
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

 配置文件

# 格式:key=value
# key: 自定义,一般为当前类实现的接口的名称
# value: 当前需要使用的类的全限定名
userDao=com.hhy.dao.impl.UserDaoImpl
userService=com.hhy.service.UserServiceImpl

三、IOC的相关概念

  • IoC(Inversion Of Control)控制反转,Spring反向控制应用程序所需要使用的外部资源;
  • Spring控制的资源全部放置在Spring容器中,该容器称为IoC容器;
  • spring容器中存储的对象称为bean对象;

 IOC(inversion of control): 控制反转,反转的是对象的创建权,用于削减程序之间的耦合关系,底层使用反射技术实现
    传统方式创建对象:  new 对象(); (主动创建)
    IOC方式创建对象: 找容器(被动接收),本质上就是一个Map集合

    作用:解耦
        通过标记(标记就是配置文件中的key)找工厂,工厂帮我们创建对应的类对象,并返回给我们使用
        当前类可以选择主动出击(new的方式)创建对象,但是此时耦合度高。
        把主动式改成被动接收,由工厂对象为当前类生产所必须的关联对象,此时降低了两个类的依赖关系。

java限制同样参数只有第一次有效_spring_06

四、 基于XML的IOC环境搭建

准备接口及实现类:

public interface AccountService {
    void add();
    void init();
    void destroy();
}

public class AccountServiceImpl implements AccountService {

    //用于判断何时被创建
    public AccountServiceImpl() {
        System.out.println("AccountServiceImpl构造器被调用");
    }
    @Override
    public void add() {
        System.out.println("add被调用");
    }

    @Override
    public void init() {
        //测试bean的生命周期
        System.out.println("AccountServiceImpl初始化");
    }

    @Override
    public void destroy() {
        //测试bean的生命周期
        System.out.println("AccountServiceImpl销毁");
    }

}

1.导入Spring的核心jar包的坐标:

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

2.创建applicationContext.xml,并导入约束:

id: 容器中的唯一标识  class:被创建的类的全限定名(包名+类名)

<?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">

    <!-- 方式一: 无参构造创建对象,存放到IOC容器中 -->
    <!-- id: 容器中的唯一标识  class:被创建的类的全限定名(包名+类名) -->
    <bean id="accountService" class="hhy.service.impl.AccountServiceImpl"></bean>
</beans>

xml和properties区别:
    二者都可以做配置文件
    properties更容易解析
    Spring之所以使用xml作为配置文件,是因为:
        xml结构清晰,嵌套关系明确,一目了然
        xml可以通过嵌套关系描述更多的事情.

 测试:

@Test
    public void t1() {
        // ClassPathXmlApplicationContext: 读取类路径下的xml文件
        // 类路径: 指的就是resources目录
        //1.调用Spring的API,解析配置文件让Spring创建IOC容器
        ApplicationContext ac =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.调用应用上下文对象的API,从IOC容器中获取类对象
        //AccountService service = (AccountService) ac.getBean("AccountService");
        //传入对应类,不用强转
        AccountService service = ac.getBean("accountService", AccountService.class);
        service.add();
    }

五、Spring中IOC容器(API)

5.1、bean工厂的结构

5.1.1 ApplicationContext: 应用上下文 接口  饿汉加载模式

ApplicationContext: 当解析完applicationContext.xml文件后,立即创建类对象(饿汉加载模式)
    它是一个接口。是spring中的IOC容器接口,可以通过该接口的方法来获取想要的bean对象。需要提供bean的id。
    它有3个常用的实现类
         ClassPathXmlApplicationContext★:
                    它是用于读取类路径(resources)下的xml配置文件,不在类路径下读取不到
         FileSystemXmlApplicationContext:
                    它是读取文件系统中的配置文件,只要有访问权限,在文件系统中都能读取的到
         AnnotationConfigApplicationContext:
                    它是用于根据注解配置 创建容器的。
            
(★★)ApplicationContext它是在一读取完配置文件,就马上创建配置文件中所配置的所有对象。(得到IOC容器)
    
在IDEA中查看类的继承体系:
        ctrl + alt + U 

ApplicationContext: 饿汉加载模式

java限制同样参数只有第一次有效_java限制同样参数只有第一次有效_07

5.1.2 BeanFactory: 懒汉式延迟加载

BeanFactory:
     它是spring中ioc容器的顶层接口,ApplicationContext只是它的子接口。
     它提供创建容器中对象的时机,使用延迟加载(懒加载)的思想。而ApplicationContext不仅继承了它的加载方式,而且还扩展出来了立即加载思想的创建容器的方式。
     它是每次在使用时才真正的创建对象。
//使用beanFactory加载 懒汉式延迟加载
    @Test
    public void t2() {
        ClassPathResource resource = new ClassPathResource("applicationContext.xml");
        XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(resource);
        //如注释其他代码 则对象不会被创建
        AccountService accountService = xmlBeanFactory.getBean("accountService", AccountService.class);
        accountService.add();
    }

5.2、创建Bean对象的三种方式

第一种:通过默认构造函数创建(上面用的就是)
	<bean id="userService" class="com.itheima.service.impl.UserServiceImpl"></bean>
	此种方式通常用于我们自己写的类,在spring中配置。
第二种:通过工厂对象的方法来创建(静态)
	class属性: 指定的是工厂的全限定类名
	factory-method属性:指定的是工厂中用于创建对象的静态方法
	<bean id="userService" class="com.itheima.factory.StaticFactory" factory-method="createBean"></bean>
	此种方法通常用于不是我们自己写的类,而是存在于jar包中已经写好的类。(它都是.class文件)
第三种:通过工厂对象的方法来创建(非静态)
	factory-bean属性:指定的是工厂bean的id.
	factory-method属性:指定的是工厂中用于创建对象的非静态方法
	<bean id="instanceFactory" class="com.itheima.factory.InstanceFactory"></bean>
	<bean id="userService" factory-bean="instanceFactory" factory-method="createBean"></bean>
	此种方式通常用于不是我们自己写的类。

5.2.1 通过工厂对象的方法来创建(静态及非静态)

准备:

public class serviceFactory {

    //该静态方法方法被调用时 创建一个对象 交给springIOC管理
    public static AccountService getInstance() {
        return new AccountServiceImpl();
    }
    
    //该非静态方法被调用时 创建一个对象 交给springIOC管理
    public AccountService getInstance2() {
        return new AccountServiceImpl();
    }
}

 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">

    <!--
        将项目中一切可能使用到的对象通通创建出来,并交个Spring的IOC管理
        创建Bean对象的三种方式
            方式1: 无参构造创建对象,存放到IOC容器中
            方式2: 调用工厂的静态方法创建类对象,存放到IOC容器中
            方式3: 调用工厂的非静态方法创建类对象,存放到IOC容器中
     -->
    <!-- 方式1: 无参构造创建对象,存放到IOC容器中 -->
    <!-- id: 容器中的唯一标识  class:被创建的类的全限定名(包名+类名) -->
    <bean id="accountService" class="hhy.service.impl.AccountServiceImpl"></bean>

    <!-- 方式2: 调用工厂的静态方法创建类对象,存放到IOC容器中 -->
    <!--
        调用工厂的静态方法,将方法的返回值存放到IOC容器中
           id: 存放到IOC容器时,对象的唯一标识
           class: 工厂的全限定名
           factory-method: 指定静态方法名称 getInstance表示当前类同该方法获取bean并加入springIOC容器
    -->
    <bean id="staticFactory" class="hhy.factory.serviceFactory" factory-method="getInstance"></bean>

    <!-- 方式3: 调用工厂的非静态方法创建类对象,存放到IOC容器中 -->
    <!--3.1: 创建工厂类对象,并存放到IOC容器中 -->
    <bean id="serviceFactory" class="hhy.factory.serviceFactory"></bean>
    <!--3.2: 调用工厂实例的非静态方法创建类对象 -->
    <!--
        调用工厂的非静态方法,将非静态方法的返回值存放到IOC容器中
            id:存放到IOC容器时,对象的唯一标识
            factory-bean:工厂对象实例的引用
            factory-method:调用实例工厂的非静态方法
    -->
    <bean id="noStaticFactory" factory-bean="serviceFactory" factory-method="getInstance2"></bean>
</beans>

测试:

//通过工厂对象的方法来创建(静态及非静态)
    @Test
    public void t3() {
        // ClassPathXmlApplicationContext: 读取类路径下的xml文件 类路径: 指的就是resources目录
        //1.调用Spring的API,解析配置文件让Spring创建IOC容器
        //饿汉模式 (测试:如注释其他代码只读取xml文件,能立即创建对象)
        ApplicationContext ac =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.调用应用上下文对象的API,从IOC容器中获取类对象 传入对应类,不用强转
        //静态
        AccountService service = ac.getBean("staticFactory", AccountService.class);
        service.add();
        //非静态
        AccountService service2 = ac.getBean("noStaticFactory", AccountService.class);
        service2.add();
    }

5.3、Bean对象的作用范围

bean的作用范围调整:
    调整bean的作用范围,使用的是bean标签的scope属性。
    它的属性取值有以下5个
      singleton            :单例对象(只存在一个)      用的最多的           它是默认值(最常用)
      prototype           :多例对象(调一次生成一个)       用的最多的
      ------------------------------------
      request              :请求范围      (存入了请求域)
      session              :会话范围      (存入了会话域)
      global-session   :全局会话范围   当非集群环境下,它就是session

5.3.1 单例bean测试:

xml

<!-- 测试IOC容器中bean的作用范围
            scope: 域,范围
                singleton : 默认值,单实例对象
                prototype : 多实例对象
     -->
    <!--配置单例bean-->
    <bean id="accountService" scope="singleton" class="hhy.service.impl.AccountServiceImpl"></bean>
    <!--配置多例bean-->
    <bean id="accountService2" scope="prototype" class="hhy.service.impl.AccountServiceImpl2"></bean>
//测试单例
    @Test
    public void t4() {
        ApplicationContext ac =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        AccountService service1 = ac.getBean("accountService", AccountService.class);
        System.out.println("service1 = " + service1);
        AccountService service2 = ac.getBean("accountService", AccountService.class);
        System.out.println("service2 = " + service2);
        System.out.println(service1==service2);
        //true
    }

 5.3.2 多例bean测试:

@Test
    public void t5() {
        ApplicationContext ac =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        AccountService service1 = ac.getBean("accountService2", AccountService.class);
        System.out.println("service1 = " + service1);
        AccountService service2 = ac.getBean("accountService2", AccountService.class);
        System.out.println("service2 = " + service2);
        System.out.println(service1==service2);
        //false
    }

 5.4、Bean对象的生命周期

bean对象的生命周期: 从加载到内存哪一刻起对象就出生了,当对象从内存中移除时,对象的生命就完结了  

bean的生命周期:
    单例对象: 将创建的bean放入容器
    	出生:容器创建,对象出生
    	活着:只要容器在,对象就一直活着
    	死亡:容器销毁,对象消亡
    特点: 生命周期与容器相同

    <!-- 测试IOC容器中bean的生命周期:
            单实例:
                创建: 配置文件解析完毕后,会立即创建对象,并存放到IOC容器中
                销毁: IOC容器销毁销毁
            多实例:
                创建: 调用getBean方法时创建.
                销毁: 等待GC回收
     -->
	<!--
            init-method: 初始化方法(构造器初始化对象之后被调用)
            destroy-method: 销毁时调用的方法(对象被销毁之前被调用)
    -->
    <!--为避免影响 二至注释掉其一-->
    <!--单例bean的生命周期-->
<!--    <bean id="accountService3" class="hhy.service.impl.AccountServiceImpl"-->
<!--        init-method="init" destroy-method="destroy"></bean>-->
    <!--多例bean的生命周期 prototype-->
    <bean id="accountService4" class="hhy.service.impl.AccountServiceImpl"
          scope="prototype"
        init-method="init" destroy-method="destroy"></bean>

   
多例对象:
    出生:每次使用时创建
    活着:在使用过程中
    死亡:使用完成之后,等待垃圾回收器回收。
    	多实例bean对象的生命周期
            scope的值必须为: prototype
//单例生命周期 初始化一次、销毁一次
    @Test
    public void 测试单例bean生命周期() {
        ApplicationContext ac =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        //调用两次 只init一次
        AccountService service1 = ac.getBean("accountService3", AccountService.class);
        AccountService service2 = ac.getBean("accountService3", AccountService.class);
        ClassPathXmlApplicationContext cl= (ClassPathXmlApplicationContext) ac;
        cl.close();
    }

    //多例生命周期 创建几个对象就初始化几次、等待垃圾回收销毁
    @Test
    public void 测试多例bean生命周期() {
        ApplicationContext ac =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        //调用两次 只init一次
        AccountService service1 = ac.getBean("accountService4", AccountService.class);
        AccountService service2 = ac.getBean("accountService4", AccountService.class);
        ClassPathXmlApplicationContext cl= (ClassPathXmlApplicationContext) ac;
        cl.close();
    }

六、Spring中的DI(依赖注入)

介绍:

依赖注入:Dependency Injection
        通俗来讲: 缺什么给什么(给的对象从IOC容器中获取)
    简单的说,就是在程序运行期,给当前类传入依赖的对象。缺什么传什么。
      例如:
    在创建UserService的bean对象时,该对象中需要依赖UserDao对象,那么就将这些依赖的对象注入当前对象中;

6.1、 IOC和DI区别

  • IoC与DI是同一件事站在不同角度看待问题
    在应用程序的角度看程序需要被动等待Spring提供资源(注入资源)是DI;
    但是在Spring容器的角度看是,是将资源的创建权利做了翻转,且由容器提供数据,是IOC;
  • 如半杯水,看待角度不同则想法不同。

半杯水:乐观的人会庆幸还有半杯水,而悲观的人是恼怒只5有半杯水;  

6.2、注入数据的方式和类型

Spring中的依赖注入:
    注入的方式有三种:
        第一种:使用构造方法注入
            要求:必须有对应参数列表的构造函数
        第二种:使用set方法注入(XML开发主流)
            要求:提供被注入对象的set方法(不需要get方法)
        第三种:使用注解注入(第二天会学)

    注入的数据类型有三类:
        第一类:基本类型和String
        第二类:其他bean类型
            要求:其他bean指的是在spring的配置文件中定义过的bean,或者是用注解注释过的类。
        第三类:复杂类型(集合类型)
            Array: 数组
            List:
            Map:
            Properties:

数据准备:

@Data
public class DataSourceInfo {
    private String driverClass;
    private String url;
    private String userName;
    private String password;
    private int port;
    private User user;
    private String[] strArr;
    private List<String> list;
    private Map<String,String> map;
    private Properties properties;

    public DataSourceInfo() {
    }

    //用于xml中有参构造注入
    public DataSourceInfo(String driverClass, String url, String userName, String password) {
        this.driverClass = driverClass;
        this.url = url;
        this.userName = userName;
        this.password = password;
    }
}

6.2.1 有参构造注入

配置xml时,类有参构造对应xml中name; 

<!-- 方式1: 有参构造 -->
    <bean id="dataSourceInfo" class="hhy.pojo.DataSourceInfo">
        <constructor-arg name="driverClass" value="com.mysql.jdbc.Driver"></constructor-arg>
        <constructor-arg name="userName" value="root"></constructor-arg>
        <constructor-arg name="password" value="123456"></constructor-arg>
        <constructor-arg name="url" value="jdbc:mysql:///test0908"></constructor-arg>
    </bean>

java限制同样参数只有第一次有效_mybatis_08

//DI注入:有参构造
    @Test
    public void t1() {
        // ClassPathXmlApplicationContext: 读取类路径下的xml文件 类路径: 指的就是resources目录
        //饿汉模式 如注释其他代码只读取xml文件,立即创建对象
        ApplicationContext ac =
                new ClassPathXmlApplicationContext("applicationContext2.xml");
        //2.调用应用上下文对象的API,从IOC容器中获取类对象
        //AccountService service = (AccountService) ac.getBean("AccountService");
        //传入对应类,不用强转
        DataSourceInfo service = ac.getBean("dataSourceInfo", DataSourceInfo.class);
        System.out.println("有参构造 = " + service);
    }

6.2.2 setter方式注入

<!-- 方式2: 通过setter方法注入 -->
    <bean id="setterData" class="hhy.pojo.DataSourceInfo">
        <property name="userName" value="迪迦"></property>
        <property name="password" value="666"></property>
        <property name="url" value="www.dijia.com"></property>
    </bean>
@Test
    public void setter注入() {
        ApplicationContext ac =
                new ClassPathXmlApplicationContext("applicationContext2.xml");
        //2.调用应用上下文对象的API,从IOC容器中获取类对象
        //AccountService service = (AccountService) ac.getBean("AccountService");
        //传入对应类,不用强转
        DataSourceInfo service = ac.getBean("setterData", DataSourceInfo.class);
        System.out.println("setter注入 = " + service);
    }

6.2.3 setter注入其他bean类(User.class)

<bean id="classData" class="hhy.pojo.DataSourceInfo">
        <!-- 注入其他bean类型 name中user为DataSourceInfo类成员,ref中userb对应下面User类属性-->
        <property name="user" ref="userb"></property>
    </bean>
    <!-- 创建user对象存放到IOC容器中 -->
    <bean id="userb" class="hhy.pojo.User">
        <property name="name" value="大幂幂"></property>
        <property name="age" value="18"></property>
    </bean>
@Test
    public void 实体类注入() {
        ApplicationContext ac =
                new ClassPathXmlApplicationContext("applicationContext2.xml");
        //2.调用应用上下文对象的API,从IOC容器中获取类对象
        //AccountService service = (AccountService) ac.getBean("AccountService");
        //传入对应类,不用强转
        DataSourceInfo service = ac.getBean("classData", DataSourceInfo.class);
        System.out.println("实体类注入 = " + service);
    }

6.2.4 setter注入数组、集合、配置

<bean id="moreData" class="hhy.pojo.DataSourceInfo">
        <!-- 注入数组 -->
        <property name="strArr">
            <array>
                <value>宝强</value>
                <value>乃亮</value>
                <value>羽凡</value>
                <value>大郎</value>
            </array>
        </property>
        <!-- 注入list -->
        <property name="list">
            <list>
                <value>蓉蓉</value>
                <value>璐璐</value>
                <value>合合</value>
                <value>莲莲</value>
            </list>
        </property>
        <!--  注入map-->
        <property name="map">
            <map>
                <entry key="name" value="波波"></entry>
                <entry key="age" value="18"></entry>
                <entry key="sex" value="妖"></entry>
            </map>
        </property>
        <!-- 注入properties -->
        <property name="properties">
            <props>
                <prop key="name">迪迦</prop>
                <prop key="age">18</prop>
            </props>
        </property>
    </bean>
@Test
    public void 数组集合配置注入() {
        ApplicationContext ac =
                new ClassPathXmlApplicationContext("applicationContext2.xml");
        //2.调用应用上下文对象的API,从IOC容器中获取类对象
        //AccountService service = (AccountService) ac.getBean("AccountService");
        //传入对应类,不用强转
        DataSourceInfo service = ac.getBean("moreData", DataSourceInfo.class);
        System.out.println("数组集合注入 = " + service);
    }

七、扩展:单例延迟加载

使用lazy-init="true" 

<bean id="test" lazy-init="true" class="hhy.pojo.Test">