Spring创建复杂对象

目录

一、什么是复杂对象

二、创建复杂对象的3种方式

2.1 实现FactoryBean接口

2.1.1 普通的创建方式

2.1.1 依赖注入的方式

2.1.3 FactoryBean的工作原理

2.2 实例工厂

2.3 静态工厂


一、什么是复杂对象

书接上回,我们已经分析了Spring是怎么去创建对象的了。那什么是简单对象什么又是复杂对象呢?那简单对象又要怎么去创建呢?

  • 简单对象:能够直接通过new构造方法创建的对象,称为是简单对象
  • 复杂对象:不能通过直接new构造方法创建的对象,称为是复杂对象,例如数据库连接操作的中的Connection对象等

二、创建复杂对象的3种方式

2.1 实现FactoryBean接口

2.1.1 普通的创建方式

1)这里用数据库连接的操作代码为例,首先需要创建一个类用于返回数据库的连接对象,这个类实现了Spring中的FactoryBean的接口(实现这个类当然就需要去重写该类中的方法)

  • 首先返回什么什么对象就在泛型中写该类的对象
  • 第一个方法用于书写创建复杂对象的代码
  • 第二个方法用于返回这个复杂对象的class对象
  • 第三个方法是告知Spring创建的对象是否是单例的  
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/test?useSSL=false","root","123456");
        // 创建好了对象之后将这个对象返回
        return conn;
    }
    @Override
    public Class<?> getObjectType() {
        // 用于返回创建的复杂对象的class对象
        return Connection.class;
    }
    @Override
    public boolean isSingleton() {
        return false;
    }
}

2) 通过Spring的配置文件获取复杂对象。这里需要注意的是,这里通过bean标签获取到的对象和之前写过的配置文件有所不同了,之前这个class属性中对应的是哪个类获取到的就是哪个类的对象,但是在实现了FactoryBean接口的类中这里获取到的对象是创建的复杂对象(后面详说)

<bean id="connection" class="com.gl.demo.factory.ConnectionFactoryBean"/>

3) 接下来进行测试,这里如果成功打印则说明拿到的确实是Connection对象而不是ConnectionFactoryBean对象,通过测试可以发现获取到的对象就是Connection对象

@Test
public void test5() {
    ApplicationContext ctx =
            new ClassPathXmlApplicationContext("applicationContext.xml");
    Connection conn = (Connection) ctx.getBean("connection");
    System.out.println("conn = "+conn);
}

4)如果只是想获取ConnectionFactoryBean对象呢?这也是可以解决的,在getBean方法的参数中加上&符号即可,此时获取到的就是ConnectionFactoryBean对象了

public void test6() {
    ApplicationContext ctx =
            new ClassPathXmlApplicationContext("applicationContext.xml");
    ConnectionFactoryBean conn = (ConnectionFactoryBean) ctx.getBean("&connection");
    System.out.println("conn = "+conn);
}

2.1.1 依赖注入的方式

通过上述方式成功的获取到了复杂对象,但是这里细心一点就会发现,如果我的数据库更换了,或者这里的密码也更换了呢?那就需要去修改代码,那是不是就耦合了?耦合了怎么解决呢?是不是就可以利用前面所说的依赖注入解决啊!接下来修改代码

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

    public void setDriveClassName(String driveClassName) {
        this.driveClassName = driveClassName;
    }

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

    public void setUsername(String username) {
        this.username = username;
    }

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

    @Override
    public Connection getObject() throws Exception {
        // 用于创建复杂对象的代码
        // 创建数据库的连接对象
        Class.forName(driveClassName);
        Connection conn =
                DriverManager.getConnection(url,username,password);
        // 创建好了对象之后将这个对象返回
        return conn;
    }
    @Override
    public Class<?> getObjectType() {
        // 用于返回创建的复杂对象的class对象
        return Connection.class;
    }
    @Override
    public boolean isSingleton() {
        return false;
    }
}
<bean id="connection" class="com.gl.demo.factory.ConnectionFactoryBean">
    <property name="driveClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
</bean>

2.1.3 FactoryBean的工作原理

其实这里的核心就是一个接口回调。当我们通过getBean方法去获取这个连接对象的时候,Spring首先会通过instanceof方法去判断是不是实现了FactoryBean类,如果是的话Spring就会调用getObject方法返回连接对象,这也就是前面所说的为什么返回的不是ConnectionFactoryBean对象而是Connection对象。

2.2 实例工厂

这里可能就会有疑问了,为什么有了创建复杂对象的方式还要学这个实例工厂的方式呢?这是因为在写项目的过程中可能这个连接对象已经创建好了,我们只要去使用就行了。好,那我直接将这个代码实现FactoryBean接口不就可以了吗?其实这里你也不确定能不能拿到源码文件,如果是class文件呢?这也就是学习实例工厂的原因

1)假设这里已经有了连接对象的class文件,当然这里是有耦合的,但是为了演示简洁就不在写配置文件了,大家知道即可

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

2)有了这个类之后是不是就需要获取到这个类对象,然后再通过这个类对象调用getConnection方法。但是如果通过getBean方法获取再调用就显得麻烦,这里就可以通过使用实例工厂进行整合。这里引出两个标签属性一个是factory-bean表示整合哪个类,另一个factory-method表示类中的哪个方法。

<bean id="connFactory" class="com.gl.demo.factory.ConnectionFactory"/>
<bean id="conn" factory-bean="connFactory" factory-method="getConnection"/>

 

2.3 静态工厂

这里的静态工厂其实与实例工厂是差不多的,只是方法是静态的,所以和实例工厂只有细微的区别

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

静态的方法可以通过类直接调用,那这个配置文件的写法也就明确了,直接在这个类对象中写上factory-method即可

<bean id="conn1" class="com.gl.demo.factory.StaticConnectionFactory" factory-method="getConnection"/>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值