Java开发【Spring之IOC详解第一篇(xml开发、常用API、ben标签、DI依赖注入)】

文章目录

一、 Spring概述

Sping官网

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

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

Spring能将开源世界中众多优秀的第三方框架进行集成比如mybatis等

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

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

##Spring的发展历史:
1997年IBM提出了EJB的思想
1998年,SUN制定开发标准规范EJB1.0
1999年,EJB1.1发布
2001年,EJB2.0发布
2003年,EJB2.1发布
2006年,EJB3.0发布
Rod Johnson(spring之父)
	Expert One-to-One J2EE Design and Development(2002)
	阐述了J2EE使用EJB开发设计的优点及解决方案
	Expert One-to-One J2EE Development without EJB(2004)
	阐述了J2EE开发不使用EJB的解决方式(Spring雏形)
2017年9月份发布了spring的最新版本--spring 5.0通用版(GA)

##Spring特点
【俗称Spring为开发架构的`粘合剂`。】
Spring 出现是为了解决JavaEE 实际问题:
1、方便解耦,简化开发  (IOC)
Spring就是一个大工厂【容器】,可以将所有对象创建和依赖关系维护交给Spring管理,
Spring工厂是用于生成bean
2、AOP编程的支持
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
3、声明式事务的支持
只需要通过配置就可以完成对事务的管理,而无需手动编程
4、方便程序的测试
Spring对Junit4支持,可以通过注解方便的测试Spring程序
5、方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
6、降低JavaEE API的使用难度
Spring 对JavaEE开发中非常难用的一些API,如:JDBC、JavaMail、远程调用等,都提供了封装,使这些API应用难度得到降低
  
##Spring体系结构
测试(Test)模块
核心容器(Core Container)
AOP(Aspect Oriented Programming)模块
数据访问/集成(Data Access/Integration)层
Web层

##Spring核心 
Spring为企业级开发提供了丰富的功能,这些功能的底层都依赖于它的两个核心特性:
1、控制反转(Inversion of Control,**IOC**)
2、面向切面编程(aspect-oriented programming,**AOP**)

# 那么IOC和AOP是一种技术吗?不是的!他们是一种思想 

在这里插入图片描述

二、高内聚低耦合【了解】

1、耦合与内聚概述
`代码的书写原则:高内聚低耦合

##耦合与内聚的概念
耦合(Coupling):代码书写过程中所使用技术的结合紧密度程序之间的依赖程度,
用于衡量软件中【各个模块之间的联系程度】。

内聚(Cohesion):代码书写过程中单个模块内部各组成部分间的联系,
用于衡量软件中各个【功能模块内部的功能联系】。

程序书写的原则:【高内聚,低耦合】。就是同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却不要那么紧密

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

##耦合的弊端:
独立性差  可重用性不高  维护成本高
2、解耦过程(分析javaweb开发)

1、服务层与持久层存在紧耦合;
2、我们加入工厂模式后,服务层与持久层完成解耦,但是工厂类与持久层存在紧耦合;
3、于是通过工厂模式和静态资源配置将代码的耦合降到最低;
最终方案:工厂+反射+配置文件 --》解耦

3、解耦方案【工厂+反射+配置文件】
1)配置文件 bean.properties
# 格式:key=value
# key: 自定义,一般为当前类实现的接口的名称
# value: 当前需要使用的类的全限定名
userDao=com.exmple.dao.impl.UserDaoImpl
userService=com.exmple.service.UserServiceImpl
2)工厂模式-bean单实例 [饿汉模式/懒汉模式]
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;

/**
 * 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);
           -------------------------------------------------------------
            // 立即加载的思想创建bean对象 【饿汉模式】
            Object obj = Class.forName(value).newInstance();
            // 将创建好的对象存放到beansMap容器中
            beansMap.put(key,obj);
           -------------------------------------------------------------
        }
        // 测试是否解析到了数据
        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;
    }
}

3)工厂类代码-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;
    }
}

三、Spring核心之IOC

1、IOC概念和作用

IOC 全称为 Inversion of Control,翻译为 “控制反转”。
【1】控制什么
控制对象的创建和销毁
【2】反转什么
反转创建对象的控制权,将(创建和销毁)对象的控制权交给IOC容器
【3】IOC的作用
解耦
传统方式创建对象:  new 对象(); 【主动创建】
IOC方式创建对象: 找容器(本质上就是一个Map集合)【被动接收】 
分析解耦的过程:
通过标记(标记就是配置文件中的key)找工厂,工厂帮我们创建对应的类对象,并返回给我们使用。
当前类可以选择主动出击(new的方式)创建对象,但是此时耦合度高。
此时把主动创建改成被动接收,由工厂对象为当前类生产所必须的关联对象,此时降低了两个类的依赖关系。

2、IOC解耦分析

我们知道在面向对象设计的软件系统中,它的底层都是由N个对象构成的,

各个对象之间通过相互合作,最终实现系统地业务逻辑 ,如图所示:
在这里插入图片描述

IOC理论提出的观点:借助于“第三方”实现具有依赖关系的对象之间的解耦。 如图所示:

在这里插入图片描述

由于引进了中间位置的“第三方”,也就是IOC容器,使得A、B、C、D这4个对象没有了耦合关系,

齿轮之间的传动全部依靠“第三方”了,全部对象的控制权全部上缴给“第三方”IOC容器。

所以,IOC容器成了整个系统的关键核心,它起到了一种类似“粘合剂”的作用,

把系统中的所有对象粘合在一起发挥作用,如果没有这个“粘合剂”,对象与对象之间会彼此失去联系,

这就是有人把IOC容器比喻成“粘合剂”的由来。

我们把上图中间的IOC容器隐藏,然后再来看看这套系统 :
在这里插入图片描述

我们现在看到的画面,就是我们要实现整个系统所需要完成的全部内容。这时候,A、B、C、D这4个对象之间已经没有了耦合关系,彼此毫无联系,这样的话,当你在实现A的时候,根本无须再去考虑B、C和D了,对象之间的依赖关系已经降低到了最低程度。

3、手写IOC【工厂模式->解耦】

我们通过使用工厂模式,实现了表现层——业务层、业务层——持久层的解耦。 
	【实现思路】:
		工厂+反射+配置文件
	【核心思想】:
		【1】读取配置文件中类的全限定名通过反射机制创建对象。  
		【2】把创建出来的对象事先都存起来,当我们使用时可以直接从存储容器中获取。 
			存哪去?   
				由于我们是很多对象,肯定要找个集合来存。这时候有 Map 和 List 供选择。      
				到底选 Map 还是 List 就看我们有没有查找需求。有查找需求,选 Map。   
				所以我们的答案就是在应用加载时,创建一个 Map,用于存放bean对象。
				我们把这个 map 称之为容器。  
			什么是IOC工厂  
				事先加载bean,并且提供一个直接获取bean的方法。
			什么是控制反转    
				主动new对象方式--被动从容器中获取
代码演示
1、创建项目及J2EE三层架构
2、创建pojo对象
3、创建dao对象
4、创建service对象
5、创建controller对象
6、创建properties文件
7、factory工厂类【重点】
	【1】事先创建集合容器
	【2】事先加载properties文件内容
	【3】反射机制实例化bean对象,并且放入集合容器
	【4】公共的访问方法
projo
Account类
/**
 * @Description:账户实体类
 */
public class Account {

    //账户编号
    private String Id;

    //账户所有者
    private String accountName;

    //账户余额
    private Float money;

    public Account() {
    }

    public String getId() {
        return Id;
    }

    public void setId(String id) {
        Id = id;
    }

    public String getAccountName() {
        return accountName;
    }

    public void setAccountName(String accountName) {
        this.accountName = accountName;
    }

    public Float getMoney() {
        return money;
    }

    public void setMoney(Float money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "Id='" + Id + '\'' +
                ", accountName='" + accountName + '\'' +
                ", money=" + money +
                '}';
    }
}

dao层
AccountDao接口
/**
 * @Description:账户dao层
 */
public interface AccountDao {

    /**
     * @Description 新增
     */
    void saveAccount();

    /**
     * @Description 删除
     */
    void delAccount();

    /**
     * @Description 修改
     */
    void updateAccout();

    /**
     * @Description 查询
     */
    void findAccount();


}



AccountDaoImpl实现类
/**
 * @Description:
 */
public class AccountDaoImpl implements AccountDao {

    private static  Account account;

    static {
        account = new Account();
        account.setId("010101");
        account.setAccountName("张三");
        account.setMoney(2000F);
    }
    @Override
    public void saveAccount() {
        System.out.println("保存:"+account.toString());
    }

    @Override
    public void delAccount() {
        System.out.println("删除:"+account.toString());
    }

    @Override
    public void updateAccout() {
        System.out.println("修改:"+account.toString());
    }

    @Override
    public void findAccount() {
        System.out.println("查询:"+account.toString());
    }
}



servic层
AccountService接口
/**
 * @Description:用户业务层接口
 */
public interface AccountService {

    /**
     * @Description 新增
     */
    void saveAccount();

    /**
     * @Description 删除
     */
    void delAccount();

    /**
     * @Description 修改
     */
    void updateAccout();

    /**
     * @Description 查询
     */
    void findAccount();

    void setAccountDao(AccountDao accountDao);
}



AccountServiceImpl实现类
/**
 * @Description:用户业务层接口实现
 */
public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

    @Override
    public void saveAccount() {
        accountDao.saveAccount();
    }

    @Override
    public void delAccount() {
        accountDao.delAccount();
    }

    @Override
    public void updateAccout() {
        accountDao.updateAccout();
    }

    @Override
    public void findAccount() {
        accountDao.findAccount();
    }

    @Override
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }
}



factory层
BeanFactory工厂类

在resources目录中建立db.properties

accountDao = com.example.spring.dao.impl.AccountDaoImpl
accountService = com.example.spring.service.impl.AccountServiceImpl
/**
 * @Description:bean工厂
 */
public class BeanFactory {

    //1、事先存储容器
    private static Map<String, Object> map = new HashMap<>();
    //2、加载配置文件
    static {
        Properties properties = new Properties();
        try {
            properties.load(BeanFactory.class.getClassLoader()
                            .getResourceAsStream("db.properties"));
            Enumeration<?> enumeration = properties.propertyNames();
            while (enumeration.hasMoreElements()) {
                String key = (String) enumeration.nextElement();
                String value = (String) properties.get(key);
                //3、实例化bean
                Object beanObject = Class.forName(value).newInstance();
                //4、放入容器
                map.put(key,beanObject);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }

    //5、公共方法获得bean
    public static Object getBean(String calssName){
       return map.get(calssName);
    }
}
controller层
ClientController测试类
/**
 * @Description:
 */
public class ClientController {
    
   @Test
    public void saveAccount() {
       AccountService accountService = (AccountService) BeanFactory.getBean("accountService");
       accountService.setAccountDao((AccountDao) BeanFactory.getBean("accountDao"));
       accountService.saveAccount();
    }

}


4、IOC入门案例

案例分析
##思考
1、我们采用工厂+反射的方式实现了手写IOC工厂,那么spring-IOC的工厂是不是也类似?
	spring框架提供了一个大工厂接口:ApplicationContext==》Beanfactroy

2、手写IOC中的配置文件类型是properties,那么spring-IOC的配置采取的是什么类型?
    spring使用XML格式的文件存储配置
	<bean id="唯一标识" 
          class="实现类的全限定名">
	</bean>

3、spring-IOC是怎么加载配置文件的呢?
	ApplicationContext工厂使用ClassPathXmlApplicationContext加载配置文件

4、手写IOC中的BeanFactory提供一个公共获得bean的方法,那spring-ioc是不是有类似的方法?
	ApplicationContext工厂使用getBean()方法,用于根据bean的名称获取实例化对象

##目标
1、掌握spring-IOC工厂的创建
2、掌握bean标签的基本配置
3、掌握spring-IOC工厂获得实例化对象的方式

##实现
步骤:
1、导入依赖
2、编写bean.xml文件替换bean.properties文件
3、使用ClassPathXmlApplicationContext加载bean.xml配置文件
4、使用ApplicationContext工厂的getBean()方法获得bean对象
代码演示
导入依赖pom.xml
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example.spring</groupId>
  <artifactId>spring-day01-04spring-ioc-xml</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>spring-day01-04spring-ioc-xml</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <!-- spring版本 -->
    <spring.version>5.1.11.RELEASE</spring.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>
  </dependencies>

  <build>
  </build>
</project>

Spring配置文件bean.xml
<!--文件的类型 版本 编码-->
<?xml version="1.0" encoding="UTF-8"?>
<!--Spring的命名空间 -->
<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作用:声明类交给spring容器
        属性:	id: 唯一标识 class:全路径限定名称
        细节:默认使用无参构造函数实例化
	-->
    <bean id="accountDao" class="com.example.spring.dao.Impl.AccountDaoImpl"/>

    <bean id="accountService" 		 class="com.example.spring.service.Impl.AccountServiceImpl"/>
    
</beans>
改造AccountService
/**
 * @Description:账户操作接口
 */
public interface AccountService {

    /**
     * @Description 创建账户
     */
    void createAccount();

    /**
     * @Description 传入accountDao
     * @param 
     * @return 
     */
    void setAccountDao(AccountDao accountDao);
}

/**
 * @Description:账户操作实现
 */
public class AccountServiceImpl implements AccountService {

    AccountDao accountDao ;

    @Override
    public void createAccount() {
        accountDao.createAccount();
    }

    @Override
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }
}

改造ClientController
/**
 * @Description:客户端
 */
public class ClientContrller {

    /**
     * ApplicationContext:spring-IOC容器
     * ClassPathXmlApplicationContext:容器实现类,加载配置文件
     * applicationContext.getBean:获得容器中的bean对象
     */
    @Test
    public void createAccount(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
        AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao");
        AccountService accountService = (AccountService) applicationContext.getBean("accountService");
        accountService.setAccountDao(accountDao);
        accountService.createAccount();
    }
}

四、Spring之IOC工厂类【了解】

IDEA中查看类的层级结构,快捷方式: ctrl + alt + U
在这里插入图片描述

BeanFactory:
它是spring中ioc容器的顶层接口,ApplicationContext只是它的子接口。
提供创建容器中对象的时机,使用延迟加载(懒加载)的思想。

ApplicationContext:
继承了BeanFactory的加载方式,而且还扩展出来了立即加载思想的创建容器的方式。
每次在使用时它才真正的创建对象。

1、BeanFactory接口

1)作用

Spring里面最顶层的接口,提供了最简单的容器的功能,只定义了实例化对象和拿对象的功能;

2)方法
public interface BeanFactory {
    //对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象
    String FACTORY_BEAN_PREFIX = "&";
    
    //根据bean的名字,在IOC容器中得到bean实例,
    *Object getBean(String name) throws BeansException;
    
    //根据bean的名字,在IOC容器中得到bean实例,args:显式参数(必须为非单例模式)
    Object getBean(String name, Object... args) throws BeansException;
    
    //根据bean的名字获得对象,并转换为Class类型
    *<T> T getBean(String name, Class<T> requiredType);
    
    //根据bean的类型获得对象(必须是拥有唯一实现类)
    *<T> T getBean(Class<T> requiredType) throws BeansException;
    
    //根据bean的类型获得对象,args:显式参数
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
    
    //这里提供对bean的检索,看看是否在IOC容器有这个名字的bean
    *boolean containsBean(String name);
    
    //判断这个bean是不是单例 
    *boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    
    //同时判断这个bean是不是多例 
    *boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    
    //这里得到bean实例的Class类型  
    *Class<?> getType(String name) throws NoSuchBeanDefinitionException;
    
    //这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来  
    *String[] getAliases(String name);

2、ApplicationContext接口

1)作用
应用上下文,继承BeanFactory接口,它是Spring的更高级的容器,提供了更多的有用的功能;
1) 国际化(MessageSource)
2) 访问资源,如URL和文件(ResourceLoader)
3) 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层  
4) 消息发送、响应机制(ApplicationEventPublisher)
5) AOP(拦截器)
2)实现类

ClassPathXmlApplicationContext

从类的根路径下加载配置文件  【推荐使用这种】

FileSystemXmlApplicationContext

从硬盘路径下加载配置文件

AnnotationConfigApplicationContext

基于Java的配置类加载Spring的应用上下文配置

在这里插入图片描述

@Test
    public void createAccountTest(){
        //加载配置文件
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("bean.xml");
        //获得bean
        AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao");
        AccountServic accountServic = (AccountServic) applicationContext.getBean("accountServic");
        //set方法指定accountDao
        accountServic.setAccountDao(accountDao);
        //创建账户
        accountServic.createAccount();
    }

3、接口容器的加载顺序

代码演示
##思考
BeanFactory、ApplicationContext都是容器,那么他们的加载顺序有什么不同?

##目的
了解BeanFactory和ApplicationContext的加载顺序

##实现
步骤:
	1、观察ApplicationContext的加载方式
	2、观察BeanFactory的加载方式
	3、比较一下加载顺序
改造AccountDaoImpl

在AccountDaoImpl中增加构造函数

public AccountDaoImpl() {
    System.out.println("AccountDaoImpl的实例已经创建");
}
改造ClientController
/**
 * @Description:测试
 */
public class ClientController {
   @Test
    public void saveAccount() {

       /**
        * Spring-IOC容器:ApplicationContext
        * 构建方式:通过ClassPathXmlApplicationContext加载配置文件
        * 使用bean:getBean
        */
       System.out.println("======ApplicationContext开始创建容器=====");
       ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
       System.out.println("======ApplicationContext创建容器完成=====");
       applicationContext.getBean("accountDao");

       System.out.println("======分割线==========");

       System.out.println("======BeanFactory开始创建容器=====");
       Resource resource = new ClassPathResource("bean.xml");
       BeanFactory beanFactory = new XmlBeanFactory(resource);
       System.out.println("======BeanFactory创建容器完成=====");
       beanFactory.getBean("accountDao");
    }

}

【3.4】加载顺序
在这里插入图片描述

小结
1.BeanFactory是顶层接口
2.ApplicationContext是子接口
3.它们最大的区别是创建对象的时间不一样(单例的):
	【BeanFactory】采用的是延迟加载的思想。即什么时候使用对象,什么时候创建
	【ApplicationContext】采用立即创建的思想。即一加载配置文件,立即就创建

五 bean标签详解【重点】

1、bean标签作用

bean作用:用于配置对象让spring 来创建的。 
【细节】
默认情况下调用类的无参构造函数。

2、bean标签基本属性

属性说明
idbean的唯一标识名称
class实现类的全限定名称
namebean的名称
* 多个别名使用 ”,” 分割
* bean与bean的别名不可以重复

入门案例中我们已经基本使用过bean.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="accountDao" name="accountDao2,accountDao3" class="com.example.spring.dao.impl.AccountDaoImpl"></bean>

    <bean id="accountService"  class="com.example.spring.service.impl.AccountServiceImpl"></bean>

</beans>

3、bean标签作用范围

属性说明
scope指定对象的作用范围。
* singleton 【默认】: 单例,所有的请求都用一个对象来处理
* prototype : 多例,每个请求用一个新的对象来处理
* request : WEB 项目中,将对象存入到 request 域中.
* session : WEB 项目中,将对象存入到 session 域中.
* global session : WEB 项目中,应用在集群环境.如果没有集群环境那么相当于session

global session图解
在这里插入图片描述

代码演示
## 【1】思考
单例、多例他们分别在什么场景中使用?他们有什么区别?
spring默认单例,不需要修改,不要随意定义成员变量。
多例:资源共用

## 【2】目标
1、掌握scope的单例、多例的配置
2、掌握单例和多例的区别

## 步骤:
	1、改造ClientController多次获得对象
	2、装配bean到spring的IOC容器中,修改bean标签中scope的作用域
	3、观察不同作用域下获得的对象内存地址是否一致
改造ClientController
/**
 * @Description:测试
 */
public class ClientController {
    @Test
    public void saveAccount() {
        /**
         * Spring-IOC容器:ApplicationContext
         * 构建方式:通过ClassPathXmlApplicationContext加载配置文件
         * 使用bean:getBean
         */
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
        AccountDao accountDaoA = (AccountDao) applicationContext.getBean("accountDao");
        AccountDao accountDaoB = (AccountDao) applicationContext.getBean("accountDao");

        System.out.println("accountDaoA的内存地址:"+accountDaoA.hashCode());
        System.out.println("accountDaoB的内存地址:"+accountDaoB.hashCode());

    }

}


Bean【默认:singleton】

使用bean标签在bean.xml中装配accountDao的scope=“singleton”

<?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">
    
    <!--创建AccountDaoImpl-->
    <bean id="accountDao" class="com.example.spring.dao.impl.AccountDaoImpl" scope="singleton"></bean>

    <!--创建AccountServicImpl-->
    <bean id="accountServic" class="com.example.spring.service.impl.AccountServicImpl"></bean>
</beans>
singleton运行结果

在这里插入图片描述

bean【多例:prototype】

使用bean标签在bean.xml中装配accountDao的scope=“prototype”

<?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="accountDao" class="com.example.spring.dao.impl.AccountDaoImpl" scope="prototype"></bean>

    <!--创建AccountServicImpl-->
    <bean id="accountServic" class="com.example.spring.service.impl.AccountServicImpl"></bean>
</beans>
prototype运行结果

在这里插入图片描述

bean作用域小结
# 1、单例和多里创建方式、内存地址
	【singleton单例】:所有请求只创建一个对象,内存地址相同
	【prototype多例】:每次请求都创建新的对象,内存地址不同
# 2、为什么使用单例?
	节省内存、CPU的开销,加快对象访问速度
# 3、为什么使用多例?
	如果你给controller中定义很多的属性,那么单例肯定会出现竞争访问,
	不要在controller层中定义成员变量(dao、service注入的bean)
	当web层的对象是有状态的时候 使用多例,防止并发情况下的互相干扰
# 4、单例、多例的场景
	单例===》spring中的Dao,Service,controller都是单例的
	多例====》struts2的Action是多实例

4、bean标签生命周期

# sevlet的生命周期
1.被创建:执行init方法,只执行一次

  --默认情况下,第一次被访问时,Servlet被创建,然后执行init方法;

  --可以配置执行Servlet的创建时机;

2.提供服务:执行service的doGet、doPost方法,执行多次

3.被销毁:当Servlet服务器正常关闭时,执行destroy方法,只执行一次

spring-IOC中不同作用域中bean的生命周期

作用范围生命周期
单例scope=“singleton”所有请求只创建一次对象出生:应用加载,创建容器,对象就被创建
活着:只要容器在,对象一直活着。
死亡:应用卸载,销毁容器,对象就被销毁
多例scope=“prototype”每次请求都创建对象出生:应用加载,创建容器,对象使用创建
活着:只要容器在,对象一直活着。
死亡:对象长时间不用,被垃圾回收器回收

生命周期方法相关标签属性

init-method  #指定类中的初始化方法名称
destroy-method #指定类中销毁方法名称
代码演示
步骤:
	1、创建LifecycBeanServic类
	2、装配LifecycBeanServic
	3、创建测试类
	4、观察默认单例下生命周期
	5、观察多例下生命周期
LifecycleService类
/**
 * @Description:生命周期测试服务
 */
public class LifecycleService {

    public LifecycleService() {
        System.out.println("LifecycleService构造");
    }

    public void init(){
        System.out.println("LifecycleService初始化");
    }

    public void doJob(){
        System.out.println("LifecycleService工作中");
    }

    public void destroy(){
        System.out.println("LifecycleService销毁");
    }
}

单例模式下生命周期

配置bean.xml,装配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">

    <bean id="lifecycBeanServic" class="com.example.spring.service.LifecycBeanServic"
          scope="singleton" init-method="init" destroy-method="destory"></bean>
</beans>
创建ClientController
/**
 * @Description:客户端
 */
public class ClientContrller {

    /**
     * ApplicationContext:spring-IOC容器
     * ClassPathXmlApplicationContext:容器实现类,加载配置文件
     * applicationContext.getBean:获得容器中的bean对象
     */
    @Test
    public void createAccount(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
        System.out.println("applicationContext初始化完成");
        LifecycleService lifecycleService = applicationContext.getBean("lifecycleService", LifecycleService.class);
        lifecycleService.doJob();
        System.out.println("applicationContext容器关闭");
        ((ClassPathXmlApplicationContext) applicationContext).close();

    }
}
多例模式下生命周期

将配置文件中的单例修改为多例

<?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="lifecycBeanServic" class="com.example.spring.service.LifecycBeanServic"
          scope="prototype"  init-method="init" destroy-method="destory"></bean>
</beans>

再次执行方法发现,LifecycleBean被延迟加载了,

并且只执行了初始化方法-init,没有执行销毁方法destory。

bean生命周期小结
# 单例对象:scope="singleton"
	一个应用只有一个对象的实例。它的作用范围就是整个应用。
	生命周期:
		对象出生:当应用加载,创建容器时,对象就被创建了。
		对象活着:只要容器在,对象一直活着。
		对象死亡:当应用卸载,销毁容器时,对象就被销毁了。

# 多例对象:scope="prototype"
	每次访问对象时,都会重新创建对象实例。
	生命周期:
		对象出生:当使用对象时,创建新的对象实例(getBean)。
		对象活着:只要对象在使用中,就一直活着。
		对象死亡:当对象长时间不用时,被垃圾回收器回收。

# 生命周期方法:
init-method:指定类中的初始化方法名称 
destroy-method:指定类中销毁方法名称

5、bean的实例化方式

bean的实例化方式有以下3种:

  • bean缺省构造函数创建
  • 静态factory方法创建
  • 实例化factory方法创建(通过非常发非静态方法创建)
1)缺省构造函数方式
配置方式
<!--空的构造方法实例化-->
<bean id="account" class="com.example.spring.pojo.Account"></bean>
注意事项
缺省构造函数实例化Bean的方式是Spring中默认的实例化方式;
被实例化的Bean中必须有无参构造;
2)静态工厂方法方式

步骤一:创建静态工厂

/**
 * @Description:静态工厂
 */
public class StaticFactory {

    public static Account createAccount(){
        System.out.println("静态工厂构建!");
        return  new Account();
    }
}

步骤二:配置静态工厂

<!--静态工厂实例化-->
    <bean id="accountStatic" class="com.example.spring.factory.StaticFactory" factory-method="createAccount"></bean>
3)实例工厂方法方式

步骤一:创建实例工厂

/**
 * @Description:实例化工厂
 */
public class InstanceFactory {

    public Account createAccount(){
        System.out.println("实例工厂构建!");
        return  new Account();
    }
    
    public User createUser(){
        System.out.println("实例工厂构建!");
        return  new User();
    }
}

步骤二:配置方式
<!--实例化工厂实例化-->
<bean id="instanceFactory" class="com.example.spring.factory.InstanceFactory"></bean>
<bean id="accountInstance" factory-bean="instanceFactory" factory-method="createAccount"></bean>
bean实例化小结
#【缺省构造函数方式】
说明:
在默认情况下会根据默认缺省构造函数来创建类对象。如果bean中没有默认无参构造函数,将会创建失败。
场景:
当各个bean的业务逻辑相互比较独立时,或者与外界关联较少时可以使用

#【静态工厂方法方式】
说明:
使用工厂中的静态方法创建对象,并装配到 spring的IOC 容器中。
id 属性:指定 bean 的 id,用于从容器中获取   
class 属性:指定静态工厂的全限定类名   
factory-method 属性:指定生产对象的静态方法
场景:
统一管理各个bean的创建
各个bean在创建之前需要相同的初始化处理,则可用静态factory方法进行统一的处理

#【实例工厂方法方式】
说明:
使用工厂中的实例方法创建对象,并装配到容器中。
1、先把实例工厂做为一个bean装配到 spring容器中。   
2、然后再引用工厂bean 来调用里面的非静态方法来获取bean并装配到spring的IOC容器中。   
factory-bean 属性:用于指定实例工厂 bean 的 id。   
factory-method 属性:用于指定实例工厂中创建对象的方法
场景:
1.实例factory方法也作为业务bean控制,可以用于集成其他框架的bean创建管理方法,
2.能够使bean和factory的角色互换

6、bean标签配置小结

	#1、bean标签的作用:把自己的类的对象的创建交给Spring管理

	#2、基本配置:
	    id:IOC工厂中bean实例的唯一标识
		class:实现类的全限定路径
		name:别名 

	#3、bean的作用域:
		单例:默认,IOC工厂创建后,立即创建bean的实例对象(bean只会被实例化一次) 
		多例:scope="prototype"  每次从工厂中获取bean的时候,都会创建一个新的对象返回  
		
    #4、bean的生命周期:
		单例:
			创建:IOC工厂创建后,立即创建bean的实例对象
			初始化:对象创建完成之后立刻调用
			工作...................
			销毁:IOC工厂卸载,单例bean销毁
		多例:
			出生:应用加载,创建容器,对象使用创建<br/>
			活着:只要容器在,对象一直活着。<br/>
			死亡:对象长时间不用,被垃圾回收器回收

 	#5、bean实例化的3种方式:获取对象
        bean缺省构造函数创建    
        静态factory方法创建   
        实例化factory方法创建

六 、spring之依赖注入DI【重点】

1、DI是什么

DI依赖注入:
Dependency Injection(简称DI注入)。
它是spring框架核心 ioc容器,
bean属性值赋值的具体方案

在上面,我们在程序编写时,通过控制反转,把对象的创建交给了 spring。
但是这种方式仅仅是降低了代码中的依赖关系,并不会完全消除依赖。
例如:我们的业务层仍会调用持久层的方法。 

如图所示:
在这里插入图片描述

而所谓的依赖注入,可以先简单的理解为由spring框架来帮助我们以解耦的方式将dao传递到service中,
以解耦的方式给属性进行赋值,简称DI注入。

2、DI和IOC区别

  • IoC与DI是同一件事站在不同角度看待问题

    ​ 在应用程序的角度看程序需要被动等待Spring提供资源(注入资源)是DI;

    ​ 但是在Spring容器的角度看是,是将资源的创建权利做了翻转,且由容器提供数据,是IOC;

  • 半杯水

在这里插入图片描述

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

3、DI的方式和数据类型

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

注入的数据类型有三类:
        第一类:基本类型和String
        第二类:其他bean类型
            要求:其他bean指的是在spring的配置文件中定义过的bean,或者是用注解注释过的类。
        第三类:复杂类型(集合类型)
            Array: 数组
            List:集合
            Map:集合
            Properties:属性集
        
构造方式:
默认:使用无参数构造方法,创建对象
set方式:
        property 指定属性
        name:按属性名
        ref:指定注入bean的Id
构造函数:
        constructor-arg:构造函数
        name:按属性名
        index:按下标注
        type:按类型
1)set方法注入
格式
使用类中属性的set方法,给属性赋值。
注意,赋值的操作不是我们硬编码的,而是通过配置的方式,让spring框架来为我们注入。
要求:
   1、bean中必须提供属性的set方法
   2、bean标签中通过proprety标签注入属性

步骤:
    1、为属性提供set方法
    2、修改bean.xml的property注入

<property name="属性名" value=""></property>

<property name="属性名(bean)" ref="引入id名"></property>
代码演示
修改AccountServicImpl

提供属性的set方法

/**
 * @Description:账户服务实现类
 */
public class AccountServicImpl implements AccountServic {
    AccountDao accountDao ;

    @Override
    public void createAccount() {
        accountDao.createAccount();
    }

    /**
     * @Description 提供set方法
     */
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }
}
修改bean.xml
    <!--
    bean:实例化对象
    id:bean的唯一标示
    class:实现类的全路径(反射使用)
    细节:默认使用无参数构造函数实例化
    -->
    
    <bean id="accountDao" class="com.example.spring.dao.impl.AccountDaoImpl">
    </bean>

    <bean id="accountService" class="com.example.spring.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>
ClientController测试
/**
 * @Description:调用层
 */
public class ClientController {
    @Test
    public  void  createAccountTest(){
        //加载bean.xml
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("classpath:bean.xml");
        //获取accountDao accountDao实例化的bean
        AccountService accountService = (AccountService) applicationContext.getBean("accountService");
        //执行
        accountService.createAccount();
    }
}

在这里插入图片描述

2)构造函数注入
格式
使用类中的构造函数,给成员变量赋值。
注意,赋值的操作不是我们硬编码的,而是通过配置的方式,让spring框架来为我们注入。
要求:
   1、bean对象需要创建有参数的构造方法
   2、在配置文件中通过constructor-arg标签注入属性
<constructor-arg name="属性名" value=""></constructor-arg>

<constructor-arg name="属性名(bean)" ref="引入id"></constructor-arg>
代码演示
修改AccountServicImpl

添加构造函数

/**
 * @Description:账户服务实现
 */
public class AccountServicImpl implements AccountServic {


    AccountDao accountDao ;

    /**
     * @Description 构造函数
     */
    public AccountServicImpl(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public void createAccount() {
        accountDao.createAccount();
    }
}

修改bean.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="accountDao" class="com.heima.spring.dao.impl.AccountDaoImpl"></bean>

    <!--创建accountServic使用构造函数-->
    <bean id="accountServic" class="com.heima.spring.service.impl.AccountServicImpl">
        <constructor-arg name="accountDao" ref="accountDao"></constructor-arg>
    </bean>
</beans>
ClientController测试
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Description:调用层
 */
public class ClientController {

    @Test
    public void createAccountTest(){
        //加载配置文件
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("classpath:bean.xml");
        //获得bean
        AccountServic accountServic = (AccountServic) applicationContext.getBean("accountServic");
        //创建账户
        accountServic.createAccount();
    }

}

在这里插入图片描述

3、依赖注入的简单配置【了解】

简单名称空间注入只是set方法注入和构造方法注入的简化方式,其本质是相同的

P名称空间注入,就是set方法注入。其本质在于简化配置,
空间名:xmlns:p="http://www.springframework.org/schema/p

c名称空间注入,就是构造函数注入。其本质在于简化配置,
空间名: xmlns:c="http://www.springframework.org/schema/c"
1)P标签方式(set方法)
p名称空间注入,就是set方法注入。其本质在于简化配置,
bean.xml中添加空间名:
xmlns:p="http://www.springframework.org/schema/p"
修改bean.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: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:bean的唯一标示
    class:实现类的全路径(反射使用)
    细节:默认使用无参数构造函数实例化
    -->
    <bean id="accountDao" class="com.heima.spring.dao.impl.AccountDaoImpl"> </bean>

    <bean id="accountService" class="com.heima.spring.service.impl.AccountServiceImpl" p:accountDao-ref="accountDao"></bean>

</beans>
ClientController测试

在这里插入图片描述

2)C标签方式(构造函数)
c名称空间注入,就是构造函数注入。其本质在于简化配置,
bean.xml中添加空间名:
xmlns:c="http://www.springframework.org/schema/c"
修改bean.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:c="http://www.springframework.org/schema/c"
       --------------------------------------------------------
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
    bean:实例化对象
    id:bean的唯一标示
    class:实现类的全路径(反射使用)
    细节:默认使用无参数构造函数实例化
    -->
    <bean id="accountDao" class="com.heima.spring.dao.impl.AccountDaoImpl"></bean></bean>

    <bean 
          id="accountService" 				       class="com.heima.spring.service.impl.AccountServiceImpl" 
          c:accountDao-ref="accountDao"></bean>
    </beans>
ClientController测试

在这里插入图片描述

4、复杂类型的注入

我们知道了自定对象,及基础对象的注入方式,那么数组、List、Set、Map、Properties是怎么注入的呢?

给类中的复杂的属性注入数据,比如集合或者数组, 
我们这里介绍注入数组、List、Set、Map、Properties。
使用set方法注入集合属性:
    array:一般用来设置数组
    list:一般用来设置list集合
    map:一般用来设置map集合
    props:一般用来设置properties
代码演示
创建Account实体类
package com.example.spring.pojo;

import java.util.*;

/**
 * @Description:账户实体类
 */
public class Account {

    //账户编号
    private String Id;

    //账户所有者
    private String accountName;

    //账户余额
    private Float money;

    private String[] myStrs;

    private List<String> myList;

    private Set<String> mySet;

    private Map<String, String> myMap;

    private Properties myProps;

    public Account() {
    }

    public String getId() {
        return Id;
    }

    public void setId(String id) {
        Id = id;
    }

    public String getAccountName() {
        return accountName;
    }

    public void setAccountName(String accountName) {
        this.accountName = accountName;
    }

    public Float getMoney() {
        return money;
    }

    public void setMoney(Float money) {
        this.money = money;
    }

    public String[] getMyStrs() {
        return myStrs;
    }

    public void setMyStrs(String[] myStrs) {
        this.myStrs = myStrs;
    }

    public List<String> getMyList() {
        return myList;
    }

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

    public Set<String> getMySet() {
        return mySet;
    }

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

    public Map<String, String> getMyMap() {
        return myMap;
    }

    public void setMyMap(Map<String, String> myMap) {
        this.myMap = myMap;
    }

    public Properties getMyProps() {
        return myProps;
    }

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

    @Override
    public String toString() {
        return "Account{" +
                "Id='" + Id + '\'' +
                ", accountName='" + accountName + '\'' +
                ", money=" + money +
                ", myStrs=" + Arrays.toString(myStrs) +
                ", myList=" + myList +
                ", mySet=" + mySet +
                ", myMap=" + myMap +
                ", myProps=" + myProps +
                '}';
    }
}
编写bean.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="account" class="com.heima.spring.pojo.Account">
        <!--set方法注入基本类型属性:-->
        <property name="id" value="1111"></property>
        <property name="accountName" value="小王"></property>
        <property name="money" value="2000"></property>
        <!--
        注入集合属性:
        使用set方法注入集合属性:
        array:一般用来设置数组
        list:一般用来设置list集合
        map:一般用来设置map集合
        props:一般用来设置properties
     -->
        <property name="myStrs">
            <array>
                <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </array>
        </property>
        <property name="myList">
            <list>
                <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </list>
        </property>
        <property name="mySet">
            <set>
                <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </set>
        </property>
        <property name="myMap">
            <map>
                <entry key="name1" value="AAA"></entry>
                <entry key="name2" value="BBB"></entry>
                <entry key="name3" value="CCC"></entry>
            </map>
        </property>
        <property name="myProps">
            <props>
                <prop key="name1">AAA</prop>
                <prop key="name2">BBB</prop>
                <prop key="name3">CCC</prop>
            </props>
        </property>
    </bean>
</beans>
controller测试
package com.example.spring.controller;

import com.example.spring.pojo.Account;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Description:调用层
 */
public class ClientController {

    @Test
    public void createAccountTest(){
        //加载配置文件
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("classpath:bean.xml");
        //获得bean
        Account account = (Account) applicationContext.getBean("account");
        //打印结果
        System.out.println("account的对象信息"+account.toString());
    }

}

在这里插入图片描述

总结

java中的耦合,如何解耦:
		耦合: 程序代码之间的依赖关系
    解耦合:
		工厂 + 反射 + 配置文件
        配置文件: 存放被需要创建的类的全限定名
        工厂: 解析配置文件,根据配置文件中的配置创建bean对象
          	1.解析配置文件,获取配置文件中配置的类全限定名
          	2.根据配置的全限定名创建对象的bean对象
    思考:
		工厂可以根据配置文件创建bean对象,那么工厂创建的bean对象是单实例还是多实例的?
          	创建单实例:
					将创建的bean对象存放到一个map集合中,我们管这个集合叫做bean对象容器;
			创建多实例:
					工厂创建的多实例对象属于每一个线程,不会往容器中存放;
解耦:
	java中的耦合: 程序代码之间的依赖关系
    解耦: 解开程序在编译期代码之间的依赖
    
    对象 对象名称 = new 对象();  // 存在依赖
	Class.forName("类的全限定名"); // 存在硬编码
	工厂 + 配置文件 + 反射
=================================================
Spring框架:
	轻量级框架: 学习成本低,执行效率高,Spring为我们的javaEE企业级应用提供了全方位的解决方案。
    web: 控制层
		SpringMVC
	service: 业务层
      	service层可以使用Spring提供了AOP完成事务的控制
    dao: 持久层
      	Spring提供了JDBCTemplate封装jdbc
      	
   SPring的两大核心:
		IOC: 控制反转 ★
            反转的是对象的创建权.
            之前我们使用对象时,是主动出击创建对象(new 对象())
            控制反转后,对象的创建权交个了Spring,由Spring帮我们创建对象,
            当我们使用对象时,找Spring的IOC容器获取对象即可,IOC容器本质上就是一个Map集合。
		AOP: 面向切面编程
            方法增强,在不改变原代码的基础上对象方法进行增强。(无侵入式)
            底层使用的是动态代理
            
   SPring的IOC入门案例:
		1.导入Spring的jar包 spring-context
        2.编写配置文件
            在配置文件中配置需要Spring帮我们创建的类
        3.使用Spring的API,解析配置文件,获取ApplicationContext对象
          调用应用上下文对象的API从IOC容器中获取bean对象
	API:
		ApplicationContext: 应用上下文对象,接口
            ClassPathXmlApplicationContext★: 解析类路径下的配置文件
            FileSystemXmlApplicationContext: 解析系统路径下的配置文件
            AnnotationConfigApplicationContext: 解析类上的注解
        立即加载的接口:
			在解析完配置文件后,会立即创建bean对象,将bean存放到IOC容器中
   		BeanFactory: 顶层接口
            默认使用延迟加载的形式创建对象
            
Spring的IOC-xml方式:
	xml文件:
		创建bean对象:
			// 方式1: 使用类的无参构造
			<bean id="唯一标识" class="类的全限定名"></bean>
            // 方式2: 调用工厂的静态方法创建
            <bean id="..." class="工厂的全限定名" factory-method="静态方法名">
            // 方式3: 调用工厂的非静态方法
            // 3.1 创建工厂对象
            <bean id="factoryId" class="工厂类的全限定名"></bean>
            // 3.2 调用非静态方法执行
            <bean id="唯一标识" factory-bean="factoryId" 
                factory-method="非静态方法名"></bean>
        bean对象的作用范围:
			scope: 设置作用范围
                singleton: 单实例对象(默认)
                prototype: 多实例对象
			<bean id="唯一标识" class="类的全限定名" scope=".."></bean>
        bean对象的生命周期:
			单实例:
				创建: ioc容器创建,bean对象就创建(xml文件解析完毕后)
                销毁: applicationContext对象关闭
			多实例:
				创建: 当调用getBean方法时创建
                销毁: 等待GC回收
            属性:
				init-method: 设置初始化方法
                destory-method: 设置销毁方法
			<bean id="唯一标识" class="类的全限定名" scope=".."></bean>
    DI: 依赖注入
        注入方式:
			方式1: 有参构造
            方式2: set方法注入  ★ 
            方式3: 注解  ★
        注入的数据类型:
			基本类型和String
            bean对象
            复杂类型:
				数组
                list
                map
                properties
                
Spring-IOC : 注解方式
    半xml半注解:
		在xml文件中开启组件扫描
            
    	相关的注解:
			创建Bean对象的注解:
				@Component
				@Controller
				@Service
				@Repository  
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程小栈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值