Spring-bean实例化三种方式

发布于:2022-11-09 ⋅ 阅读:(6) ⋅ 点赞:(0) ⋅ 评论:(0)

bean实例化三种方式:

  • 构造方法(常用)!
  • 静态工厂(了解)
  • 实例工厂(了解)
    • FactoryBean(实用)!

环境准备:

  • 创建一个Maven项目
  • pom.xml添加Spring依赖
  • resources下添加spring的配置文件applicationContext.xml

1.构造方法实例化(常用)

步骤1.准备需要的类BookDao和BookDaoImpl类

package com.hnu.dao.impl;
import com.hnu.dao.BookDao;
//实现接口
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }

//运行程序,如果控制台有打印构造函数中的输出,说明Spring容器在创建对象的时候也用的是构造函数
//通过反射的方式获取对象 使用无参构造  无参构造只要当容器被加载就会被执行
//几遍是private修饰也执行,因为Spring默认使用了构造函数创建对象
    private BookDaoImpl() {
        System.out.println("book dao constructor is running ....");
    }

//有参构造 当即有有参构造又有无参构造,运行会报错
/*private BookDaoImpl(int i) {
    System.out.println("有参构造 is running ....");
}*/
}



package com.hnu.dao;
//先创建接口,然后创建实现类,最后在App类中引用实现
public interface BookDao {
    public void save();
}

步骤2:将类配置到Spring容器

version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--bean标签标示配置bean
    	id属性标示给bean起名字
    	class属性表示给bean定义类型
	-->
    <!--name:为bean指定别名,别名可以有多个,使用逗号,分号,空格进行分隔-->
    <!--`singleton`默认为单例-->
    <bean id="bookDao" name="dao bookDaoImpl" class="com.hnu.dao.impl.BookDaoImpl"/>

步骤3:编写运行程序

package com.hnu;
import com.hnu.dao.BookDao;
import com.hnu.dao.impl.BookDaoImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForInstanceBook {
    public static void main(String[] args) {
        //获得容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //从容器中获取对象进行方法调用
        BookDao  bookDao = (BookDao)ctx.getBean("dao");
        //调用方法
        bookDao.save();
    }
}

image-20221109094632439

运行结果:

image-20221109095511750

如果把前面的有参构造注释取消掉,这时候同时存在有参和无参构造,也不会报错

image-20221109095957563

但是如果把无参构造注释掉。只留下个有参构造,这时候就要报错了,注意一点对于Spring的不报错,我们要从下往上来看,下面的是一些根本性错误(最核心错误),然后依次往上看,

比如:

最后一行:

Caused by: java.lang.NoSuchMethodException: com.hnu.dao.impl.BookDaoImpl.<init>()

  • Caused by 翻译为引起,即出现错误的原因
  • java.lang.NoSuchMethodException:抛出的异常为没有这样的方法异常
  • com.hnu.dao.impl.BookDaoImpl.<init>():哪个类的哪个方法没有被找到导致的异常,<init>()指定是类的构造方法,即该类的无参构造方法

如果最后一行错误获取不到错误信息,接下来查看第二层:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.hnu.dao.impl.BookDaoImpl]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.hnu.dao.impl.BookDaoImpl.<init>()

  • nested:嵌套的意思,后面的异常内容和最底层的异常是一致的
  • Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.hnu.dao.impl.BookDaoImpl]: No default constructor found;
    • Caused by: 引发
    • BeanInstantiationException:翻译为bean实例化异常
    • No default constructor found:没有一个默认的构造函数被发现

image-20221109100144433

2.静态工厂实例化

首先准备一下环境,划红线的是上一个构造方法的类,不用管

image-20221109133507744

步骤1:创建OrderDao和OrderDaoImpl类

package com.hnu.dao;
public interface OrderDao {
    public void save();
}


package com.hnu.dao.impl;
import com.hnu.dao.OrderDao;
public class OrderDaoImpl implements OrderDao {
    public void save() {
        System.out.println("order dao save...");
    }
}

步骤2:创建一个工厂类OrderDaoFactory并提供一个静态方法

package com.hnu.factory;

import com.hnu.dao.OrderDao;
import com.hnu.dao.impl.OrderDaoImpl;

//静态工厂实例化,返回一个OrderDaoImpl实现对象
public class OrderDaoFactory {
    public static OrderDao getOrderDao(){
        return new OrderDaoImpl();
    }
}

步骤3:将类配置到Spring容器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

      <!--静态实例化工厂-->
    <bean id="orderDao" name="orderDao1" class="com.hnu.factory.OrderDaoFactory" factory-method="getOrderDao"/>

步骤4:创建调用运行的执行类AppForInstanceOrder

package com.hnu;
import com.hnu.dao.OrderDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForInstanceOrder {
    public static void main(String[] args) {
        
//用spring来管理工厂
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        OrderDao orderDao = (OrderDao) ctx.getBean("orderDao1");
        orderDao.save();
    }
}

运行结果:

image-20221109134244346

大致步骤为:

先创建接口然后用一个实现类实现接口方法,然后创建一个静态工厂,工厂返回实现类对象,在IOC容器中创建工厂对象,然后在实现类中获取容器并且调用方法

3.实例工厂与FactoryBean

1.实例工厂实例化

环境准备:

image-20221109153625036

步骤1:准备一个UserDao和UserDaoImpl类

package com.hnu.dao;
public interface UserDao {
    public void save();
}



package com.hnu.dao.impl;
import com.hnu.dao.UserDao;
public class UserDaoImpl implements UserDao {
    public void save() {
        System.out.println("user dao save ...");
    }
}

步骤2:创建一个工厂类UserDaoFactory

package com.hnu.factory;
import com.hnu.dao.UserDao;
import com.hnu.dao.impl.UserDaoImpl;
public class UserDaoFactory {
    public UserDao getUserDao() {
        //返回一个实现类对象去实现接口中的方法,注意这里不是静态工厂了哦
        return new UserDaoImpl();
    }
}

步骤3:将类配置到Spring容器

<!--实例化工厂 先获得工厂然后实例化对象-->
    <bean id="userDaoFactory" class="com.hnu.factory.UserDaoFactory"/>
    <bean id="userDao" factory-bean="userDaoFactory" factory-method="getUserDao"/>

实例化工厂运行的顺序是:

  • 创建实例化工厂对象,对应的是第一行配置

  • 调用对象中的方法来创建bean,对应的是第二行配置

    • factory-bean:工厂的实例对象

    • factory-method:工厂对象中的具体创建对象的方法名,对应关系如下:

image-20221109154039384

步骤4:创建调用运行的执行类AppForInstanceUser

package com.hnu;
import com.hnu.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForInstanceUser {
    public static void main(String[] args) {
        //获取容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取bean对象
        UserDao userDao = (UserDao) ctx.getBean("userDao");
        //执行方法
        userDao.save();
    }
}

执行结果:

image-20221109154321279

2.FactoryBean使用

简化实例工厂开发

创建一个UserDaoFactoryBean工厂类

image-20221109155450816

package com.hnu.factory;
import com.hnu.dao.UserDao;
import com.hnu.dao.impl.UserDaoImpl;
import org.springframework.beans.factory.FactoryBean;

import javax.jws.soap.SOAPBinding;

//使用接口的形式,实现工厂模式 实例化Bean
public class UserDaoFactoryBean implements FactoryBean<UserDao> {

    //替代原来实例工厂中创建对象的方法
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }
    //返回所创建类的class对象
    public Class<?> getObjectType() {
        return UserDao.class;
    }

    //创建的对象是否是单例化
    public boolean isSingleton() {
        return false;
    }
}

将类配置到Spring容器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="userDao" class="com.hnu.factory.UserDaoFactoryBean"/>

运行类和前面实例化工厂一样,这里验证创建的对象是否是单例化

package com.hnu;

import com.hnu.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForInstanceUser {
    public static void main(String[] args) {
        //获取容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取bean对象
        UserDao userDao = (UserDao) ctx.getBean("userDao");
        UserDao userDao1 = (UserDao) ctx.getBean("userDao");
        //执行方法
        userDao.save();
        System.out.println(userDao);
        System.out.println(userDao1);
    }
}

运行结果:

image-20221109155819845