【Java中级】26.0 SSM之Spring框架(二)——bean对象管理细节、依赖注入、构造注入和set方法注入

1.0 再次强调

IOC解耦只是削减计算机的耦合,但是不能消除,只能降低。

2.0 新建一个项目
image.png

填充基本的代码:
pom.xml



    4.0.0

    com.edp
    second_project_spring
    1.0-SNAPSHOT
    jar

    
        
            org.springframework
            spring-context
            5.2.3.RELEASE
        
    


bean.xml



    
    
    
    
    


AccountDaoImpl.java

package com.edp.dao.impl;

import com.edp.dao.IAccountDao;

/**
 * @author EdPeng
 * @Title:
 * @Package
 * @Description: 账户持久层实现类
 * @date 2020/2/23下午 5:45
 */
public class AccountDaoImpl implements IAccountDao {
    public void saveAccount() {
        System.out.println("保存了账户。");
    }
}

IAccountDao.java

package com.edp.dao.impl;
import com.edp.dao.IAccountDao;

public class AccountDaoImpl implements IAccountDao {
    public void saveAccount() {
        System.out.println("保存了账户。");
    }
}

IAccountServiceImpl .java

package com.edp.service.impl;

import com.edp.dao.impl.AccountDaoImpl;
import com.edp.service.IAccountService;
import com.edp.dao.IAccountDao;

public class IAccountServiceImpl implements IAccountService {

    public IAccountServiceImpl(){
        System.out.println("IAccountServiceImpl对象创建了!");
    }
    public void saveAccount() {
        System.out.println("IAccountService中的saveAccount方法执行了……");
    }
}

IAccountService .java

package com.edp.service;

public interface IAccountService {
  
    void saveAccount();
}

Client .java

package com.edp.ui;

import com.edp.service.IAccountService;
import com.edp.dao.IAccountDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class Client {
    public static void main(String[] args) {
//1.获取核心容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");

        //根据id获取bean对象
        IAccountService accountService = (IAccountService) applicationContext.getBean("accountService");

        System.out.println(accountService);
        accountService.saveAccount();
    }
}
3.0 spring对bean对象管理的细节——创建bean的三种方式
3.1 第一种方式:使用默认构造函数创建

在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时,采用的就是默认构造函数创造bean对象,此时如果类中没有默认构造函数,则对象无法创建。
比如我们修改IAccountServiceImpl .java

public class IAccountServiceImpl implements IAccountService {

    public IAccountServiceImpl(String value){
        System.out.println("IAccountServiceImpl对象创建了!");
    }
    public void saveAccount() {
        System.out.println("IAccountService中的saveAccount方法执行了……");
    }
}

将原来的默认构造函数修改为有参构造函数,意味着构造函数没有了,运行Client类:


image.png

而且,这样没有无参构造函数的情况下,bean.xml都在会编译环境下报错:


image.png
3.2 第二种方式:使用普通工厂中的方法创建对象(使用某个类中的方法创建,并存入spring容器)

这个方法解决加入需要配置的类在class字节码中(即集成的jar包中的类。)
创建一个模拟的工厂类


image.png

InstanceFactory.java

package com.edp.factory;

import com.edp.service.IAccountService;
import com.edp.service.impl.IAccountServiceImpl;

/**
 * @author EdPeng
 * @Title: 模拟一个工厂类
 * @Package
 * @Description:模拟工厂类(该类可能是存在于jar包中的,我们无法通过修改源码的方式来提供默认构造函数)
 * @date 2020/2/29下午 5:46
 */
public class InstanceFactory {
    public IAccountService  getAccountService(){
        return  new IAccountServiceImpl();
    }
}

这时候,bean.xml的配置如下:





    
   


运行:


image.png

成功运行,证明这样配置没有问题。


image.png
3.3 第三种方式:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)

新建一个StaticFactory.java类:

package com.edp.factory;

import com.edp.service.IAccountService;
import com.edp.service.impl.IAccountServiceImpl;

/**
 * @author EdPeng
 * @Title:模拟一个工厂类
 * @Package
 * @Description:模拟工厂类(该类可能是存在于jar包中的,我们无法通过修改源码的方式来提供默认构造函数)
 * @date 2020/2/29下午 9:00
 */
public class StaticFactory {

    public static IAccountService getAccountService() {
        return new IAccountServiceImpl();
    }
}

bean.xml配置也很简单:





    


运行:


image.png

注意,上面看上去两个Factory类其实已经耦合了,但是我们只是在模拟jar包中的类,jar包中有普通方法也有静态方法,spring都给我们提供配置的方法。

在jar包中的类都是“.class”文件,是无法改动的,当我们需要获得某个方法的返回值存入spring容器中,就需要用到以上3种中的第2、3种bean对象创建方法。

4.0 spring对bean对象管理的细节——bean对象的作用范围
4.1 spring的bean对象默认情况下就是单例的。

重置一下bean.xml:





    


修改Client.java类测试一下:

public class Client {
    public static void main(String[] args) {
//1.获取核心容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");

        //根据id获取bean对象
        IAccountService accountService = (IAccountService) applicationContext.getBean("accountService");
        IAccountService accountService2 = (IAccountService) applicationContext.getBean("accountService");
        System.out.println(accountService);
        System.out.println(accountService2);
        
        accountService.saveAccount();
        accountService2.saveAccount();
        
        System.out.println(accountService==accountService2);
    }
}

执行:


image.png
4.2 bean标签的scope属性

修改bean.xml文件





    
    


执行:

image.png

其中global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session,一般情况下接触不到这个方面,但在此做以解释。

当我们用户访问服务器时,服务器往往都有一个访问地址,比如“192.168.0.1”,但在超大型项目中,一个服务器往往扛不住这么大的数据访问量,当在集群环境时,往往会有多个服务器ip地址供用户访问。

当我们访问一个大型网站,比如淘宝时,首先访问的是“https://www.taobao.com/”,用户打开的是一个login.jsp页面,然后网页就会寻找空闲的服务器ip地址提供数据服务。(专业名词叫“负载均衡”)

在用户注册账户时,将由一个空闲的服务器进行数据存储,但当用户登录的时候,服务器的情况已经瞬息万变,再次访问的时候,注册时的物理服务器已经不是现在登录的物理服务器,而这个时候,新的服务器不会存储用户的账户信息。

这时候就需要一个全局的集群环境的会话范围,能够让用户找到服务器所在信息的调度。这个会话模式在spring中的配置属性就是global-session。

5.0 spring对bean对象管理的细节——bean对象的生命周期

bean对象的生命周期

  • 单例对象
  • 出生:当容器创建时对象出生
  • 活着:只要容器还在,对象一直活着
  • 死亡:容器销毁,对象消亡
  • 总结:单例对象的生命周期和容器相同
  • 多例对象
  • 出生:当我们使用对象时,spring框架为我们创建
  • 活着:对象在使用过程中,一直活着
  • 死亡:当对象长时间不用,且没有别的对象引用时,由java的垃圾回收器回收
6.0 Spring的依赖注入
6.1 什么是依赖注入(Dependency Injection)?
  • IOC的作用:降低程序间的耦合(依赖关系),也就是降低程序间的依赖关系,而依赖关系的管理,以后都交给spring来维护。
  • 在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明。
  • 而针对这依赖关系的维护,就称之为依赖注入
6.2 依赖注入分为三类

依赖注入能注入的数据分为三类:

  • 基本类型和String
  • 其他bean类型(在配置文件中或者注解配置过的bean)
  • 复杂类型/集合类型
6.3 依赖注入的注入方式

总共有3种:

  • 第1种:使用构造函数提供
  • 第2种:使用set方法提供
  • 第3种:使用注解提供
7.0 使用构造注入

首先在类中,定义一些可注入的变量。
修改IAccountServiceImpl.java

public class IAccountServiceImpl implements IAccountService {

    //如果是经常变换的数据,并不适用于注入的方式
    private String name;
    private Integer age;
    private Date birthday;

    public IAccountServiceImpl(String name, Integer age, Date birthday) {
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public void saveAccount() {
        System.out.println("IAccountService中的saveAccount方法执行了……"+name+" , "+age+" , "+birthday);
    }
}

当然,我们不应该关注这些变量是不是应该出现在Dao层,只是说作为一个对象,以一种方便理解的方式命名。
配置bean.xml





    
    
        
        
        

    

    
    


运行:

image.png

发现,没有出现乱码,这就是Spring的强大之处:能把涉及到的可能的它能处理的细节都提前替我们处理。

8.0 set方法注入

注入只需要set方法,不需要get方法。
创建一个com.edp.service.impl.IAccountServiceImpl2 .java

public class IAccountServiceImpl2 implements IAccountService {

    //如果是经常变换的数据,并不适用于注入的方式
    private String name;
    private Integer age;
    private Date birthday;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public void saveAccount() {
        System.out.println("IAccountService中的saveAccount方法执行了……"+name+" , "+age+" , "+birthday);
    }
}

配置bean.xml





    
    

    
    
        
        
        
    

修改Client.java

public class Client {
    public static void main(String[] args) {
//1.获取核心容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");

        IAccountService accountService = (IAccountService) applicationContext.getBean("accountService2");
        accountService.saveAccount();
    }
}

执行:


image.png

set方法注入的优势就是就是构造函数注入的弊端,当然set方法注入的弊端就是构造函数注入的优势,但我们更常用的方式是set方法注入。

9.0 复杂类型的注入

创建com.edp.service.impl.IAccountServiceImpl3.java

package com.edp.service.impl;

import com.edp.service.IAccountService;

import java.util.*;

public class IAccountServiceImpl3 implements IAccountService {

    private String[] myStr;
    private List myList;
    private Set mySet;
    private Map myMap;
    private Properties myProps;

    public void setMyStr(String[] myStr) {
        this.myStr = myStr;
    }

    public void setMyList(List myList) {
        this.myList = myList;
    }

    public void setMySet(Set mySet) {
        this.mySet = mySet;
    }

    public void setMyMap(Map myMap) {
        this.myMap = myMap;
    }

    public void setMyProps(Properties myProps) {
        this.myProps = myProps;
    }

    @Override
    public String toString() {
        return "IAccountServiceImpl3{" +
                "\n myStr=" + Arrays.toString(myStr) +
                ",\n myList=" + myList +
                ",\n mySet=" + mySet +
                ",\n myMap=" + myMap +
                ",\n myProps=" + myProps +
                '}';
    }

    public void saveAccount() {
        System.out.println( toString()); 
    }
}

修改bean.xml


image.png




    
        
            
                AAA
                BBB
                CCC
            
        
    


修改Client.java

public class Client {

    public static void main(String[] args) {
//1.获取核心容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");

        IAccountService accountService = (IAccountService) applicationContext.getBean("accountService3");
        accountService.saveAccount();
    }
}

执行:


image.png

继续完善bean.xml





    
        
            
                AAA
                BBB
                CCC
            
        

        
            
                DDD
                EEE
                FFF
            
        

        
            
                GGG
                HHH
                III
            
        

        
            
                
                
                    bbbb
                
                
            
        

        
            
                
                
                
            
        

    


执行:


image.png

接下来,我们如下操作,修改bean.xml:





    
        
            
                AAA
                BBB
                CCC
            
        
        
            
                DDD
                EEE
                FFF
            
        
        
            
                GGG
                HHH
                III
            
        
        
            
                
                
                
            
        
        
            
                
                
                    bbbb
                
                
            

        
    


执行:


image.png

将标签内的对应关系打乱,发现还是可以运行。

复杂类型(集合类型)的注入,用于给List结构集合注入的标签有:list、array、set;用于给map结构集合注入的标签有:map、props,结构相同的,标签可以互换。

10.0 使用注解注入

【Java中级】27.0 SSM之Spring框架(三)——注解注入

END

你可能感兴趣的:(【Java中级】26.0 SSM之Spring框架(二)——bean对象管理细节、依赖注入、构造注入和set方法注入)