Sping系列课程--工厂

Sping系列课程–工厂

第一章 引言

4. 工厂设计模式

4.1 什么是工厂设计模式
1. 概念:通过工厂类,创建对象
	User user = new User();
	UserDAO userDAO = new UserDAOImpl();
	
2. 好处: 解耦合
	耦合:指的是代码间的强关联关系,一方的改变会影响到另一方
	问题:不利于代码维护
	UserService userService = new UserServiceImpl();
4.2 简单的工厂实现
package com.jujuxiaer.basic;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
* @author Jujuxiaer
* @date 2020-11-06 20:34
*/
public class BeanFactory {

   private static Properties env = new Properties();

   /* 将applicationContext.properties文件中的内容读取到Properties集合中,
       然后这个IO操作属于系统级资源,避免重复性的打开IO,最后在程序启动的时候一次性的读取想要的内容
       所以读这个配置文件时候,可以在静态代码块中进行
    */
   static {
       // 1. 获得IO输入流
       InputStream inputStream = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
       // 2. 文件内容封装到Properties集合中
       try {
           env.load(inputStream);
       } catch (IOException e) {
           e.printStackTrace();
       }
   }

   /*
       对象创建的三种方式:
           1. 直接调用构造方法 创建对象 UserService userService = new UserServiceImpl();
           2. 通过反射的方式 创建对象 解耦合
               Class clazz = Class.forName("com.jujuxiaer.basic.UserServiceImpl");
               UserService userService = (UserService) clazz.newInstance();
    */
   public static UserService getUserService() {
       // 使用new 的方式创建对象
       // return new UserServiceImpl();

       // 使用反射方式创建对象
       UserService userService = null;
       try {
           // 但是在这里类的全限定类名字符串还是存在耦合,可通过配置文件的方式解决
           // Class clazz = Class.forName("com.jujuxiaer.basic.UserServiceImpl");

           Class clazz = Class.forName(env.getProperty("userService"));
           userService = (UserService) clazz.newInstance();
       } catch (ClassNotFoundException e) {
           e.printStackTrace();
       } catch (InstantiationException e) {
           e.printStackTrace();
       } catch (IllegalAccessException e) {
           e.printStackTrace();
       }

       return userService;
   }

   public static UserDAO getUserDAO() {
       UserDAO userDAO = null;
       try {
           Class clazz = Class.forName(env.getProperty("userDAO"));
           userDAO = (UserDAO) clazz.newInstance();
       } catch (ClassNotFoundException e) {
           e.printStackTrace();
       } catch (InstantiationException e) {
           e.printStackTrace();
       } catch (IllegalAccessException e) {
           e.printStackTrace();
       }

       return userDAO;
   }
}
4.3 通用工厂设计
  • 问题

    简单工厂会存在大量的代码冗余
    

    Sping系列课程--工厂_第1张图片

  • 通用工厂的代码

// 创建一切想要的对象
public class BeanFactory {
    /**
     * @param key 配置文件中的key,比如 userService userDAO
     * @return
     */
    public  static  Object getBean(String key){
        Object ret = null;
        try{
            Class<?> clazz = Class.forName(env.getProperty(key));
            ret = clazz.newInstance();
        } catch (Exception e){

        }
        return ret;
    }
}
4.4 通用工厂的使用方式
1. 定义类型(类)
2. 通过配置文件的配置来告知工厂(applicationContext.properties)
	key = value
3. 通过工厂获得类的对象
	Object ret = BeanFactory.getBean("key");

5. 总结

Spring本质: 工厂ApplicationContext(applicationContext.xml)

第二章 第一个Spring程序

1. 软件版本

1. JDK1.8+
2. Maven3.5
3. IDEA2020.2
4. SpringFramework 5.1.4
	官方网址 www.spring.io

2. 环境搭建

  • Spring的Jar包

    # 设置pom依赖
    
        org.springframework
        spring-context
        5.1.4.RELEASE
    
    
  • Spring的配置文件

    1. 配置文件的放置位置: 任意位置,没有硬性要求
    2. 配置文件的命名:没有硬性要求,建议我们叫applicationContext.xml
    
    思考:日后应用Spring框架时,需要进行配置文件路径的设置
    

    Sping系列课程--工厂_第2张图片

3. Spring的核心API

  • ApplicationContext

    作用: Spring提供的ApplicationContext这个工厂,用于地对象的创建
    好处:解耦合
    
    • ApplicationContext接口类型

      接口:屏蔽实现的差异
      非Web环境:ClassPathXmlApplicationContext(常用于Main函数或Junit单元测试中)
      Web环境:XmlWebApplicationContext
      

      Sping系列课程--工厂_第3张图片

    • 重量级资源

      ApplicationContext工厂的对象会占用大量的内存。
      不会频繁的创建对象:一个应用只会创建一个工厂对象。
      ApplicationContext工厂:一定是线程安全的(也就是能被多线程并发访问)
      

4. 程序开发

1. 创建类型(类)
2. 配置文件的配置 applicationContext.xml
    
    
3. 通过工厂类,获取对象
	ApplicationContext
		|- ClassPathXmlApplicationContext
		
    // 1. 获取Spring工厂
    ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
    // 2. 通过工厂获取对象
    Person person = (Person) ctx.getBean("person");

5. 细节分析

  • 名词解释

    Spring工厂创建的对象,叫做Bean或者组件(Component)
    
  • Spring工厂中的相关方法

    // 1. 获取Spring工厂
    ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
    // 2. 通过工厂获取对象
    Person person = (Person) ctx.getBean("person");
    
    // 不需要进行强转
    Person person = ctx.getBean("person", Person.class);
    
    // 此时在Spring工厂的配置当中,只能有一个Bean标签是Person类型, 不然的话会抛异常
    // 抛的异常信息: expected single matching bean but found 2: person,person1
    Person person = ctx.getBean(Person.class);
    
    // 返回的是 Bean标签中定义的bean的名字 数组
    // ctx.getBeanDefinitionNames() 获取的是Spring工厂配置文件中所有Bean标签的id值
    String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
    for (String beanDefinitionName : beanDefinitionNames) {
        System.out.println("beanDefinitionName = " + beanDefinitionName);
    }
    System.out.println("person = " + person);
    
    // 根据类型获取Spring工厂配置文件中对应的Bean标签中id的值
    String[] beanNamesForType = ctx.getBeanNamesForType(Person.class);
    for (String beanName : beanNamesForType) {
        System.out.println("beanName = " + beanName);
    }
    
    // 用于判断会否存在指定的id值的Bean
    if (ctx.containsBeanDefinition("11person")) {
        System.out.println("True = " + true);
    } else {
        System.out.println("False = " + false);
    }
    
    // 用于判断会否存在指定的id值的Bean, 暂时来看和上面的ctx.containsBeanDefinition("person")作用一样
    if (ctx.containsBean("person")) {
        System.out.println("True = " + true);
    } else {
        System.out.println("False = " + false);
    }
    
  • 配置文件中需要注意的细节

    1. 只配置class属性
    
    	a) 上述这种配置,有没有id值呢,也就是Spring会为我们赋上id值吗
    		回答: 有id值,值为 com.jujuxiaer.basic.Person#0
    	b) 上述这种配置方式,应用功能场景:如果这个bean只需使用一次,那么就可以省略id值
     								 如果这个bean会使用多次或者被其他bean引用,则需要设置id值
    
    2. name属性
    作用: 用于在Spring配置文件中,为bean对象定义别名
    相同:
    	1. ctx.getBean("id|name"); --> Object
    	2.  
    		等效
    		
    区别:
    	1. 别名可以定义多个,但是id属性只能有一个值
    		  多个别名之间以逗号分隔
    	2. XML的id属性的值,命名要求: 必须要以字母开头,后面可跟字母、数字、下划线、连字符,不能以特殊字符开头,比如"/person"
    			name属性的值,命名没有要求,比如可以设置成"/person"
           name属性会应用在特殊命名的场景中: /person (spring+struct1)
          	
          XML发展到了今天:id属性的限制,不存在了, 比如亦可以用"/person"命名
          
        3. 代码
            // 用于判断会否存在指定的id值的Bean,不能判断name属性值
            if (ctx.containsBeanDefinition("p")) {
                System.out.println("True = " + true);
            } else {
                System.out.println("False = " + false);
            }
    
            // 用于判断会否存在指定的id值的Bean, 暂时来看和上面的ctx.containsBeanDefinition("person")作用一样
            // 也可以判断name属性值
            if (ctx.containsBean("p")) {
                System.out.println("True = " + true);
            } else {
                System.out.println("False = " + false);
            }
    

6. Spring工厂底层实现原理(简易版)

注意:Spring工厂是可以调用对象私有构造函数创建对象的

Sping系列课程--工厂_第4张图片

7. 思考

问题: 在未来的开发过程中,是不是所有的对象都交由Spring工厂来创建呢?
回答: 理论来说,是的。但是又特例:对于实体对象(entity)不会交给Spring创建,而是交由持久层创建。

第三章 Spring5.x与日志框架的整合

Spring与日志框架整合后,日志框架就能在控制台中,输出Spring框架运行过程中的一些重要的信息。
好处:便于了解Spring框架的运行过程,利于程序的调试。
  • Spring 如何整合日志框架

    默认
    	Spring1.2.3都是与commons-logging.jar整合
    	Spring5.x默认整合的日志框架为logback log4j2
    
    Spring5.x整合log4j
    	1. 引入log4j jar包
    	2. 引入log4j.properties配置文件
    
    • pom

      <dependency>
          <groupId>org.slf4jgroupId>
          <artifactId>slf4j-log4j12artifactId>
          <version>1.7.25version>
          <scope>testscope>
      dependency>
      
      <dependency>
          <groupId>log4jgroupId>
          <artifactId>log4jartifactId>
          <version>1.2.17version>
      dependency>
      
    • log4j.properties

      # resources文件夹根目录下
      ### 配置根
      log4j.rootLogger = debug,console
      
      ### 日志输出到控制台显示
      log4j.appender.console = org.apache.log4j.ConsoleAppender
      log4j.appender.console.Target = System.out
      log4j.appender.console.layout = org.apache.log4j.PatternLayout
      log4j.appender.console.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
      

第四章 注入(injection)

1. 什么是注入

通过Spring的工厂以及配置文件,为所创建对象的成员变量赋值
1.1 为什么需要注入

通过编码的方式为成员变量赋值,存在耦合

Sping系列课程--工厂_第5张图片

1.2 如何进行注入,开发步骤
  • 类为成员变量提供get/set方法

  • 配置Spring的配置文件

    <bean id="person" class="com.jujuxiaer.basic.Person">
        <property name="id">
            <value>10value>
        property>
        <property name="name">
            <value>juzhihuavalue>
        property>
    bean>
    
1.3 注入的好处
解耦合

2. Spring注入的原理分析(简易版)

Spring底层通过调用对象属性对应的set方法,完成成员变量的赋值,这种方式我们称为set注入

Sping系列课程--工厂_第6张图片

第五章 set注入详解

针对不同类型的成员变量,在标签中需要嵌入其他标签

Sping系列课程--工厂_第7张图片

1. JDK内置类型

1.1 String + 8中基本类型
jujuxiaer
1.2 数组
<property name="emails">
    <list>
        <value>[email protected]value>
        <value>[email protected]value>
    list>
property>
1.3 set集合

对应的成员变量为Set tels; 因为Set的泛型此时是String,所有标签中嵌套的为标签,如果Set泛型为其他的类型,则标签中嵌套的为其他标签

<property name="tels">
    <set>
        <value>1341111111value>
        <value>1342222222value>
    set>
property>
1.4 list集合
<property name="addresses">
    <list>
        <value>湖北省武汉市value>
        <value>上海市黄浦区value>
    list>
property>

    <list>
		list>
1.5 map集合
注意: map -- entry -- 键有特定的标签 <key>key>
					  值根据对应的类型选择对应类型的标签,比如<ref bean       等等
 name="qqs">
    <map>
        <entry>
            <key><value>jujuxiaervalue>key>
            <value>1225449109value>
        entry>
    map>
property>
1.6 Properties
Properties类型:特殊的Map,该map的键为String,值也为String
<property name="p">
    <props>
        <prop key="key1">value1prop>
        <prop key="key2">value2prop>
    props>
property>
1.7 复杂JDK类型(Date)
需要程序员自定义类型转换器,处理。

2. 用户自定义类型

2.1 第一种方式
  • 为成员变量提供get/set方法

  • 配置文件中进行注入(赋值)

    <bean id="userService" class="com.jujuxiaer.basic.UserServiceImpl">
        <property name="userDAO">
            <bean class="com.jujuxiaer.basic.UserDAOImpl"/>
        property>
    bean>
    
2.2 第二种方式
  • 第一种方式存在的问题

    1. 配置文件代码冗余
    2. 被注入的对象(userDAO),多次创建,浪费(JVM)内存资源
    
  • 为成员变量提供get/set方法

  • 配置文件中进行注入(赋值)

    <bean id="userDAO" class="com.jujuxiaer.basic.UserDAOImpl"/>
    <bean id="userService" class="com.jujuxiaer.basic.UserServiceImpl">
        <property name="userDAO">
            <ref bean="userDAO"/>
        property>
    bean>
    
    # Spring4.x 废弃了 <ref local=""/> 基本等效 <ref bean=""/>
    

    Sping系列课程--工厂_第8张图片

3. set注入的简化方式

3.1 基于属性简化
# JDK类型注入
<property name="name">
    <value>jujuxiaervalue>
property>

<property name="name" value="jujuxiaer"/>

# 注意:value属性,只能简化8种基本类型+String 注入标签

# 用户自定义类型
<bean id="userDAO" class="com.jujuxiaer.basic.UserDAOImpl"/>
<bean id="userService" class="com.jujuxiaer.basic.UserServiceImpl">
    <property name="userDAO">
        <ref bean="userDAO"/>
    property>
bean>

# 用户自定义类型,简化后
<bean id="userDAO" class="com.jujuxiaer.basic.UserDAOImpl"/>
<bean id="userService" class="com.jujuxiaer.basic.UserServiceImpl">
    <property name="userDAO" ref="userDAO"/>
bean>
3.2 基于p命名空间简化
# JDK类型注入
<bean id="person" class="com.jujuxiaer.basic.Person">
    <property name="name">
        <value>jujuxiaervalue>
    property>
bean>

<bean id="person" class="com.jujuxiaer.basic.Person" p:name="jujuxiaer"/>

# 注意:value属性,只能简化8种基本类型+String 注入标签

# 用户自定义类型
<bean id="userDAO" class="com.jujuxiaer.basic.UserDAOImpl"/>
<bean id="userService" class="com.jujuxiaer.basic.UserServiceImpl">
    <property name="userDAO">
        <ref bean="userDAO"/>
    property>
bean>

# 用户自定义类型,简化后
<bean id="userDAO" class="com.jujuxiaer.basic.UserDAOImpl"/>
<bean id="userService" class="com.jujuxiaer.basic.UserServiceImpl" p:userDAO-ref="userDAO"/>

第六章 构造注入

注入:通过Spring的配置文件,为成员变量赋值
set注入: Spring通过调用set方法,通过配置文件为成员变量赋值
构造注入: Spring通过调用构造方法,通过配置文件为成员变量赋值

1. 开发步骤

  • 提供有参的构造方法

    public class Customer implements Serializable {
    
        private String name;
        private int age;
    
        public Customer(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }
    
  • Spring的配置文件

    <bean id="customer" class="com.jujuxiaer.basic.constructer.Customer">
        <constructor-arg>
            <value>jujuxiaervalue>
        constructor-arg>
        <constructor-arg>
            <value>102value>
        constructor-arg>
    bean>
    

2. 构造方法重载

2.1 参数个数不同时
通过控制标签数量进行区分

2.2 参数个数相同时

通过在标签引入type属性来进行类型的区分<constructor-arg type="">
    
<bean id="customer" class="com.jujuxiaer.basic.constructer.Customer">
    <constructor-arg type="int">
        <value>23value>
    constructor-arg>
bean>

3. 注入总结

未来实战中使用set注入,还是构造注入?
回答:set注入会更多
	原因:1. 构造注入麻烦,有重载
		 2. Spring框架底层,大量应用了set注入

Sping系列课程--工厂_第9张图片

第七章 反转控制 与 依赖注入

1. 反转(转移)控制(Inverse of Control,简称IOC)

控制: 对于成员变量的赋值的控制权
反转控制:把对于成员变量赋值的控制权,从代码中反转(转移)到了Spring工厂和配置文件中完成
   好处: 解耦合
底层实现:工厂设计模式   

Sping系列课程--工厂_第10张图片

2. 依赖注入(Dependency Injection,简称DI)

注入:通过Spring工厂和配置文件,为对象(bean/组件)的成员变量赋值

依赖注入:一个类需要另一个类时,就意味着依赖,一旦出现依赖,就可以把另一个类作为本类的成员变量,最终通过Spring配置文件进行注入(赋值)。

Sping系列课程--工厂_第11张图片

第八章 Spring工厂创建复杂对象

Sping系列课程--工厂_第12张图片

1. 什么是复杂对象

复杂对象:指的是不能直接通过new构造方法创建的对象
	Connection
	SqlSessionFactory

2. Spring工厂创建复杂对象的3中方式

2.1 FactoryBean接口
  • 开发步骤

    • 实现FactoryBean接口

      Sping系列课程--工厂_第13张图片

  • Spring配置文件的配置

    # 如果Class属性中指定的类型是FactoryBean接口的实现类,那么通过id值获得的是这个类所创建的复杂对象,比如Connection
    <bean id="conn" class="com.jujuxiaer.factorybean.ConnectionFactoryBean"/>
    

    Sping系列课程--工厂_第14张图片

    Sping系列课程--工厂_第15张图片

  • 细节

    • 如果 ,ctx.getBean("&conn"); 获得的就是ConnectionFactoryBean对象

    • isSingleton方法

      返回true,只会创建一个复杂对象

      返回false,每一次都会创建新的对象

      问题:根据这个对象的特点,决定是返回true(SqlSessionFactory),还是false(Connection)

    • mysql高版本在连接创建时,需要指定SSL证书,解决问题的方式

      url = "jdbc:mysql://localhost:3306/suns?useSSL=false"
      
    • 依赖注入的体会(DI)

      把ConnectionFactoryBean中依赖的四个字符串信息,进行配置文件的注入
      好处:解耦合
      
          
          
          
          
      
      
  • FactoryBean的实现原理(简易版)

    接口回调
    1. 为什么Spring规定FactoryBean接口 实现 并且getObject()?
    2. ctx.getBean("conn");获得的是复杂对象Connection,而不是获得ConnectionFactoryBean
    
    Spring内部运行流程:
    1. 通过conn获得ConnectionFactoryBean类对象,进而通过instanceod判断出是FactoryBean接口的实现类
    2. Spring按照规定getObejct() --> Connection
    3. 返回Connection
    

    Sping系列课程--工厂_第16张图片

  • Factory总结

    Spring中用于创建复杂对象的一种方式,也是Spring原生提供的,后续我们在讲解Spring整合其他框架时,会大量应用FactoryBean
    
2.2 实例工厂
1. 避免Spring框架的侵入
2. 整合遗留系统
  • 开发步骤

    <bean id="connFactory" class="com.jujuxiaer.factorybean.ConnectionFactory"/>
    <bean id="conn" factory-bean="connFactory" factory-method="getConnection"/>
    
2.3 静态工厂
  • 开发步骤

    <bean id="conn" class="com.jujuxiaer.factorybean.StaticConnectionFactory" factory-method="getConnection"/>
    

3. Spring工厂创建对象总结

Sping系列课程--工厂_第17张图片

第九章 控制Spring工厂创建对象次数

1. 如何控制简单对象的创建次数

<bean id="account" class="com.jujuxiaer.scope.Account" scope="singleton|prototype"/>
singleton: 只会创建一次简单对象
prototype: 每一次都会创建简单对象

默认为singleton

2. 如何控制复杂对象的创建次数

FactoryBean {
	isSingleton() {
		return true 只会创建一次
		return false 每一次都会创建新的
	}
}
如果没有isSingleton方法,还是通过制定scope属性,进行对象创建次数的控制。

3. 为什么要控制对象的创建次数

好处:节省不必要的内存浪费
  • 什么样的对象只创建一次

    1. SqlSessionFactoryBean 
    2. DAO
    3. Service
    
  • 什么样的对象,每一次都要创建新的呢?

    1. Connection(因为要控制事务,不能被大家共用)
    2. SqlSession(里面封装了Connection) | Session
    3. Struct2 Action
    

第十章 对象的生命周期

Sping系列课程--工厂_第18张图片

1. 什么是对象的生命周期

指的是一个对象创建、存活、消亡的一个完整过程。

2. 为什么要学习对象的生命周期

由Spring来负责对象的创建、存活、销毁,了解生命周期后,有利于我们使用好Spring为我们创建的对象。

3. 生命周期的3个阶段

  • 创建阶段

    Spring工厂何时创建
    
    • scope=“singleton”

      Spring工厂创建的同时,对象创建
      
      注意: 设置scope="singleton" 这种情况下,也需要在获取对象的同时,创建对象
      
      
    • scope=“prototype”

      Spring工厂会在获取对象的同时,创建对象
      ctx.getBean("")
      
  • 初始化阶段

    Spring工厂在创建完成对象后,调用对象的初始化方法,完成对应的初始化操作
    
    1. 初始化方法提供:程序员根据需求,提供初始化方法,最终完成初始化操作
    2. 初始化方法调用:Spring工厂进行调用
    
    • InitializingBean接口

      public class Product implements InitializingBean {
      
          public Product() {
              System.out.println("Product.Product");
          }
      
          /**
           * 完成对象的初始化操作
           * @throws Exception
           */
          public void afterPropertiesSet() throws Exception {
              System.out.println("Product.afterPropertiesSet");
          }
      }
      
    • 对象中提供一个普通的方法

      public void myInit() {
          
      }
      
      // 
      
    • 细节分析

      1. 如果一个对象既实现了InitializingBean,又提供了普通的初始化方法,执行顺序是怎样呢?

        1. InitializingBean
        2. 普通的初始化方法
        
      2. 注入一定发生在初始化操作的前面

      3. 什么叫做初始化操作

        资源的初始化:数据库 IO 网络 ......
        
  • 销毁阶段

    Spring销毁对象前,会调用对象的销毁方法,完成销毁操作
    
    1. Spring什么时候销毁所创建的对象?
    	ctx.close();
    2. 销毁方法:程序员根据自己的需求,定义销毁方法,完成销毁操作
          调用:Spring工厂完成调用
    
    • DisposableBean
    • 定义一个普通的销毁方法
    public class Product implements InitializingBean, DisposableBean {
        private String name;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
            System.out.println("Product.setName");
        }
    
        public Product() {
            System.out.println("Product.Product");
        }
    
        // 完成对象的初始化操作
        public void afterPropertiesSet() throws Exception {
            System.out.println("Product.afterPropertiesSet");
        }
        public void myInit() {
            System.out.println("Product.myInit");
        }
    
        public void destroy() throws Exception {
            System.out.println("Product.destroy");
        }
    
        public void myDestroy() throws Exception {
            System.out.println("Product.myDestroy");
        }
    }
    
    <bean id="product" class="com.jujuxiaer.life.Product" init-method="myInit" destroy-method="myDestroy">
        <property name="name" value="productName"/>
    </bean>
        
    @Test
    public void test17() {
        // 1. 获取Spring工厂
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
        ctx.close();
    }   
    
    • 细节分析
    1. 销毁方法的操作只适用于scope=“singleton”

    2. 什么叫做销毁操作

      主要指的是 资源的释放操作,比如 io.close(); connection.close();
      

第十一章 配置文件参数化

把Spring配置文件中需要经常修改的字符串信息,转移到一个更小的配置文件中

1. Spring的配置文件中存在经常修改的字符串?
	存在,以数据库连接相关的参数 代表
2. 经常变化字符串,在Spring配置文件中,直接修改
	不利于项目维护(修改)
3. 转移到一个小的配置文件(.properties)	
	利于维护(修改)
	
配置文件参数化:利于Spring配置文件的维护(修改)	

1. 配置文件参数化的开发步骤

  • 提供一个小的配置文件(.properties)

    # 文件名称:随意;放置位置:随意
    jdbc.driverClassName = com.mysql.jdbc.Driver
    jdbc.url =jdbc:mysql://localhost:3306/suns?useSSL=false
    jdbc.user = root
    jdbc.password = 123456
    
  • Spring的配置文件和小配置文件的整合

    
    <context:property-placeholder location="classpath:/db.properties"/>
    
  • 在Spring配置文件中通过${key}获取小配置文件中对应的值

    Sping系列课程--工厂_第19张图片

第十二章 自定义类型转换器

1. 类型转换器

作用:Spring通过类型转换器把配置文件中字符串类型的数据,转换成了对象中成员变量对应类型的数据,进而完成了注入

Sping系列课程--工厂_第20张图片

2. 自定义类型转换器

需要自定义类型转换器的原因:
当Spring内部没有提供特定类型转换器时,而程序员在应用的过程中还需要使用个,那么就需要程序员自己定义类型转换器
  • 类实现Convert接口

    /**
     * @author Jujuxiaer
     * @date 2020-11-08 14:25
     * Converter中String是待转换的原始数据类型,Date是转换后的数据类型
     */
    public class MyDateConverter implements Converter<String, Date> {
    
        /*
            convert作用: String --> Date
                 param: source 代表的是配置文件中 日期字符串 2020-11-07
                return: 当把转换好的Date作为convert方法返回值后,Spring自动为birthday属性进行注入(赋值)
         */
        @Override
        public Date convert(String s) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date date = null;
            try {
                date = sdf.parse(s);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return date;
        }
    }
    
  • 在Spring的配置文件中进行配置

    • MyDateConverter对象创建出来

          
          <bean id="myDateConverter" class="com.jujuxiaer.converter.MyDateConverter"/>
      
    • 类型转换器的注册

      
      <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
          <property name="converters">
              <set>
                  <ref bean="myDateConverter"/>
              set>
          property>
      bean>
      

3. 细节

  • MyDateConverter中的日期格式,通过依赖注入的方式,由配置文件完成赋值。

    public class MyDateConverter implements Converter<String, Date> {
        private String pattern;
        public String getPattern() {
            return pattern;
        }
        public void setPattern(String pattern) {
            this.pattern = pattern;
        }
    
        /*
                convert作用: String --> Date
                     param: source 代表的是配置文件中 日期字符串 2020-11-07
                    return: 当把转换好的Date作为convert方法返回值后,Spring自动为birthday属性进行注入(赋值)
             */
        @Override
        public Date convert(String s) {
            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
            Date date = null;
            try {
                date = sdf.parse(s);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return date;
        }
    }
    
    
    <bean id="myDateConverter" class="com.jujuxiaer.converter.MyDateConverter">
        <property name="pattern" value="yyyy-MM-dd"/>
    bean>
    
  • ConversionServiceFactoryBean定义id属性,必须为conversionService

  • Spring框架内置了日期类型转换器

    内置的日期类型转换器支持的日期格式:2010/11/08
                          而不支持,比如2020-11-08 日期格式
    

第十三章 后置处理Bean

BeanPostProcessor作用:对Spring工厂所创建的对象,进行再加工

AOP底层实现:

注意: BeanPostProcesser接口
		xxx (){
		
		}
  • 后置处理Bean de 运行原理分析

    Sping系列课程--工厂_第21张图片

程序员源实现BeanPostProcesser规定接口中的方法:
Object postProcessBeforeInitialization(Object bean, String beanName)
作用:Spring创建完对象,并进行注入后,可以运行Before方法进行加工
获得创建好的对象:通过方法的参数
最终通过返回值交给Spring框架

Object postProcessAfterInitialization(Object bean, String beanName)
作用:Spring执行完对象的初始化操作后,可以运行After方法进行加工
获得创建好的对象:通过方法的参数
最终通过返回值交给Spring框架

实战中:
很少处理Spring的初始化操作(InitializingBean),没有必要区分Before After。只需要实现其中一个After方法即可。但注意postProcessBeforeInitialization方法也需要将bean对象返回。

  • BeanPostProcesser开发步骤

    1. 类 实现BeanPostProcesser接口

      public class MyBeanPostProcessor implements BeanPostProcessor {
          @Override
          public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
              return bean;
          }
      
          @Override
          public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
              Category category = (Category) bean;
              category.setName("xiaowangba");
              return bean;
          }
      }
      
    2. Spring的配置文件进行配置

      <bean id="myBeanPostProcessor" class="com.jujuxiaer.beanpost.MyBeanPostProcessor"/>
      
    3. BeanPostProcessor细节

      BeanPostProcessor会对Spring工厂中所有创建的对象进行加工
      

你可能感兴趣的:(Spring)