Spring 从入门到精通 (十) 复杂对象详解

关键词:Spring | 复杂对象

本专栏通过理论和实践相结合,系统学习框架核心思想及简单原理,原创不易,如果觉得文章对你有帮助,点赞收藏支持博主 ✨

在这里插入图片描述

一、什么是简单对象?

可以直接 new 构造方法来创建的对象,就是简单对象,反射底层一样会调用构造方法

二、什么是复杂对象?

不能直接通过 new 构造方法创建的对象

举例:常见的 jdbc 中的 Connection 对象,mybatis 中的 SqlSessionFactory 对象

三、Spring工厂创建复杂对象的三种方式

  • FactoryBean接口
  • 实例工厂
  • 静态工厂

3.1、FactoryBean接口

现在想把 jdbc 中的 Connection 对象也交给 Spring 创建

首先,在 pom 中引入 MySQL 驱动 jar 包

<!--MySQL驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.48</version>
</dependency>

开发自己的 FactoryBean

package factorybean;


import org.springframework.beans.factory.FactoryBean;

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

public class ConnectionFactoryBean implements FactoryBean<Connection> {

    // 写创建复杂对象的代码
    @Override
    public Connection getObject() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/zhou", "root", "root");
        return conn;
    }

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

    // 是否为单例
    @Override
    public boolean isSingleton() {
        return true;
    }
}

spring配置文件

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

测试

@Test
public void t3() {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring.xml");
    Connection conn = (Connection) context.getBean("conn");
    System.out.println(conn);
}
com.mysql.jdbc.JDBC4Connection@591ac8

3.1.1、FactoryBean细节1

如果我们在获取是,在 id 前加上“&”符号,那么获取的将不再是复杂对象,而是 ConnectionFactoryBean 对象

@Test
public void t4() {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring.xml");
    ConnectionFactoryBean conn = (ConnectionFactoryBean) context.getBean("&conn");
    System.out.println(conn);
}
factorybean.ConnectionFactoryBean@18edcc5

3.1.2、单例还是多例?

如果对象能够被公用,就设置为单例,即返回 true ,否则设置为多例,返回false,jdbc 的 Connection 对象在事务处理时,明显不可以公用,因此使用多例比较合适,而 MyBatis 的 SqlSessionFactory 是重量级的对象,因此使用单例更为合适,其他对象可以根据上述原则配置即可。

3.1.3、SSL证书错误处理

由于mysql版本问题,你可能会遇到报错说没有使用ssl证书,因为mysql为了保证更加安全,添加了ssl证书验证,当然我们是没有的哈,只需要在url上配置一下就不在提示了。

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

3.1.4、耦合优化

ConnectionFactoryBean中用户名,密码,url等等参数直接通过字符串的形式写在了程序里,使用了硬编码,耦合了,我们使用依赖注入来解决这块的耦合。

依赖这几个字符串,就把他们声明为成员变量,并提供set方法

package factorybean;


import org.springframework.beans.factory.FactoryBean;

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

public class ConnectionFactoryBean implements FactoryBean<Connection> {

    private String driverClassName;
    private String url;
    private String username;
    private String password;

    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 getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    // 写创建复杂对象的代码
    @Override
    public Connection getObject() throws Exception {
        Class.forName(driverClassName);
        return DriverManager.getConnection(url, username, password);
    }

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

    // 是否为单例
    @Override
    public boolean isSingleton() {
        return true;
    }
}

在Spring配置文件中完成注入

<bean id="conn" class="factorybean.ConnectionFactoryBean">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/zhou?useSSL=false"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</bean>

再次测试

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

没有任何问题

com.mysql.jdbc.JDBC4Connection@13f604a

就这样,轻松的解决了耦合问题,这就是Spring。

3.1.5、FactoryBean实现原理

  1. 通过配置文件获取 conn 信息,并通过 instanceof 判断是否是 FactoryBean 的实现类
  2. Spring 按照接口规定调用 getObject() —> Connection
  3. 返回 Connection

3.2、实例工厂

目的: 避免Spring框架的侵入,整合遗留系统

ConnectionFactory

package factorybean;

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

public class ConnectionFactory {

    public Connection getConnection() {
        Connection conn = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/zhou?useSSL=false", "root", "root");
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

}

spring.xml

<bean id="connectionFactory" class="factorybean.ConnectionFactory"/>

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

test

@Test
public void t5() {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring.xml");
    Connection conn = (Connection) context.getBean("con");
    System.out.println(conn);
}
com.mysql.jdbc.JDBC4Connection@fcf36f

3.3、静态工厂

StaticConnectionFactory

public class StaticConnectionFactory {
    public static Connection getConnection() {
        Connection connection = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/zhou?useSSL=false", "root", "root");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
}

spring.xml

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

test

@Test
public void t3() {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring.xml");
    Connection conn = (Connection) context.getBean("conn");
    System.out.println(conn);
}
com.mysql.jdbc.JDBC4Connection@1aab8c6

四、总结

在这里插入图片描述

五、写在最后

座右铭:不要在乎别人如何看你,要在乎你自己如何看未来,看梦想,看世界…!

一起学习的可以私信博主或添加博主微信哦。

专栏:订阅专栏 ✅
关注:关注博主 🆙

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

王子周棋洛

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

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

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

打赏作者

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

抵扣说明:

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

余额充值