【JAVA】Spring(上)bean的实例化与注入

目录

【Spring】

【Spring Framework系统框架4.x】

【IoC】—— Inversion of Control 控制反转

【Spring技术对IoC思想进行了实现】

【DI】—— Dependency Injection 依赖注入

【目标】—— 充分解耦

【IoC使用】

【DI使用】

【bean】

【基础配置】

【别名配置】

【作用范围配置】​编辑

【bean的三种实例化方式】

【第一种】—— 构造方法

【第二种】—— 静态工厂

【第三种】—— 实例工厂

【bean生命周期】

【bean生命周期控制】

【bean销毁时机】

【依赖注入方式(两种)】

【setter注入】

【构造器注入】

【可优化构造器注入】—— 参数配置(依然有弊端)

【依赖注入方式选择】

【依赖自动装配】

【集合注入】

【案例】—— 数据源对象管理

【加载properties文件】

【使用】

【其他功能使用】


【Spring】

【官网】

Spring | Home

【Spring Framework系统框架4.x】

【IoC】—— Inversion of Control 控制反转

【概述】

使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转

【Spring技术对IoC思想进行了实现】

  • Spring提供了一个容器,称为IoC容器,用来充当IoC思想中的“外部
  • IoC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean

【DI】—— Dependency Injection 依赖注入

【概述】

在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入

【目标】—— 充分解耦

【方法】

  • 使用IoC容器管理beanIoC)
  • 在IoC容器内将有依赖关系的bean进行关系绑定(DI

【IoC使用】

1、导入Spring坐标

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>

2、定义Spring管理的类(接口&实现类)

2.1、Dao

public interface BookDao {
    void save();
}
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save...");
    }
}

2.2、Service

public interface BookService {
    void save();
}
public class BookServiceImpl implements BookService {
    private BookDao bookDao = new BookDaoImpl();

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

3、配置Spring配置文件(applicationContext.xml),配置对应类作为Spring管理的bean

<?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-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"/>
</beans>

【注意】

bean定义是id属性在同一上下文中不能重复

4、初始化IoC容器(Spring容器),通过容器获取bean

    public static void main(String[] args) {
        //获取IoC容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取bean
        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();
    }

【DI使用】

1、删除使用new的形式创建对象的代码

public class BookServiceImpl implements BookService {
    private BookDao bookDao;

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

2、提供依赖对象对应的setter方法

public class BookServiceImpl implements BookService {
    private BookDao bookDao;

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

    //提供对应的set方法
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
}

3、配置service与dao之间的关系

    <!--配置bean-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <!--配置service与dao之间的关系-->
        <!--property标签表示配置当前bean的属性-->
        <property name="bookDao" ref="bookDao"/>
    </bean>

【bean】

【基础配置】

【别名配置】

【注意】  

获取bean无论是通过id还是name获取,如果无法获取到,将抛出异常

NoSuchBeanDefinitionException: No bean named 'bookServiceImpl' available

【作用范围配置】

【注意】

1、适合交给容器进行管理的bean

  • 表现层对象
  • 业务层对象
  • 数据层对象
  • 工具对象

2、不适合交给容器进行管理的bean

  • 封装实体的域对象

【bean的三种实例化方式】

【第一种】—— 构造方法

1、提供可访问的构造对象

public class BookDaoImpl implements BookDao {
    public BookDaoImpl() {
       
    }

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

2、配置

    <!--方式一:构造方法实例化bean-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>

【注意】

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

【第二种】—— 静态工厂

1、提供静态工厂

public class OrderDaoFactory {
    public static OrderDao getOrderDao(){
        return new OrderDaoImpl();
    }
}

2、配置

    <!--方式二:使用静态工厂实例化bean-->
    <bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>

【第三种】—— 实例工厂

1、提供实例工厂

public class UserDaoFactory {
    public UserDao getUserDao() {
        return new UserDaoImpl();
    }
}

2、配置

    <!--方式三:使用实例化工厂示例bean-->
    <bean id="userDaoFactory" class="com.itheima.factory.UserDaoFactory"/>
    <bean id="userDao" factory-method="getUserDao" factory-bean="userDaoFactory"/>

【优化】

1、提供FactoryBean

public class UserDaoFactoryBean implements FactoryBean<UserDao> {
    //代替原始实例工厂中创建对象的方法
    //得到bean实例
    @Override
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }
    //得到bean类型
    @Override
    public Class<?> getObjectType() {
        return UserDao.class;
    }
    //设置是否单例,true:单例,false:非单例,默认单例
    @Override
    public boolean isSingleton() {
        return true;
    }
}

2、配置

    <!--优化方式三-->
    <bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>

【bean生命周期】

【概述】

  • 生命周期:从创建到消亡的完整过程
  • bean生命周期:bean从创建到销毁的整体过程
  • bean生命周期控制:在bean创建后到销毁前做一些事情

【流程】

  • 初始化容器
  1. 创建对象(内存分配)
  2. 执行构造方法
  3. 执行属性注入(set操作)
  4. 执行bean初始化方法
  • 使用bean
  1. 执行业务操作
  • 关闭/销毁容器
  1. 执行bean销毁方法

【bean生命周期控制】

【配置生命周期控制方法】

1、提供生命周期控制方法

public class BookDaoImpl implements BookDao {

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

    //表示bean初始化时对应的操作
    public void init() {
        System.out.println("init...");
    }

    //表示bean销毁前时对应的操作
    public void destroy() {
        System.out.println("destroy...");
    }
}

2、配置

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"/>

3、主程序调用

public class AppForLiftCycle {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContextLift.xml");
        //注册关闭容器钩子,可放在任意位置
        ctx.registerShutdownHook();
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
        //暴力关闭容器,只能放在最后
        //ctx.close();
    }
}

【接口控制生命周期控制方法】

1、实现InitializingBean, DisposableBean接口

public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {

    private BookDaoImpl bookDao;

    @Override
    public void save() {
        System.out.println("book service save...");
    }

    public void setBookDao(BookDaoImpl bookDao) {
        this.bookDao = bookDao;
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("service destroy");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("service init");
    }
}

2、配置

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"/>
    </bean>

 3、主程序调用

public class AppForLiftCycle {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContextLift.xml");
        //注册关闭容器钩子,可放在任意位置
        ctx.registerShutdownHook();
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
        //暴力关闭容器,只能放在最后
        //ctx.close();
    }
}

【bean销毁时机】

容器关闭前触发bean的销毁

  • 关闭方式:(两种)
  1. 手工关闭容器:ConfigurableApplicationContext接口close()操作
  2. 注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机:ConfigurableApplicationContext接口registerShutdownHook()操作

【依赖注入方式(两种)】

【setter注入】

  • 引用类型

【使用】

1、在bean中定义引用类型属性并提供可访问的set方法

public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
    private BookDaoImpl bookDao;

    public void setBookDao(BookDaoImpl bookDao) {
        this.bookDao = bookDao;
    }
}

2、配置中使用property标签ref属性注入引用类型对象

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"/>
    </bean>
  • 简单类型

【使用】

1、在bean中定义引用类型属性并提供可访问的set方法

public class BookDaoImpl implements BookDao {
    private int connectionNum;
    private String databaseNum;

    public void setConnectionNum(int connectionNum) {
        this.connectionNum = connectionNum;
    }

    public void setDatabaseNum(String databaseNum) {
        this.databaseNum = databaseNum;
    }

    public void save() {
        System.out.println("book service save..." + databaseNum + "," + connectionNum);
    }
}

2、配置中使用property标签value属性注入简单类型数据

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <property name="databaseNum" value="mysql"/>
        <property name="connectionNum" value="10"/>
    </bean>

【构造器注入】

  • 引用类型

【使用】

1、在bean中定义引用类型属性并提供可访问的构造方法

public class BookServiceImpl implements BookService {
    private BookDao bookDao;
    private UserDao userDao;

    public BookServiceImpl(BookDaoImpl bookDao, UserDaoImpl userDao) {
        this.bookDao = bookDao;
        this.userDao = userDao;
    }

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

2、配置中使用constructor-arg标签ref属性注入引用类型对象

    <!--配置bean-->
    <bean id="bookDao" class="com.itheima2.dao.impl.BookDaoImpl"/>
    <bean id="userDao" class="com.itheima2.dao.impl.UserDaoImpl"/>
    <bean id="bookService" class="com.itheima2.service.impl.BookServiceImpl">
        <constructor-arg name="bookDao" ref="bookDao"/>
        <constructor-arg name="userDao" ref="userDao"/>
    </bean>
  • 简单类型

【使用】

1、在bean中定义引用类型属性并提供可访问的set方法

public class BookDaoImpl implements BookDao {
    private int connectionNum;
    private String databaseNum;

    public BookDaoImpl(int connectionNum, String databaseNum) {
        this.connectionNum = connectionNum;
        this.databaseNum = databaseNum;
    }

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

2、配置中使用constructor-arg标签value属性注入简单类型数据

    <!--配置bean-->
    <bean id="bookDao" class="com.itheima2.dao.impl.BookDaoImpl">
        <constructor-arg name="databaseNum" value="mysql"/>
        <constructor-arg name="connectionNum" value="10"/>
    </bean>

【注意】

name与形参名称一致 

【可优化构造器注入】—— 参数配置(依然有弊端)

1、配置中使用constructor-arg标签type属性设置按形参类型注入

    <!--配置中使用constructor-arg标签type属性设置按形参类型注入-->
    <bean id="bookDao" class="com.itheima2.dao.impl.BookDaoImpl">
        <constructor-arg type="int" value="10"/>
        <constructor-arg type="java.lang.String" value="mysql"/>
    </bean>

2、配置中使用constructor-arg标签index属性设置按形参位置注入

    <!--配置中使用constructor-arg标签index属性设置按形参位置注入-->
    <bean id="bookDao" class="com.itheima2.dao.impl.BookDaoImpl">
        <constructor-arg index="1" value="mysql"/>
        <constructor-arg index="0" value="10"/>
    </bean>

【依赖注入方式选择】

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

【依赖自动装配】

【概述】

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

【自动装配方式】

  • 按类型(byType)
  • 按名称(byName)

【使用】

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

    <!--配置bean-->
    <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注入与构造器注入,同时出现时自动装配配置失效

【集合注入】

【种类】

  • 注入数组
  • 注入List
  • 注入Set
  • 注入Map
  • 注入Properties

例:

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <property name="array">
            <array>
                <value>100</value>
                <value>200</value>
                <value>300</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>abc</value>
                <value>def</value>
                <value>ghi</value>
                <value>ghi</value>
            </list>
        </property>
        <property name="set">
            <set>
                <value>abc</value>
                <value>def</value>
                <value>ghi</value>
                <value>ghi</value>
            </set>
        </property>
        <property name="map">
            <map>
                <entry key="country" value="china"/>
                <entry key="province" value="shanxi"/>
                <entry key="city" value="xian"/>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="country">china</prop>
                <prop key="province">shanxi</prop>
                <prop key="city">xian</prop>
            </props>
        </property>
    </bean>

【案例】—— 数据源对象管理

【实现】

1、导入druid坐标

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.16</version>
</dependency>

2、配置数据源对象作为spring管理的bean

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://127.0.0.1:3306/spring_db"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</bean>

【加载properties文件】

【使用】

1、开启命名空间

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

2、使用context命名空间,加载指定properties文件

<context:property-placeholder location="jdbc.properties"/>

3、使用${ }占位符读取加载的属性值

例:

<property name="driverClassName" value="${jdbc.diver}"/>
<property name="username" value="${jdbc.username}"/>

4、在properties文件中写出属性值的内容

例:

jdbc.diver = com.mysql.jdbc.Driver
jdbc.username = root

【其他功能使用】

  • 不加载系统属性
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
  • 加载多个properties
<context:property-placeholder location="jdbc.properties,msg.properties"/>
  • 加载所有properties
<context:property-placeholder location="*.properties"/>
  • 加载properties文件标准格式(重点)
<context:property-placeholder location="classpath:*.properties"/>
  • 从类路径或jar包中搜索并加载properties文件
<context:property-placeholder location="classpath*:*.properties"/>

【容器】

【创建容器】

【两种方式】

第一种:类路径加载配置文件

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

第二种:文件路径加载配置文件(绝对路径)

ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\applicationContext.xml");

加载多个配置文件

ApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml", "bean2.xml");

【获取bean】

【三种方式】

方式一:使用bean名称获取

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

方式二:使用bean名称获取并指定类型

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

方式三:使用bean类型获取

BookDao bookDao = ctx.getBean(BookDao.class);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Lx_Hy_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值