Spring学习笔记:创建复杂对象、控制Spring工厂创建对象的次数

Spring笔记汇总

创建复杂对象

1. 什么是复杂对象

在这里插入图片描述
复杂对象:指的就是不能直接通过new构造方法创建的对象

  • Connection
  • SqlSessionFactory

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

2.1 FactoryBean接口

开发步骤

实现Factory接口
在这里插入图片描述

package com.company.factory;

import org.springframework.beans.factory.FactoryBean;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Collection;

public class ConnectionFactoryBean implements FactoryBean<Connection> {
    // 用于书写创建复杂对象的代码 并 把复杂对象作为方法的 返回值 返回
    @Override
    public Connection getObject() throws Exception {
        // 加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //获取连接
        String url = "jdbc:mysql://localhost:3306/test?useSSL=false&" +
                "useUnicode=true&characterEncoding=utf-8&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai";
        Connection connection = DriverManager.getConnection(url, "root", "123456");

        return connection;
    }

    // 返回所创建复杂对象的Class对象
    @Override
    public Class<?> getObjectType() {
        return Collection.class;
    }

    // 返回true:对象只需要创建一次
    // 返回false:每一次调用 都需要创建一个新的复杂对象
    @Override
    public boolean isSingleton() {
        return false;
    }
}

Spring配置文件的设置

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

Connection conn = (Connection) ctx.getBean("conn");
简单对象与复杂对象的比较
<bean id="user" class="com.xxx.User"/>
简单对象
	ctx.getBean("user")获得的是User这个类的对象

<bean id="conn" class="com.compa ny.factorybean.ConnectionFactoryBean"/>
错误认知:
	ctx.getBean("conn")获得的是ConntionFactoryBean这个类的对象
FactoryBean接口的实现类: ConntionFactoryBean
	ctx.getBean("conn")获得的是 它所创建的复杂对象Connection
细节分析

1、如果就想获得FactoryBean类型的对象ctx.getBean("&conn")

  • 获得就是ConnectionFactoryBean对象
  • ConnectionFactoryBean conn = (ConnectionFactoryBean) ctx.getBean("&conn");

2、isSingleton方法

  • 返回true 只会创建一个复杂对象
  • 返回false每一次都会创建新的对象
  • 问题:根据这个对象的特点,决定是返回true (SqlSessionFactory) 还是false (Connection)

3、mysq|高版本连接创建时,需要制定SSL证书, 解决问题的方式

jdbc:mysql://localhost:3306/test?useSSL=false

4、依赖注入的体会(DI)

  • 把ConnectionFactoryBean中依赖的4个字符串信息 ,进行配置文件的注入
  • 好处:解耦合
<bean id="conn" class="com.company.factory.ConnectionFactoryBean">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
</bean>
ConnectionFactoryBean
package com.company.factory;

import org.springframework.beans.factory.FactoryBean;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Collection;

public class ConnectionFactoryBean implements FactoryBean<Connection> {
    private String driverClassName;
    private String url;
    private String username;
    private String password;

    set和get
    
    // 用于书写创建复杂对象的代码 并 把复杂对象作为方法的 返回值 返回
    @Override
    public Connection getObject() throws Exception {
        Class.forName(driverClassName);
        Connection connection = DriverManager.getConnection(url, username, password);

        return connection;
    }

    // 返回所创建复杂对象的Class对象
    @Override
    public Class<?> getObjectType() {
        return Collection.class;
    }

    // 返回true:对象只需要创建一次
    // 返回false:每一次调用 都需要创建一个新的复杂对象
    @Override
    public boolean isSingleton() {
        return false;
    }
}
FactoryBean的实现原理[简易版]

接口回调

  • 为什么Spring规定FactoryBean接口 实现并且getObject()?
  • ctx. getBean(“conn”) 获得是复杂对象Connection 而没有获得ConnectionFactoryBean(&)

Spring内部运行流程

  1. 通过conn获得ConnectionFactoryBean类的对象
  2. 进而通过instanceof 判断出是FactoryBean接口的实现类
  3. Spring按照规定getObject() —> Connection返回Connection

在这里插入图片描述

FactoryBean总结

Spring中用于创建复杂对象的一种方式,也是Spring原生提供的,之后整合其他框架,大量应用FactoryBean

2.2 实例工厂

  • 避免Spring框架的侵入(必须implements FactoryBean)
  • 处理遗留问题(只有.class 没有.java)
ConnectionFactory
/**
 * 此时为遗留系统(.class)
 */
public class ConnectionFactory {

    Connection connection = null;
    public Connection getConnection(){
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false","root","abc8658539");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return connection;
    }
}

开发步骤

<bean id="connectionFactory" class="com.company.factory.ConnectionFactory"/>

<bean id="conn" factory-bean="connectionFactory" factory-method="getConnection"/>

2.3 静态工厂(方法为静态的)

开发步骤

<bean id="conn" class="com.company.factory.StaticConntionFactory" factory-method="getConnection"/>

3. Spring工厂对象创建总结

在这里插入图片描述

控制Spring工厂创建对象的次数

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

<bean id="account" scope="singleton|prototype" class="xxx.Account"/>
sigleton:只会创建一次简单对象默认值
prototype:每一次都会创建新的对象

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

FactoryBean{
	isSingleton(){
		return true		只会创建一次
		return false 	每一次都会创建新的
    }
}
若没有(如实例工厂与静态工厂)isSingleton方法,还是通过scope属性进行对象创建次数的控制

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

好处:节省不必要的内存浪费

什么样的对象只创建一次?(可以共用 或者 线程安全)

  • SqlSessionFactory
  • DAO
  • Service

什么样的对象每一 次都要创建新的?(不可以被共用 或者 线程不安全)

  • Connection (控制了提交事务,每个事务的提交时间都不相同)
  • SqlSession | Session (封装了提交事务)
  • Struts2 Action

对象的生命周期

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

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

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

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

3、生命周期的3个阶段

1、创建阶段

Spring工厂何时创建对象

  • scope=“singleton”

Spring工厂创建的同时,同时创建对象

注意:如果 在scope = “singleton” 这种情况下也想要在获取对象的同时创建对象,则增加<bean lazy-init="true"/>

  • scope=“prototype”

Spring工厂会在获取对象的同时,创建对象:ctx.getBean("")

2、初始化阶段

Spring工厂在创建完对象后,调用对象的初始化方法,完成对应的初始化操作

初始化方法提供:程序员根据需求,提供初始化方法,最终完成初始化操作

初始化方法调用: Spring工厂进行调用

  • InitializingBean接口(Spring自己会进行调用,但是也是会造成Spring侵入)
//程序员根据需求,实现的方法,完成初始化操作
public void afterProperitesSet(){
	
}
  • 对象中提供一个普通的方法(通知spring调用)
public void myInit(){
     
}

<bean id="product" class= "xxx.Product" init-method=" myInit" />
  • 细节分析
  1. 如果一个对象既实现InitializingBean同时又提供的普通的初始化方法顺序

    首先 InitializingBean,后 普通初始化方法

  2. 注入一定发生在初始化操作的前面(set)

  3. 什么叫做初始化操作

    资源的初始化: 数据库、IO、网络 …

3、销毁阶段

Spring销毁对象前,会调用对象的销毁方法,完成销毁操作

1、Spring什么时候销毁所创建的对象?
	ctx.close() ;
2、销毁方法:程序员根据自己的需求,定义销毁方法,完成销毁操作
	调用:Spring工厂 完成调用
  • DisposableBean
public void destroy() throws Exception {
    System.out.println("Product.destroy");
}
  • 定义一个普通的销毁方法
public void myDestory() throws Exception {
    System.out.println("Product.myDestory");
}

<bean id="product" class="com.company.life.Product" init-method="myInit" destroy-method="myDestory"/>
  • 细节分析
  1. 销毁方法的操作只适用于 scope="singleton"

  2. 什么叫做销毁操作:主要指的就是资源的释放操作 io.close()connection.close()

总结

在这里插入图片描述

Test

package com.company.life;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class Product implements InitializingBean, DisposableBean {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("Product.setName");
        this.name = name;
    }

    public Product() {
        System.out.println("Product.Product");
    }

//    public Product(String name) {
//        System.out.println("name = " + name);
//        this.name = name;
//    }

//    这个就是初始化方法:做一些初始化操作
//    Spring进行调用
//    implements InitializingBean
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Product.afterPropertiesSet");
    }

    public void myInit() {
        System.out.println("Product.myInit");
    }

    // 销毁方法:销毁操作(进行资源释放)
    @Override
    public void destroy() throws Exception {
        System.out.println("Product.destroy");
    }

    public void myDestory() throws Exception {
        System.out.println("Product.myDestory");
    }
}

    /**
     *  用于测试:测试生命周期
     *
     */
    @Test
    public void test12(){
        // Spring工厂创建   若 scope = "singleton" 则在此时创建对象
//        ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
        // 若 scope = "prototype" 则在此时获取对象时 创建对象
        Product product = (Product) ctx.getBean("product");
        // close方法ApplicationContext里面没有实现这个方法
        ctx.close();
    }
<!--    <bean id="product" scope="prototype" class="com.company.life.Product"/>-->
<!--    此时虽然是singleton但是也是在获取对象时创建-->
    <bean id="product" class="com.company.life.Product" init-method="myInit" destroy-method="myDestory">
        <property name="name" value="张三"/>
<!--        <constructor-arg>-->
<!--            <value>张三</value>-->
<!--        </constructor-arg>-->
    </bean>

Spring学习笔记:配置文件参数化、自定义类型转换器、后置处理Bean

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值