Spring控制反转、依赖注入、复杂对象、控制对象的创建次数

1.IOC、DI、复杂对象 相关概念

1.1 控制反转 IOC

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

1.2 依赖注入 DI

	注入:通过Spring的工厂及配置文件,为对象(bean,组件)的成员变量赋值(get set)
	依赖注入:当一个类需要另一个类的时候,就意味着依赖,,一旦出现依赖,就可以把另一个类作为本类的成员变量,最终通过Spring配置文件进行注入(赋值)

1.3 复杂对象

	简单对象:可以直接通过new 构造方法创建的对象(Person)
	复杂对象:不能直接通过new 构造创建的对象(sqlSessionFactory...),重量级资源

2.创建复杂对象的三种方式

2.1 FactoryBean接口

步骤:实现FactoryBean工厂,实现三个方法,在spring配置文件中配置

重点看后面实现的那三个方法

写一个ConnectionFactoryBean,实现接口:

2.1.1 依赖注入的体会

Class.forName(driverClassName);
Connection conn = DriverManager.getConnection(url,username,pwd);
创建Connection需要三个属性,这时就产生了依赖,通过配置注入到属性中,再进行使用,将程序的耦合度降低。

package zyc.stu.Spring5_34_44.FactoryBeanTest;

import java.sql.Connection;
import java.sql.DriverManager;
import org.springframework.beans.factory.FactoryBean;

/**
 * @author zhuZiGe_
 * @create 2020-09-10-9:30
 */
public class ConnectionFactoryBean implements FactoryBean<Connection> {
    private String driverClassName;
    private String url;
    private String username;
    private String pwd;

    public String getDriverClassName() {
        return driverClassName;
    }

    public void setDriverClassName(String driverClassName) {
        this.driverClassName = driverClassName;
    }

    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 getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    //实现三个方法

    public Connection getObject() throws Exception {
        Class.forName(driverClassName);
        Connection conn = DriverManager.getConnection(url,username,pwd);
        return conn;
    }

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

    public boolean isSingleton() {
        return false;
    }
}

xml文件配置:

    <bean id="conn" class="zyc.stu.Spring5_34_44.FactoryBeanTest.ConnectionFactoryBean">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/springdemo?useSSL=false"/>
        <property name="username" value="root"/>
        <property name="pwd" value="root"/>
    </bean>

测试:

    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml");
        Connection conn = (Connection) context.getBean("conn");
        System.out.println(conn);
    }

细节:

  • context.getBean("conn") 获得的是FactoryBean接口的泛型指定类:自动调用了重写的第一个方法getObject(),得到的是内部创建的复杂对象

  • isSingleton():控制了此复杂对象的创建次数

       返回false:不是单例,每次创建新的对象
       返回true:是单例,拿着上次创建的对象
       ----------------------------------------------
       问题:什么时候返回ture?(参考JDBC中)
       		根据需要,例如Connection,不能共用,每次都要创建新的连接,而SqlSessionFactory耗资源,只要一个就够了
    
  • FactoryBean的工作原理:context.getBean(“conn”)

     首先,根据conn标签获得<bean>相关信息,并判断instanceof(FactoryBean)实现类
     其次,根据判断结果,是FactoryBean的实现类,去找getObject方法
     最后,调用getObject方法,将里面创建的复杂对象拿到
    

2.2 实例工厂

用途1:避免Spring框架的侵入(FactoryBean接口导致整个系统依赖于Spring)
用途2:整合遗留系统:
      从现有的基础继续开发,没有源文件.java可供修改,只有编译好的.class文件时
      没有源文件就无法实现FactoryBean接口

例:ConnectionFactory中是用的原始的方法实现复杂对象的创建,想得到复杂对象,必须实例化ConnectionFactory再调用getConnection方法,这时只需要在配置文件中集成这个遗留就行。

下面模拟一个遗留下来的实例:
先创建遗留实例的bean,将其纳入Spring管理,再创建新的bean,指明bean和想要调用的方法。

package zyc.stu.Spring5_34_44.FactoryBeanTest;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * @author zhuZiGe_
 * @create 2020-09-10-12:35
 */
public class ConnectionFactory {
    public Connection getConnection(){
        Connection conn=null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/springdemo?useSSL=false","root","root");

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return conn;
    }
}

在xml文件中配置:我只想拿你内部那个方法获取复杂对象而已

    <bean id="connFactory" class="zyc.stu.Spring5_34_44.FactoryBeanTest.ConnectionFactory"></bean>

    <bean id="connSL" factory-bean="connFactory" factory-method="getConnection"/>   

测试:

    @Test
    public void test2() {
        ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml");
        Connection connSL = (Connection) context.getBean("connSL");
        System.out.println(connSL);
    }

2.3 静态工厂

  1. 静态工厂和实例工厂大致相同,只不过工厂中的方法是静态的。
  2. 配置文件中,不用创建静态工厂的bean再去引用,直接使用class属性指定类,再指定调用的方法。

将上面的类名ConnectionFactory改为StaticConnectionFactory,并在方法上标记static,主要看xml文件中如何配置

<bean id="staticConnectionFactory" class="zyc.stu.Spring5_34_44.FactoryBeanTest.StaticConnectionFactory" factory-method="getConnection"/>

3.控制对象的创建次数

3.1 控制简单对象的创建次数

在配置文件中进行配置:
sigleton:只会创建⼀次简单对象,默认值;
prototype:每⼀次都会创建新的对象;

3.2 控制复杂对象的创建次数

通过isSingleton()方法控制:参考本文 2.1
public boolean isSingleton() { return true/false; }

3.3 如果是实例工厂或者静态工厂,没有 isSingleton ⽅法,与简单对象一样通过 scope 控制。

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

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

什么样的对象只创建⼀次?

  • 重量级的、可以被共用的、线程安全的…
    SqlSessionFactory | DAO | Service

什么样的对象每⼀次都要创建新的?

  • 不能被共用的,线程不安全的…
    Connection | SqlSession | Session
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值