Spring复杂对象的3中创建方法

2023-09-17 10:36:52

复杂对象是相对于简单对象可以直接 new 出的对象。这种对象在 Spring 中不可以通过简单对象的创建方式来创建。下面我们将通过实现 FactoryBean 接口、实例工厂、静态工厂三种方法来创建。

FactoryBean 接口

Spring 提供 FactoryBean 接口并且提供了 getObject 方法是为了支持自定义工厂。通过实现这个和接口,可以在获取 Bean 的时候执行一些定制化的操作,如返回一个特定的实例,或者根据特定条件来决定为 singleton 或者 prototype 类型。

getObject 方法允许自定义 Bean 创建过程,可以在这力编写自己的逻辑来决定返回的对象。并且在 getObjectType 方法中设定返回对象的类型。

注意:在实现这个接口的时候在后面指定的泛型是在配置文件中获取的对象类型,而不是实现接口的类对象。

代码演示:

ConnectionFactoryBean implements FactoryBean<Connection> :

注: isSingleton() 设定返回对象是否为单例模式

package com.day2springInject.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;


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

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

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

    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;
    }


}

applicaitonContext.xml :

<!--    数据库连接。复杂对象的创建这里的对象是实现类的对象而不是调用类的     -->
    <bean id="conn" class="com.day2springInject.factorybean.ConnectionFactoryBean">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/mp"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>

</bean>

TestSpring:

    @Test
    public void test12() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
        Connection conn = (Connection) ctx.getBean("conn");  //  得到的是 Connection 对象
        Connection conn2 = (Connection) ctx.getBean("conn"); // 测试 isSingleton
        System.out.println(conn);
        System.out.println(conn2);
    }

运行截图: 

如果想要获取到原类的对象需要在getBean中加上 &

    @Test
    public void test13() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
        ConnectionFactoryBean conn = (ConnectionFactoryBean) ctx.getBean("&conn");  // 这样获得的不是实现类对象了 而是调用类对象
        System.out.println(conn);
    }

 

 实例工厂

实例工厂是为了解决

整合遗留系统:在之前的项目中没有使用 Spring 的项目使用最常规的 new 的方式来实现,需要修改成 Spring 项目但是无法修改源码的情况下,我们只能通过添加配置的方法了实现。

避免 Spring 框架的耦合:

代码耦合度越低越好,但是这样创建项目会使返回对象类型依赖于创建类,所以我们要解除这种耦合。

原来的 Connction 类:

public class ConnectionFactory {

    public Connection getConnection() {
        Connection conn = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mp","root","123456");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }
}

我们一看便知,这种创建放法在不让改变代码的前提下变成 Spring 项目并添加对象依赖,只能通过添加依赖的方法,我们需要操作如下两步:

1.添加 Connection 的依赖

我们想要获取连接对象必须先获取到他的类才可以进行下去,所以先将 Connction 注册进去。

<bean id="connFactory" class="com.day2springInject.factorybean.ConnectionFactory"/>

但是这样有问题存在,就是连接对象是依赖于 Connection 的,这样不就和 Spring 降耦合的理念违背了?而且使用效果不好,所以我们还需要将这个连接对象创建出来也就是 conn 对象。

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

这里的 factory-bean 是将 “connFactory” 这恶鬼bean作为工厂来创建 conn1 这个对象,factory-method 指定了工厂方法,也就是说通过 connFactory 这个对象的 getConnection 方法来创建 conn1。

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

 

静态工厂

静态工厂是为了创建静态方法中的返回对象的工厂,因为静态方法的调用相对于实例方法可以省略创建的一步,也就是直接通过类对象.方法来使用,也就是staticConnextionFactort.getConnection() 。如果在不修改代码的前提下想要变为 Spring 管理,也是只能通过添加配置的方式来注册。

<bean id="conn2" class="com.day2springInject.factorybean.StaticConnectionFactory" factory-method="getConnection"></bean>

可能你会好奇,都是创建对象,为什么静态工厂好像再还没创建出实例来就可以获取类的类型了。

应该可以这么理解,就是说在<bean>注册的时候,如果还没注册完成也就是没有到</bean>的时候是没有注册出对象的,而是获取到了Class类。所以这也就是实例对象为什么需要两步的原因,而静态对象少一步的原因。

更多推荐

【java】【SpringBoot】【三】开发实用篇 基于SpringBoot整合任意第三方技术

目录一、热部署1、手动启动热部署2、自动启动热部署3、热部署范围配置4、关闭热部署二、配置高级1、@ConfigurationProperties2、宽松绑定/松散绑定3、常用计量单位绑定4、数据校验三、测试1、加载测试专用属性2、加载测试专用配置3、web环境模拟测试3.1模拟端口3.2虚拟请求测试3.3匹配响应执行

锂离子电池和电池组安全使用指南

声明本文是学习GB-T42729-2023锂离子电池和电池组安全使用指南.而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们1范围本文件提供了锂离子电池和电池组使用过程中的安全指导和建议,给出了锂离子电池和电池组制造厂商向用户提供可能发生危险的相关信息。本文件适用于锂离子电池和电池组的使用。2规范性引

系统架构设计师(第二版)学习笔记----信息安全基础知识

【原文链接】系统架构设计师(第二版)学习笔记----信息系统基础文章目录一、信息安全的概念1.1信息安全的基本要素1.2信息安全的内容1.3设备安全的内容1.4数据安全的内容1.5内容安全的含义1.6行为安全的含义二、信息存储安全2.1信息存储安全的内容有:2.2信息使用安全的内容2.3用户的标识与验证方法2.4用户存

【Docker】Docker安全性与安全实践(五)

前言:Docker安全性的作用和意义在于确保容器化应用程序和镜像的隔离性、保护数据和系统资源、防止恶意攻击,以及提高应用的整体安全性。文章目录1.Docker安全性1.1`隔离性`1.2`镜像安全`1.3`特权访问`1.4`数据保护`2.Docker安全实践2.1`使用官方镜像或可信源`2.2`更新和修补镜像`2.3`

【Rust 基础篇】Rust中的不安全函数:解锁系统级编程的黑盒之门

导言Rust是一种以安全性和高效性著称的系统级编程语言。它的设计哲学是在不损失性能的前提下,保障代码的内存安全和线程安全。为了实现这一目标,Rust引入了"借用检查器"和"所有权系统"等特性,有效地避免了空指针、数据竞争等常见的安全问题。然而,有些场景下,为了完成某些高级操作或者与底层交互,Rust需要突破其安全边界。

工业交换机为什么有必要进行老化测试?

我们可以根据客户的要求来制定老化测试的检测标准,如果没有特别的要求,我们将依照国家相应的标准进行老化测试检验。老化测试的主要目的是通过模拟产品在现实使用过程中所面临的各种恶劣条件,对产品进行高强度的测试。同时,根据产品的使用要求,合理预测其使用寿命。老化测试是为了确保产品达到满意的合格率,几乎所有产品在出厂前都必须经过

Golang使用Channel

1.使用协程packagemain//使用协程import("fmt""strconv""time")functest(){fori:=1;i<=10;i++{fmt.Println("test()helloworld"+strconv.Itoa(i))time.Sleep(time.Second)}}//主线程和te

开源与区块链:去中心化的未来

🌷🍁博主猫头虎带您GotoNewWorld.✨🍁🦄博客首页——猫头虎的博客🎐🐳《面试题大全专栏》文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺🌊《IDEA开发秘籍专栏》学会IDEA常用操作,工作效率翻倍~💐🌊《100天精通Golang(基础入门篇)》学会Golang语言,畅玩云原生,走遍大

ddns有什么作用?无公网IP怎么将内网IP端口映射外网访问

DDNS是什么?DDNS英文全称DynamicDomainNameServer,中文含义是指动态域名服务。很多普通路由器或者智能路由器设置中,都可以找到DDNS(动态DNS)功能。上面的解释可能过于专业,其实DDNS通俗点说,它是一种将用户的动态IP地址映射到一个固定的域名解析服务上的功能,因为现在目前大多数路由器拨号

如何将内网ip映射到外网?快解析内网穿透

关于内网ip映射到外网的问题,就是网络地址转换,私网借公网。要实现这个,看起来说得不错,实际上是有前提条件的。要实现内网ip映射到外网,首先要有一个固定的公网IP,可以从运营商那里得到。当你得到公网IP后,你的私网有可能有多台主机,都要挂到公网上,这时候会用到DMZ。比如,你有一个公网IP,也可能是通过快解析等得到,你

R语言绘制PCA双标图、碎石图、变量载荷图和变量贡献图

1、原论文数据双标图代码:setwd("D:/Desktop/0000/R")#更改路径#导入数据df<-read.table("Inputdata.csv",header=T,sep=",")#-----------------------------------#所需的包:packages<-c("ggplot2"

热文推荐