Spring工厂创建复杂对象以及控制创建对象的次数

1.复杂对象

1.1 什么是复杂对象

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

Spring工厂创建复杂对象
在这里插入图片描述

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

2.1 FactoryBean接口
2.1.1 开发步骤
  • 实现FactoryBean接口
    FactoryBean接口有三个方法需要被实现
    1. Object getObject() :
      用于书写创建复杂对象的代码,并把复杂对象作为方法的返回值返回
    2. Class getObjectType() :
      用于返回所创建对象的Class对象
    3. boolean isSingleton()
      返回 true 只会创建一个复杂对象
      返回 false 每一次都会创建新的对象
      在这里插入图片描述
public class ConnectionFactoryBean implements FactoryBean<Connection> {

    @Override
    public Connection getObject() throws Exception {
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection connection = DriverManager.getConnection("jdbc:mysql://192.168.31.174:3306/?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=UTC","root","123456");
        return connection;
    }

    @Override
    public Class<?> getObjectType() {
        return Connection.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}
  • Spring配置文件的配置
# 如果Class中指定的类型 是FactoryBean接口的实现类,那么通过id值获得的是这个类所创建的复杂对象  Connection
<bean id="conn" class="com.tcgroup.factory.ConnectionFactoryBean"/>

在这里插入图片描述
在这里插入图片描述

2.1.2 细节

如何获得FactoryBean类型的对象
通过我们上面的配置, 由于ConnectionFactoryBean实现了FactoryBean接口,所以通过ID“conn”获得的是ConnectionFactoryBean生产的Connection对象,

  • 如果就想获得FactoryBean类型的对象 可以在ID“conn”前面加一个&
  • classPathXmlApplicationContext.getBean("&conn")获得就是ConnectionFactoryBean对象

isSingleton方法
-返回 true 只会创建一个复杂对象
在这里插入图片描述

  • 返回 false 每一次都会创建新的对象
    在这里插入图片描述
    不是系统自己识别ConnectionFactoryBean是不是单例模式 , 而是需要自己手动去根据这个对象的特点 ,决定是返回true (SqlSessionFactory) 还是 false (Connection),如果你在isSingleton方法里面写的是返回true只会创建一个复杂对象,不管调用几次getBean, 返回的都是同一个对象,适合做复用

依赖注入的思想对上面代码进行优化

public class ConnectionFactoryBean implements FactoryBean<Connection> {

    private String url;
    private String userName;
    private String psaaword;
    private String driver;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPsaaword() {
        return psaaword;
    }

    public void setPsaaword(String psaaword) {
        this.psaaword = psaaword;
    }

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    @Override
    public Connection getObject() throws Exception {
        Class.forName(driver);
        Connection connection = DriverManager.getConnection(url,userName,psaaword);
        return connection;
    }

    @Override
    public Class<?> getObjectType() {
        return Connection.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

    <bean id="conn" class="com.tcgroup.factory.ConnectionFactoryBean">
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://192.168.31.174:3306/?characterEncoding=utf8&amp;useUnicode=true&amp;useSSL=false&amp;serverTimezone=UTC"/>
        <property name="userName" value="root"/>
        <property name="psaaword" value="123456"/>
    </bean>

FactoryBean的实现原理[简易版]
接口回调

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

Spring内部运行流程

  1. 通过conn获得 ConnectionFactoryBean类的对象 ,进而通过instanceof 判断出是FactoryBean接口的实现类
  2. Spring按照规定 getObject() —> Connection
  3. 返回Connection
    在这里插入图片描述
2.2 实例工厂
1. 避免Spring框架的侵入 
2. 整合遗留系统 

开发步骤
假设我们有之前遗留下来的一个ConnectionFactory,提供了getConnection方法可以帮我们拿到一个Connection对象

public class ConnectionFactory {

    public Connection getConnection(){
        Connection conn=null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn= DriverManager.getConnection("jdbc:mysql://192.168.31.174:3306/?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=UTC","root","123456");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }
}

那么接下来我们可以通过配置文件来获取这个Class文件并且用factory-method指定调用他的getConnection方法
第一行先创建ConnectionFactory实例, 然后第二行调用这个实例的getConnection方法

   <bean id="connFactory" class="com.tcgroup.factory.ConnectionFactory"> </bean>
    <bean id="connn" factory-bean="connFactory" factory-method="getConnection"/>
2.3 静态工厂

静态工厂和上面差不多 从之前来说,区别在于实例工厂需要先new一个ConnectionFactory对象,然后通过对象来调用getConnection方法,获取Connection对象,而静态方法可以直接通过类名.方法名来调用方法,而从Spring的配置文件上也是有区别的

public class StaticConnectionFactory {

    public static Connection getConnection(){
        Connection conn=null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn= DriverManager.getConnection("jdbc:mysql://192.168.31.174:3306/?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=UTC","root","123456");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }
}

实例工厂需要先把实例创建出来, 然后再去引用,而静态工厂可以直接引用不需要创建实例

    <bean id="connnn" class="com.tcgroup.factory.StaticConnectionFactory" factory-method="getConnection"/>

3.工厂创建对象总结:

在这里插入图片描述

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

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

通过applicationContext.xml文件配置scope属性为singleton可以控制Spring工厂创建这个简单对象的时候只创建一次
sigleton:只会创建一次简单对象 不写scope属性默认是sigleton
prototype:每一次都会创建新的对象

   <bean id="account" scope="singleton" class="com.tcgroup.scope.Account"/>

在这里插入图片描述

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

上面已经介绍过,FactoryBean接口有一个 boolean isSingleton()方法需要被实现
返回 true 只会创建一个复杂对象
返回 false 每一次都会创建新的对象

FactoryBean{
   isSingleton(){
      return true  只会创建一次
      return false 每一次都会创建新的
   }
}

如没有isSingleton方法 还是通过scope属性 进行对象创建次数的控制

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

好处:节省不必要的内存浪费,有些可以复用的对象没有必要每次都重新创建

  • 什么样的对象只创建一次?
    可以共用的,线程安全的
1. SqlSessionFactory
2. DAO
3. Service
  • 什么样的对象 每一次都要创建新的?
    不能共用的,线程不安全的
1. Connection
2. SqlSession | Session
3. Struts2 Action
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值