Spring bean实例化,实例化bean的三种方式,依赖注入(DI配置) 详细步骤

Bean的实例化

(与service层无关,换句话 与DI无关,主要讲解IoC创建bean的原理)

Spring创建bean时调用的是无参构造方法,而私有方法能被调用 因为底层用了反射。用构造方法来实例化对象。

对于Spring的报错,从下往上看

1 Bean是如何创建的【理解】

bean本质上就是对象,创建bean使用构造方法完成

2 实例化Bean的三种方式

2.1 构造方法方式【重点】
  • BookDaoImpl实现类
public class BookDaoImpl implements BookDao {
    public BookDaoImpl() {
        System.out.println("book dao constructor is running ....");
    }
    public void save() {
        System.out.println("book dao save ...");
    }
}
  • applicationContext.xml配置
<!--方式一:构造方法实例化bean-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
  • AppForInstanceBook测试类
public class AppForInstanceBook {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");

        bookDao.save();
    }
}
  • 运行结果
    在这里插入图片描述

注意:**无参构造方法如果不存在,将抛出异常BeanCreationException**

2.2 静态工厂方式实例化bean【了解】

我们需要的是工厂里面的OrderDao对象===>配置工厂类名和方法名

  • OrderDao接口和OrderDaoImpl实现类
public interface OrderDao {
    public void save();
}
public class OrderDaoImpl implements OrderDao {
    public void save() {
        System.out.println("order dao save ...");
    }
}
  • OrderDaoFatory工厂类
//静态工厂创建对象
public class OrderDaoFactory {
    public static OrderDao getOrderDao(){
        System.out.println("static factory setup....");
        return new OrderDaoImpl();
    }
}
  • applicationContext.xml配置
<!--方式二:使用静态工厂实例化bean-->
<bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>

在这里插入图片描述

  • AppForInstanceOrder测试类
public class AppForInstanceOrder {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");

        orderDao.save();
    }
}
  • 运行结果
    在这里插入图片描述
2.3 实例工厂方式【了解】

和静态工厂类似,多一个配置步骤 factory-bean="userFactory

  • UserDao接口和UserDaoImpl实现类
public interface UserDao {
    public void save();
}
public class UserDaoImpl implements UserDao {
    public void save() {
        System.out.println("user dao save ...");
    }
}
  • UserDaoFactory工厂类
//实例工厂创建对象
public class UserDaoFactory {
    public UserDao getUserDao(){
        return new UserDaoImpl();
    }
}
  • applicationContext.xml配置
<!--方式三:使用实例工厂实例化bean-->
<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>

<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>

在这里插入图片描述

  • AppForInstanceUser测试类
public class AppForInstanceUser {
    public static void main(String[] args) {
        //        //创建实例工厂对象
        //        UserDaoFactory userDaoFactory = new UserDaoFactory();
        //        //通过实例工厂对象创建对象
        //        UserDao userDao = userDaoFactory.getUserDao();
        //        userDao.save();
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) ctx.getBean("userDao");
        userDao.save();
    }
}
  • 运行结果
    在这里插入图片描述
2.4 实现FactoryBean<T>方式【扩展,了解】
  • 定义UserDaoFactoryBean实现FactoryBean<UserDao>

UserDaoFactoryBean中实例化什么类型的对象泛型就是该类型。

//FactoryBean创建对象
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
    //代替原始实例工厂中创建对象的方法
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    public Class<?> getObjectType() {
        return UserDao.class;
    }
}
  • applicationContext.xml配置
<!--方式四:使用FactoryBean实例化bean-->
<bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>

使用之前的AppForInstanceUser测试类去运行看结果就行了。注意配置文件中id="userDao"是否重复。

代码
package com.itheima;

import com.itheima.dao.OrderDao;
import com.itheima.dao.UserDao;
import com.itheima.factory.OrderDaoFactory;
import com.itheima.factory.UserDaoFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForInstanceOrder {
    //使用工厂创建对象
    public static void main(String[] args) {
        //方法二  静态工厂
                //造对象不要直接new 用工厂的方式做适当的解耦
/*        OrderDao orderDao = OrderDaoFactory.getOrderDao();
        orderDao.save();*/
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        OrderDao orderDao =(OrderDao) ctx.getBean("orderDao");
        orderDao.save();

/*        //方法三    实例工厂  先找到工厂的对象,再用对象调用方法
        UserDaoFactory userDaoFactory = new UserDaoFactory();
        UserDao userDao = userDaoFactory.getUserDao();

        userDao.save();*/


        //Spring 的形式来运行
/*        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        UserDao userDao =(UserDao) ctx.getBean("userDao");

        userDao.save();*/
    }
}

<?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">

<!--1.导入Spring坐标spring-context,对应的版本号是5.2.10.RELEASE    -->
<!--2.配置bean      id随便起-->
<!--方式一   构造方法实例化bean    构造方法默认时无参构造,写不写均可-->
                <!--使用IoC   和   DI    -->
<!--    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        &lt;!&ndash;7.配置server与dao的关系    把dao放到server中&ndash;&gt;
        &lt;!&ndash;property代表当前bean的属性    name中 代表BookServiceImpl  private BookDao bookDao&ndash;&gt;
        &lt;!&ndash;关系绑定&ndash;&gt;
        <property name="bookDao" ref="bookDao" />
    </bean>-->

    <!--方式二:静态工厂实例化bean-->
            <!--这样造出来的对象时factory对象而不是到对象   需要进一步进缩小范围(factory中的dao对象)-getOrderDao() -->
    <bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>


    <!--方式三:实例工厂实例化bean  -->
        <!--工厂的bean造出来    -->
   <!-- <bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>
        &lt;!&ndash;静态工厂直接写class类名,实例化工厂不写class   &ndash;&gt;
    <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>-->
        <!--方式三的变种   去掉了 <bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>   的臃肿-->
    <!--方式四:使用FactoryBean实例bean    -->
        <!--id给个名称,class写定义新的UserFactoryBean       造非单例对象时,接口方法isSingleton  false -->
    <!--<bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>-->



</beans>

依赖注入(DI配置)

1 依赖注入方式【重点】

1.1 依赖注入的两种方式
  • setter注入

    • 简单类型

    • 引用类型(很常用)

  • 构造方法注入

1.2 setter方式注入
问题导入

setter方式注入使用什么子标签?

引用类型

在这里插入图片描述

  • 标签中:使用ref

  • 完整代码:

    public class BookServiceImpl implements BookService{
        private BookDao bookDao;
    
        //setter注入需要提供要注入对象的set方法
        public void setBookDao(BookDao bookDao) {
            this.bookDao = bookDao;
        }
    
        public void save() {
            System.out.println("book service save ...");
            bookDao.save();
        }
    }
    
    <!--注入引用类型-->
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <!--property标签:设置注入属性-->
        <!--name属性:设置注入的属性名,实际是set方法对应的名称-->
        <!--ref属性:设置注入引用类型bean的id或name-->
        <property name="bookDao" ref="bookDao"/>
    </bean>
    
  • 测试

    public class AppForDISet {
        public static void main( String[] args ) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            BookService bookService = (BookService) ctx.getBean("bookService");
            bookService.save();
        }
    }
    
简单类型
  • 简单类型包含:基本类型(int, char, long…)+ 特殊类型String
    在这里插入图片描述

  • 标签中:使用value

  • 完整代码

    public class BookDaoImpl implements BookDao {
    
        private int connectionNum;
        //setter注入需要提供要注入对象的set方法
        public void setConnectionNum(int connectionNum) {
            this.connectionNum = connectionNum;
        }
    
        public void save() {
            System.out.println("book dao save ..."+connectionNum);
        }
    }
    
    <!--注入简单类型-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <!--property标签:设置注入属性-->
        <!--name属性:设置注入的属性名,实际是set方法对应的名称-->
        <!--value属性:设置注入简单类型数据值-->
        <property name="connectionNum" value="100"/>
    </bean>
    
总结
#简单类型使用value,引用类型使用ref
1.3 构造方式注入
问题导入

构造方式注入使用什么子标签?

引用类型

在这里插入图片描述

  • 完整代码

    public class BookServiceImpl implements BookService{
        private BookDao bookDao;
    
        public BookServiceImpl(BookDao bookDao) {
            this.bookDao = bookDao;
        }
    
        public void save() {
            System.out.println("book service save ...");
            bookDao.save();
        }
    }
    
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" />
    
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <constructor-arg name="bookDao" ref="bookDao"/>
    </bean>
    
  • 测试

    public class AppForDIConstructor {
        public static void main( String[] args ) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            BookService bookService = (BookService) ctx.getBean("bookService");
            bookService.save();
        }
    }
    
简单类型

在这里插入图片描述

  • 完整代码

    public class BookDaoImpl implements BookDao {
    
        private int connectionNum;
        private String databaseName;
    
        public BookDaoImpl(String databaseName, int connectionNum) {
            this.databaseName = databaseName;
            this.connectionNum = connectionNum;
        }
    
        public void save() {
            System.out.println("book dao save ..."+databaseName+","+connectionNum);
        }
    }
    
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <!--根据构造方法参数名称注入-->
        <constructor-arg name="connectionNum" value="10"/>
        <constructor-arg name="databaseName" value="mysql"/>
    </bean>
    
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <constructor-arg name="bookDao" ref="bookDao"/>
    </bean>
    
参数适配【了解】

在这里插入图片描述

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
    <!--根据构造方法参数名称注入-->
    <!--<constructor-arg name="connectionNum" value="10"/>-->
    <!--<constructor-arg name="databaseName" value="mysql"/>-->

    <!--根据构造方法参数类型注入-->
    <!--<constructor-arg type="int" value="10"/>-->
    <!--<constructor-arg type="java.lang.String" value="mysql"/>-->

    <!--根据构造方法参数位置注入-->
    <!--<constructor-arg index="0" value="mysql"/>-->
    <!--<constructor-arg index="1" value="100"/>-->
</bean>
1.4 依赖注入方式选择
  1. 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
  2. 可选依赖使用setter注入进行,灵活性强
  3. Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
  4. 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
  5. 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
  6. 自己开发的模块推荐使用setter注入
代码
BookDaoImpl

package com.itheima.dao.impl;
import com.itheima.dao.BookDao;
public class BookDaoImpl implements BookDao {
    private int connectionNum;
    private String databaseName;


    //注入一:set注入
/*    public void setConnectionNum(int connectionNum) {
        this.connectionNum = connectionNum;
    }

    public void setDatabaseName(String databaseName) {
        this.databaseName = databaseName;
    }*/

    //注入二:构造器注入
    public BookDaoImpl(int connectionNum, String databaseName) {
        this.connectionNum = connectionNum;
        this.databaseName = databaseName;
    }

    public void save() {
        System.out.println("book dao..."+ databaseName+","+connectionNum);
    }
}
BookServiceImpl

package com.itheima.service.impl;
import com.itheima.dao.BookDao;
import com.itheima.dao.UserDao;
import com.itheima.service.BookService;

public class BookServiceImpl implements BookService {
    private BookDao bookDao;
    private UserDao userDao;
    
    //注入方法一:set注入
/*    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }*/
    //注入方法二:构造器注入
    public BookServiceImpl(BookDao bookDao, UserDao userDao) {
        this.bookDao = bookDao;
        this.userDao = userDao;
    }

    public void save() {
        System.out.println("book service...");
        bookDao.save();
        userDao.save();
    }
}
AppForDISet

package com.itheima;
import com.itheima.service.BookService;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForDISet {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx= new ClassPathXmlApplicationContext("applicationContext.xml");

        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();

        ctx.close();
    }
}
applicationContext.xml

<?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">

        <!--注入一:set注入   -->
    <!--     <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" >
          <property name="connectionNum" value="10"/>
          <property name="databaseName" value="mySql"/>
       </bean>
     <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
            <property name="bookDao" ref="bookDao" />
        </bean>-->

    <!--注入二:构造器注入   标准书写  推荐使用。其他方法会存在问题-->
<!--    <bean name="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <constructor-arg name="connectionNum" value="10"/>
        <constructor-arg name="databaseName" value="MySql"/>
    </bean>
    <bean name="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <constructor-arg name="bookDao" ref="bookDao"/>
        <constructor-arg name="userDao" ref="userDao"/>
    </bean>-->
    <!--注入二-1:进一步解耦,消除参数捆绑  与形参名不耦合了-->
<!--    <bean name="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <constructor-arg type="int" value="10"/>
        <constructor-arg type="java.lang.String" value="MySql"/>
    </bean>
    <bean name="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <constructor-arg name="bookDao" ref="bookDao"/>
        <constructor-arg name="userDao" ref="userDao"/>
    </bean>-->
    <!--注入二-2:参数位置注入,消除二-1出现两个同类型的数据-->
    <bean name="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <constructor-arg index="0" value="10"/>
        <constructor-arg index="1" value="MySql"/>
    </bean>
    <bean name="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <constructor-arg name="bookDao" ref="bookDao"/>
        <constructor-arg name="userDao" ref="userDao"/>
    </bean>
</beans>

2 依赖自动装配【理解】

问题导入

如何配置按照类型自动装配?

2.1 自动装配概念
  • IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配

  • 自动装配方式

    按类型(常用)

    按名称:

    按构造方法

    不启用自动装配

2.2 自动装配类型
依赖自动装配

配置中使用bean标签autowire属性设置自动装配的类型

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>
依赖自动装配特征
  1. 自动装配用于引用类型依赖注入,不能对简单类型进行操作
  2. 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
  3. 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
  4. 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
<?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 name="bookDao" class="com.itheima.dao.impl.BookDaoImpl" />
    <bean name="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"/>
    </bean>-->
    <!--自动注入    -->
    <bean name="bookDao" class="com.itheima.dao.impl.BookDaoImpl" />
    <!--那边无论写了多少,set方法给够,这边一个autowire 结束-->
    <bean name="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>
</beans>

3 集合注入-07’32

准备工作

在类中添加集合类型属性:添加get,set方法

public class BookDaoImpl implements BookDao {

    private int[] array;

    private List<String> list;

    private Set<String> set;

    private Map<String,String> map;

    private Properties properties;

    public void setArray(int[] array) {
        this.array = array;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    public void save() {
        System.out.println("book dao save ...");

        System.out.println("遍历数组:" + Arrays.toString(array));

        System.out.println("遍历List" + list);

        System.out.println("遍历Set" + set);

        System.out.println("遍历Map" + map);

        System.out.println("遍历Properties" + properties);
    }
}
3.1 注入数组类型数据
<property name="array">
    <array>
        <value>100</value>
        <value>200</value>
        <value>300</value>
    </array>
</property>
3.2 注入List类型数据
<property name="list">
    <list>
        <value>itcast</value>
        <value>itheima</value>
        <value>boxuegu</value>
        <value>chuanzhihui</value>
    </list>
</property>
3.3 注入Set类型数据
<property name="set">
    <set>
        <value>itcast</value>
        <value>itheima</value>
        <value>boxuegu</value>
        <value>boxuegu</value>
    </set>
</property>
3.4 注入Map类型数据
<property name="map">
    <map>
        <entry key="country" value="china"/>
        <entry key="province" value="henan"/>
        <entry key="city" value="kaifeng"/>
    </map>
</property>
3.5 注入Properties类型数据
<property name="properties">
    <props>
        <prop key="country">china</prop>
        <prop key="province">henan</prop>
        <prop key="city">kaifeng</prop>
    </props>
</property>

说明:property标签表示setter方式注入,构造方式注入constructor-arg标签内部也可以写<array>、<list>、<set>、<map>、<props>标签

3.6 验证结果
public class AppForDICollection {
    public static void main( String[] args ) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");

        bookDao.save();
    }
}

在这里插入图片描述

内容来自学习笔记

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

热爱代码的猿猿

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

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

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

打赏作者

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

抵扣说明:

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

余额充值