• 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创建的对象是否是单例的  
    1. public class ConnectionFactoryBean implements FactoryBean {
    2. @Override
    3. public Connection getObject() throws Exception {
    4. // 用于创建复杂对象的代码
    5. // 创建数据库的连接对象
    6. Class.forName("com.mysql.jdbc.Driver");
    7. Connection conn =
    8. DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false","root","123456");
    9. // 创建好了对象之后将这个对象返回
    10. return conn;
    11. }
    12. @Override
    13. public Class getObjectType() {
    14. // 用于返回创建的复杂对象的class对象
    15. return Connection.class;
    16. }
    17. @Override
    18. public boolean isSingleton() {
    19. return false;
    20. }
    21. }

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

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

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

    1. @Test
    2. public void test5() {
    3. ApplicationContext ctx =
    4. new ClassPathXmlApplicationContext("applicationContext.xml");
    5. Connection conn = (Connection) ctx.getBean("connection");
    6. System.out.println("conn = "+conn);
    7. }

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

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

    2.1.1 依赖注入的方式

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

    1. public class ConnectionFactoryBean implements FactoryBean {
    2. private String driveClassName;
    3. private String url;
    4. private String username;
    5. private String password;
    6. public void setDriveClassName(String driveClassName) {
    7. this.driveClassName = driveClassName;
    8. }
    9. public void setUrl(String url) {
    10. this.url = url;
    11. }
    12. public void setUsername(String username) {
    13. this.username = username;
    14. }
    15. public void setPassword(String password) {
    16. this.password = password;
    17. }
    18. @Override
    19. public Connection getObject() throws Exception {
    20. // 用于创建复杂对象的代码
    21. // 创建数据库的连接对象
    22. Class.forName(driveClassName);
    23. Connection conn =
    24. DriverManager.getConnection(url,username,password);
    25. // 创建好了对象之后将这个对象返回
    26. return conn;
    27. }
    28. @Override
    29. public Class getObjectType() {
    30. // 用于返回创建的复杂对象的class对象
    31. return Connection.class;
    32. }
    33. @Override
    34. public boolean isSingleton() {
    35. return false;
    36. }
    37. }
    1. <bean id="connection" class="com.gl.demo.factory.ConnectionFactoryBean">
    2. <property name="driveClassName" value="com.mysql.jdbc.Driver"/>
    3. <property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false"/>
    4. <property name="username" value="root"/>
    5. <property name="password" value="123456"/>
    6. bean>

    2.1.3 FactoryBean的工作原理

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

    2.2 实例工厂

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

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

    1. public class ConnectionFactory {
    2. public Connection getConnection() {
    3. Connection conn = null;
    4. try {
    5. Class.forName("com.mysql.jdbc.Driver");
    6. conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false","root","123456");
    7. } catch (ClassNotFoundException e) {
    8. e.printStackTrace();
    9. } catch (SQLException e) {
    10. e.printStackTrace();
    11. }
    12. return conn;
    13. }
    14. }

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

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

     

    2.3 静态工厂

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

    1. public class StaticConnectionFactory {
    2. public static Connection getConnection() {
    3. Connection conn = null;
    4. try {
    5. Class.forName("com.mysql.jdbc.Driver");
    6. conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false","root","123456");
    7. } catch (ClassNotFoundException e) {
    8. e.printStackTrace();
    9. } catch (SQLException e) {
    10. e.printStackTrace();
    11. }
    12. return conn;
    13. }
    14. }

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

    <bean id="conn1" class="com.gl.demo.factory.StaticConnectionFactory" factory-method="getConnection"/>
    
  • 相关阅读:
    deepFm系列
    flutter中使用缓存
    2.继承总结方法
    国产AD+全志T3开发案例,为能源电力行业排忧解难!8/16通道
    Kubernetes中的探针机制
    8.ProForm 遇到表单的label ,文案可能过长
    农牧行业全产业链20+业务用契约锁电子签,释放成本、提效90%
    pumping lemma
    LSF_SPAN
    HLS入门
  • 原文地址:https://blog.csdn.net/x2656271356/article/details/133948880