JavaWeb开发(三)3.3——Spring Bean详解

news2024/11/18 21:24:49

一、Bean的概念

由 Spring IoC 容器负责创建、管理所有的Java对象,这些管理的对象称为 Bean,Bean 根据 Spring 配置文件中的信息创建。

二、基于XML方式管理bean对象

eg:

<?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-3.0.xsd">
    
    <bean id="userEntity" class="com.qizekj.entity.UserEntity"></bean>

</beans>

XML 配置的 元素中可以包含多个属性或子元素,常用的属性或子元素如下表所示:

  • id:Bean 的唯一标识符,Spring IoC 容器对 Bean 的配置和管理都通过该属性完成。id 的值必须以字母开始,可以使用字母、数字、下划线等符号,不允许重复的。一般命名格式为类名称首字母小写。
  • name:该属性表示 Bean 的名称,我们可以通过 name 属性为同一个 Bean 同时指定多个名称,每个名称之间用逗号或分号隔开。Spring 容器可以通过 name 属性配置和管理容器中的 Bean。
  • class:该属性指定了 Bean 的具体实现类,它必须是一个完整的类名,即类的全限定名。
  • scope:表示 Bean 的作用域,属性值可以为 singleton(单例)、prototype(原型)、request、session 和 global Session。默认值是 singleton。
  • constructor-arg: 元素的子元素,我们可以通过该元素,将构造参数传入,以实现 Bean 的实例化。该元素的 index 属性指定构造参数的序号(从 0 开始),type 属性指定构造参数的类型。
  • property:元素的子元素,用于调用 Bean 实例中的 setter 方法对属性进行赋值,从而完成属性的注入。该元素的 name 属性用于指定 Bean 实例中相应的属性名。
  • ref: 和 等元素的子元索,用于指定对某个 Bean 实例的引用,即 元素中的 id 或 name 属性。
  • value: 和 等元素的子元素,用于直接指定一个常量值。
  • list:用于封装 List 或数组类型的属性注入。
  • set:用于封装 Set 类型的属性注入。
  • map:用于封装 Map 类型的属性注入。
  • entry: 元素的子元素,用于设置一个键值对。其 key 属性指定字符串类型的键值,ref 或 value 子元素指定其值。
  • init-method:容器加载 Bean 时调用该方法,类似于 Servlet 中的 init() 方法。
  • destroy-method:容器删除 Bean 时调用该方法,类似于 Servlet 中的 destroy() 方法。该方法只在 scope=singleton 时有效。
  • lazy-init 懒加载,值为 true,容器在首次请求时才会创建 Bean 实例;值为 false,容器在启动时创建 Bean 实例。该方法只在 scope=singleton 时有效。

三、Bean属性注入

Bean 属性注入,就是将属性注入到 Bean 中的过程,而这属性既可以普通属性,也可以是一个对象(Bean)。
DI 依赖注入:对象的属性注入值;(spring实现)。

3.1、有参构造函数注入属性值

使用构造函数实现属性注入大致步骤如下:
(1)在 Bean 中添加一个有参构造函数,构造函数内的每一个参数代表一个需要注入的属性;
eg:

public class OrderEntity {
    private String orderId;
    private String orderName;

    public OrderEntity(String orderId, String orderName) {
        this.orderId = orderId;
        this.orderName = orderName;
    }

    @Override
    public String toString() {
        return "OrderEntity{" +
                "orderId='" + orderId + '\'' +
                ", orderName='" + orderName + '\'' +
                '}';
    }
}

(2)在 Spring 的 XML 配置文件中,通过 及其子元素 对 Bean 进行定义;
(3)在 元素内使用 元素,对构造函数内的属性进行赋值,Bean 的构造函数内有多少参数,就需要使用多少个 元素。
eg:

<!-- 第一种方式:使用name,指定参数列表名称: -->
<bean id="orderEntity" class="com.qizekJ.entity.OrderEntity">
	<constructor-arg name="orderId" value="1"></constructor-arg>
    <constructor-arg name="orderName" value="订单1"></constructor-arg>
</bean>
<!-- 第二种方式:使用index,指定参数列表索引: -->
<bean id="orderEntity" class="com.qizekJ.entity.OrderEntity">
    <constructor-arg index="0" value="2"></constructor-arg>
    <constructor-arg index="1" value="订单2"></constructor-arg>
</bean>

3.2、setter 注入属性值

在 Spring 实例化 Bean 的过程中,IoC 容器首先会调用默认的构造方法(无参构造方法)实例化 Bean(Java 对象),然后通过 Java 的反射机制调用这个 Bean 的 setXxx() 方法,将属性值注入到 Bean 中。

使用 setter 注入的方式进行属性注入,大致步骤如下:
(1)在 Bean 中提供一个默认的无参构造函数(在没有其他带参构造函数的情况下,可省略),并为所有需要注入的属性提供一个 setXxx() 方法;
eg:

public class OrderEntity {
    private String orderId;
    private String orderName;

    public OrderEntity() {
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }

    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }

    @Override
    public String toString() {
        return "OrderEntity{" +
                "orderId='" + orderId + '\'' +
                ", orderName='" + orderName + '\'' +
                '}';
    }
}

(2)在 Spring 的 XML 配置文件中,使用 及其子元素 对 Bean 进行定义;
(3)在 元素内使用 元素对各个属性进行赋值。
eg:

<bean id="bookEntity" class="com.qizekj.entity.OrderEntity">
    <property name="orderId" value="3"></property>
    <property name="orderName" value="订单3"></property>
</bean>

3.3、p 命名空间注入属性值

p 命名空间是 setter 方式属性注入的一种快捷实现方式。通过它,我们能够以 bean 属性的形式实现 setter 方式的属性注入,而不再使用嵌套的 元素,以实现简化 Spring 的 XML 配置的目的。

使用p 命名空间实现属性注入大致步骤如下:
(1)在配置文件的 元素中导入以下 XML 约束:

xmlns:p="http://www.springframework.org/schema/p"

(2)在导入 XML 约束后,我们就能通过以下形式实现属性注入:

 <bean id="Bean 唯一标志符" class="包名+类名" p:普通属性="普通属性值" p:对象属性-ref="对象的引用">

eg:

<bean id="orderEntity" class="com.qizekj.entity.OrderEntity" p:orderId="4" p:orderName="订单4">
</bean>

使用 p 命名空间注入依赖时,须注意以下 3 点:

  • Java 类中必须有 setter 方法;
  • Java 类中必须有无参构造器(类中不包含任何带参构造函数的情况,无参构造函数默认存在);
  • 在使用 p 命名空间实现属性注入前,XML 配置的 元素内必须先导入 p 命名空间的 XML 约束。

注入空值属性:

<bean id="OrderEntity" class="com.qizekj.entity.OrderEntity">
    <property name="orderId" value="5">
    </property>
    <property name="orderName" >
        <null></null>
    </property>
</bean>

注入特殊符号:
eg:
(1)转移注入方式:

<!--  转移注入方式 -->
<bean id="OrderEntity" class="com.qizekj.entity.OrderEntity">
    <property name="orderId" value="&lt;&lt;6&gt;&gt;"></property>
    <property name="orderName">
        <null></null>
    </property>
</bean>

(2)Cdata注入方式:

<!--  Cdata注入方式 -->
<bean id="OrderEntity" class="com.qizekj.entity.OrderEntity">
    <property name="orderId">
        <value><![CDATA[<<7>>]]></value>
    </property>
    <property name="orderName">
        <null></null>
    </property>
</bean>

3.4、c 命名空间注入

c 命名空间是构造函数注入的一种快捷实现方式。通过它,我们能够以 属性的形式实现构造函数方式的属性注入,而不再使用嵌套的 元素,以实现简化 Spring 的 XML 配置的目的。

使用c 命名空间实现属性注入大致步骤如下:
(1)在配置文件的 元素中导入以下 XML 约束:

xmlns:c="http://www.springframework.org/schema/c"

(2)在导入 XML 约束后,我们就能通过以下形式实现属性注入:

<bean id="Bean 唯一标志符" class="包名+类名" c:普通属性="普通属性值" c:对象属性-ref="对象的引用">

使用 c 命名空间注入依赖时,必须注意以下 2 点:

  • Java 类中必须包含对应的带参构造器;
  • 在使用 c 命名空间实现属性注入前,XML 配置的 元素内必须先导入 c 命名空间的 XML 约束。

3.5、注入外部bean

接口UserDao:

public interface UserDao {
    void addUser();
}

实现UserDao接口:

public class UserDaoImpl implements  UserDao {
   public void addUser() {
       System.out.println("执行addUser");
    }
}

UserService业务类:

import com.qizekj.dao.UserDao;
import com.qizekj.dao.UserDaoImpl;

public class UserService {
    private UserDao userDao;

    public UserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void addUser() {
        userDao.addUser();
    }
}

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">
    
    <!-- 注入useService  -->
    <bean id="userService" class="com.qizekj.service.UserService">
        <!--  注入userDao,name 属性值: 类中属性的名称;ref:创建UserDaoImpl类的 bean的id -->
        <property name="userDao" ref="userDao"></property>
    </bean>
    <bean id="userDao" class="com.qizekj.dao.UserDaoImpl"></bean>
</beans>

3.5、注入内部bean

员工对象:

public class EmpEntity {

    private String name;
    private Integer age;
    /**
     * 员工属于那个部门
     */
    private  DeptEntity deptEntity;
    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setDeptEntity(DeptEntity deptEntity) {
        this.deptEntity = deptEntity;
    }

    @Override
    public String toString() {
        return "EmpEntity{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", deptEntity=" + deptEntity +
                '}';
    }
}

部门对象:

public class DeptEntity {
    private String name;
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "DeptEntity{" +
                "name='" + name + '\'' +
                '}';
    }
}

Xml相关配置:

<!--内部bean -->
<bean id="empEntity" class="com.qizekj.entity.EmpEntity">
    <!--设置属性name/age -->
    <property name="name" value="qizekj"></property>
    <property name="age" value="32"></property>
    <!-- 嵌入部门bean-->
    <property name="deptEntity">
        <bean id="deptEntity" class="com.qizekj.entity.DeptEntity">
            <property name="name" value="技术部"></property>
        </bean>
    </property>
</bean>

3.6、注入级联赋值

方式一:

<bean id="empEntity" class="com.qizekj.entity.EmpEntity">
    <!--两个属性-->
    <property name="name" value="qizekj"></property>
    <property name="addres" value="安徽省合肥市"></property>
    <!--级联赋值-->
    <property name="deptEntity" ref="deptEntity"></property>
</bean>
<bean id="deptEntity" class="com.qizekj.entity.DeptEntity">
    <property name="name" value="技术部"></property>
</bean>

方式二:
方式二注意:需要在员工类增加deptEntity的get方法。

<bean id="empEntity" class="com.qizekj.entity.EmpEntity">
    <!--两个属性-->
    <property name="name" value="qizekj"></property>
    <property name="addres" value="安徽省合肥市"></property>
    <!--级联赋值-->
    <property name="deptEntity" ref="deptEntity"></property>
    <property name="deptEntity.name" value="技术部"></property>
</bean>
<bean id="deptEntity" class="com.qizekj.entity.DeptEntity">
</bean>

3.7、注入数组、集合类型属性

学生类:

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class StuEntity {
    //1.数组属性
    private String[] arrays;
    //2.list集合属性
   private List<String> list;
    //3.Map
    private Map<String,String> map;
    //4.Set
    private Set<String> set;

    public void setArrays(String[] arrays) {
        this.arrays = arrays;
    }

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

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

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

    @Override
    public String toString() {
        return "StuEntity{" +
                "arrays=" + Arrays.toString(arrays) +
                ", list=" + list +
                ", map=" + map +
                ", set=" + set +
                '}';
    }
}

xml配置文件:

<bean id="stuEntity" class="com.mayikt.entity.StuEntity">
    <!--数组类型注入-->
    <property name="arrays">
        <array>
            <value>mayikt01</value>
            <value>mayikt02</value>
        </array>
    </property>
    <!--list-->
    <property name="list">
        <list>
            <value>语文</value>
            <value>数学</value>
        </list>
    </property>
    <!--Map-->
    <property name="map">
       <map>
           <entry key="余胜军" value="23"></entry>
           <entry key="小薇" value="25"></entry>
       </map>
    </property>
    <!--Set-->
    <property name="Set">
       <set>
           <value>01</value>
           <value>02</value>
       </set>
    </property>
</bean>

四、IOC操作Bean的管理

Spring中两种类型bean,一种是为普通bean,另外一种是工厂bean:
普通Bean:在配置文件中定义什么类型与返回的类型需一致;
工厂Bean:在配置文件中定义Bean类型与返回类型可以不一致。

eg:
创建一个工厂Bean类,实现FactoryBean接口

public class QizekjBean implements FactoryBean {

    public UserEntity getObject() throws Exception {
        return new UserEntity();
    }

    public Class<?> getObjectType() {
        return null;
    }
}

配置文件spring_factory.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">

    <!--spring ioc管理-->
    <bean id="qizekjBean" class="com.qizekj.factorybean.QizekjBean"> </bean>
</beans>

测试类:

public class factoryTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext classPathXmlApplicationContext =
                new ClassPathXmlApplicationContext("spring_factory.xml");
        //QizekjBean qizekjBean = (QizekjBean) classPathXmlApplicationContext.getBean("qizekjBean");
        UserEntity qizekjBean = (UserEntity) classPathXmlApplicationContext.getBean("qizekjBean");
        System.out.println(qizekjBean);
    }
}

当工厂Bean类实现FactoryBean接口,重写了getObject()方法,返回类型为UserEntity时,测试类中再用xml配置的QizekjBean就会报错了。

五、Bean作用域

单例的作用域:每次在调用getbean方法获取对象都是同一个对象;
多例的作用域:每次在调用getbean方法获取对象都是一个新的对象。

默认情况下,所有的 Spring Bean 都是单例的,也就是说在整个 Spring 应用中, Bean 的实例只有一个。
在 元素中添加 scope 属性来配置 Spring Bean 的作用范围。

单例:在同一个jvm中,该bean对象只会创建一次;
多例:在同一个jvm中,该bean对象可以被创建多次。

Spring 5 共提供了 6 种 scope 作用域:

  • singleton:默认值,单例模式,表示在 Spring 容器中只有一个 Bean 实例。
  • prototype:原型模式,表示每次通过 Spring 容器获取 Bean 时,容器都会创建一个新的 Bean 实例。
  • request:每次 HTTP 请求,容器都会创建一个 Bean 实例。该作用域只在当前 HTTP Request 内有效。
  • session:同一个 HTTP Session 共享一个 Bean 实例,不同的 Session 使用不同的 Bean 实例。该作用域仅在当前 HTTP Session 内有效。
  • application:同一个 Web 应用共享一个 Bean 实例,该作用域在当前 ServletContext 内有效。 与 singleton 类似,但 singleton 表示每个 IoC 容器中仅有一个 Bean 实例,而一个 Web 应用中可能会存在多个 IoC 容器,但一个 Web 应用只会有一个 ServletContext,也可以说 application 才是 Web 应用中货真价实的单例模式。
  • websocket:websocket 的作用域是 WebSocket ,即在整个 WebSocket 中有效。

注意:在以上 6 种 Bean 作用域中,除了 singleton 和 prototype 可以直接在常规的 Spring IoC 容器(例如 ClassPathXmlApplicationContext)中使用外,剩下的都只能在基于 Web 的 ApplicationContext 实现(例如 XmlWebApplicationContext)中才能使用,否则就会抛出一个 IllegalStateException 的异常。

(1)singleton

singleton 是 Spring 容器默认的作用域。当 Bean 的作用域为 singleton 时,Spring IoC 容器中只会存在一个共享的 Bean 实例。这个 Bean 实例将存储在高速缓存中,所有对于这个 Bean 的请求和引用,只要 id 与这个 Bean 定义相匹配,都会返回这个缓存中的对象实例。
如果一个 Bean 定义的作用域为 singleton ,那么这个 Bean 就被称为 singleton bean。在 Spring IoC 容器中,singleton bean 是 Bean 的默认创建方式,可以更好地重用对象,节省重复创建对象的开销。

在 Spring 配置文件中,可以使用 元素的 scope 属性,将 Bean 的作用域定义成 singleton,其配置方式如下所示:

<bean id="..." class="..." scope="singleton"/>

(2)prototype

如果一个 Bean 定义的作用域为 prototype,那么这个 Bean 就被称为 prototype bean。对于 prototype bean 来说,Spring 容器会在每次请求该 Bean 时,都创建一个新的 Bean 实例。

在 Spring 配置文件中,可以使用 元素的 scope 属性将 Bean 的作用域定义成 prototype,其配置方式如下所示:

<bean id="..." class="..." scope="prototype"/>

eg:
配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<?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">

    <!--spring ioc管理-->
    <bean id="qizekjBean" class="com.qizekj.factorybean.QizekjBean"> </bean>
</beans>

测试类:

public class factoryTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext classPathXmlApplicationContext =
                new ClassPathXmlApplicationContext("spring_factory.xml");
        QizekjBean qizekjBean1 = (QizekjBean) classPathXmlApplicationContext.getBean("qizekjBean");
        QizekjBean qizekjBean2 = (QizekjBean) classPathXmlApplicationContext.getBean("qizekjBean");
        System.out.println(qizekjBean1);
        System.out.println(qizekjBean2);
        System.out.println(qizekjBean1 == qizekjBean2);
    }
}

结果:
userEntity1与userEntity2完全相等
在这里插入图片描述

将配置文件中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">

    <!--spring ioc管理-->
    <bean id="qizekjBean" class="com.qizekj.factorybean.QizekjBean" scope="prototype"> </bean>
</beans>

运行测试类,得到结果为:
userEntity1与userEntity2不相等,不是同一个bean
在这里插入图片描述

六、Bean继承

在 Spring 中,Bean 和 Bean 之间也存在继承关系。我们将被继承的 Bean 称为父 Bean,将继承父 Bean 配置信息的 Bean 称为子 Bean。
Spring Bean 的定义中可以包含很多配置信息,例如构造方法参数、属性值。子 Bean 既可以继承父 Bean 的配置数据,也可以根据需要重写或添加属于自己的配置信息。

在 Spring XML 配置中,我们通过子 Bean 的 parent 属性来指定需要继承的父 Bean,配置格式如下:

<!--父Bean-->
<bean id="parentBean" class="xxx.xxxx.xxx.ParentBean" >
    <property name="xxx" value="xxx"></property>
    <property name="xxx" value="xxx"></property>
</bean> 
<!--子Bean--> 
<bean id="childBean" class="xxx.xxx.xxx.ChildBean" parent="parentBean"></bean>

在父 Bean 的定义中,有一个十分重要的属性,那就是 abstract 属性。如果一个父 Bean 的 abstract 属性值为 true,则表明这个 Bean 是抽象的。
抽象的父 Bean 只能作为模板被子 Bean 继承,它不能实例化,也不能被其他 Bean 引用,更不能在代码中根据 id 调用 getBean() 方法获取,否则就会返回错误。
在父 Bean 的定义中,既可以指定 class 属性,也可以不指定 class 属性。如果父 Bean 定义没有明确地指定 class 属性,那么这个父 Bean 的 abstract 属性就必须为 true。

七、Spring Bean的生命周期

7.1 Bean的生命周期

周期简单分为:实例化→属性赋值→初始化→销毁
生命周期的原理:
(1)通过构造函数创建bean对象(默认执行无参构造函数,底层基于反射实现)
(2)为bean的属性赋值 (使用反射调用set方法)
(3)调用bean的初始化的方法(需要单独在类中配置初始化的方法)
(4)正常使用bean对象
(5)Spring容器关闭,调用该类的销毁回调的方法(需要单独在类中配置销毁的方法)

eg:

public class MemberEntity {
    private String name;
    public MemberEntity(){
        System.out.println("第一步:————通过构造函数创建bean对象,无参构造函数被执行");
    }

    public void setName(String name) {
        System.out.println("第二步:为bean的属性赋值,set方法初始化属性");
        this.name = name;
    }

    public void initMethod(){
        System.out.println("第三步:调用bean的初始化的方法,回调调用init初始化方法");
    }

    public void destroyMethod(){
        System.out.println("第五步:Spring容器关闭,调用该类的销毁回调的方法,回调调用destroyMethod方法");
    }
}

配置文件,配置bean并赋值,设置initMethod、destroyMethod方法:

<?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="memberEntity" class="com.qizekj.entity.MemberEntity" init-method="initMethod" destroy-method="destroyMethod">
        <property name="name" value="qizekj"></property>
    </bean>
</beans>

测试类:

public static void main(String[] args) {
    ClassPathXmlApplicationContext classPathXmlApplicationContext =
            new ClassPathXmlApplicationContext("spring_02.xml");
    MemberEntity memberEntity = (MemberEntity) classPathXmlApplicationContext.getBean("memberEntity");
    System.out.println("第四步:获取使用到的memberEntity,正常使用bean对象");
    System.out.println(memberEntity);
    // 手动让bean容器销毁
    classPathXmlApplicationContext.close();
}

运行结果:
在这里插入图片描述

7.2 Bean的后置处理器

Bean的后置处理器: 作用提供更多的扩展功能。

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * @author chenqun
 * @date 2023/1/14 17:11
 */
public class QizekjBeanPost implements BeanPostProcessor {
    /**
     * 调用初始化方法之前执行
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在bean 初始化方法之前执行");
        return bean;
    }

    /**
     * 调用初始化方法之后执行
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在bean 初始化方法之后执行");
        return 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 id="memberEntity" class="com.qizekj.entity.MemberEntity" init-method="initMethod" destroy-method="destroyMethod">
        <property name="name" value="qizekj"></property>
    </bean>

    <bean id="mayiktBeanPost" class="com.qizekj.entity.QizekjBeanPost"></bean>
</beans>

测试方法:

public class Test04 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext classPathXmlApplicationContext =
                new ClassPathXmlApplicationContext("spring_02.xml");
        MemberEntity memberEntity = (MemberEntity) classPathXmlApplicationContext.getBean("memberEntity");
        System.out.println("第四步:获取使用到的memberEntity,正常使用bean对象");
        System.out.println(memberEntity);
        // 手动让bean容器销毁
        classPathXmlApplicationContext.close();
    }
}

运行结果:
在这里插入图片描述

7.3 Bean的后置处理器底层原理

配置多个BeanPostProcessor:

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;

/**
 * @author chenqun
 * @date 2023/1/14 17:11
 */
public class QizekjBeanPost implements BeanPostProcessor, Ordered {
    /**
     * 调用初始化方法之前执行
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在bean 初始化方法之前执行");
        return bean;
    }

    /**
     * 调用初始化方法之后执行
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在bean 初始化方法之后执行");
        return bean;
    }

    public int getOrder() {
        return 1;
    }
}
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;

/**
 * @author chenqun
 * @date 2023/1/14 17:18
 */
public class QizekjBeanPost2 implements BeanPostProcessor, Ordered {
    /**
     * 调用初始化方法之前执行
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("QizekjBeanPost2:在bean 初始化方法之前执行");
        return bean;
    }

    /**
     * 调用初始化方法之后执行
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("QizekjBeanPost2:在bean 初始化方法之后执行");
        return bean;
    }

    public int getOrder() {
        return 0;
    }
}

配置文件:

<?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="memberEntity" class="com.qizekj.entity.MemberEntity" init-method="initMethod" destroy-method="destroyMethod">
        <property name="name" value="qizekj"></property>
    </bean>

    <!-- 后置处理器-->
    <bean id="mayiktBeanPost" class="com.qizekj.entity.QizekjBeanPost"></bean>
    <bean id="mayiktBeanPost2" class="com.qizekj.entity.QizekjBeanPost2"></bean>
</beans>

测试类:

public class Test04 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext classPathXmlApplicationContext =
                new ClassPathXmlApplicationContext("spring_02.xml");
        MemberEntity memberEntity = (MemberEntity) classPathXmlApplicationContext.getBean("memberEntity");
        System.out.println("第四步:获取使用到的memberEntity,正常使用bean对象");
        System.out.println(memberEntity);
        // 手动让bean容器销毁
        classPathXmlApplicationContext.close();
    }
}

运行结果:
实现Ordered接口的getOrder方法,值越小越优先加载。
在这里插入图片描述

八、SpringBean的自动装配

根据指定装配规则(属性名称或者属性的类型),spring自动将匹配属性的值注入。

(1)根据属性的名称注入(autowire=“byName”),bean的id名称与属性的名称一致:
eg:

<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util.xsd">

    <!-- 根据属性的名称注入,bean的id名称与属性的名称一致 -->
    <bean id="empEntity" class="com.qizekj.entity.EmpEntity" autowire="byName">
    </bean>
    
    <bean id="deptEntity" class="com.qizekj.entity.DeptEntity">
        <property name="name" value="技术部"></property>
    </bean>
</beans>

根据属性的类型注入(autowire=“byType”),bean的类型与属性类型一致:
eg:

<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util.xsd">

    <!-- 根据属性的类型注入,bean的类型与属性类型一致 -->
    <bean id="empEntity" class="com.mayikt.entity.EmpEntity" autowire="byType">
    </bean>
    
    <bean id="deptEntity" class="com.mayikt.entity.DeptEntity">
        <property name="name" value="教育部门"></property>
    </bean>
</beans>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/163653.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【B-树、B+树、B* 树】多叉平衡搜索树,解决“IO次数”与“树高”问题~

目录 一、为什么会出现B-树&#xff1f; 面试题&#xff1a; 二、什么是B-树&#xff1f; 2.1、B,B-树,B*树 导航 三、B-树的模拟实现 3.1、插入结点分析 3.1.1、根节点的分裂 3.1.2、继续插入数据&#xff0c;分裂子节点 3.2.3、再次插入数据&#xff0c;导致根节点继…

tomcat和apache有什么区别?如何将内网发布到互联网访问?

tomcat、 apache是比较常用的搭建服务器的中间件&#xff0c;它们之间还是有一些区别差异的&#xff0c;我们通常会根据本地应用场景来选择合适的中间件来搭建服务器。在内网本地部署搭建服务器后&#xff0c;还可以通过快解析端口映射方法&#xff0c;将内网应用地址发布到互联…

Android原生检测Selinux的三种方法

本文介绍 3 种检测 Android 设备 SELinux 状态的方法, Java 层检测Selinux已经没有太多意义,因为不是很靠谱,随便一个hook代码就能绕过,所以我要告诉你如何在 C 层完成检测。这几种方法在效率和抵抗mock SELinux State 的技术方面都不相同,因此在使用之前你需要知道每种方…

Windows server——部署DNS服务

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 本章重点 一.DNS概述 1.DNS的诞生 二.DNS的功能 使用域名访问具有以下优点…

【大厂高频真题100题】《二叉树的序列化与反序列化》 真题练习第23题 持续更新~

二叉树的序列化与反序列化 序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。 请设计一个算法来实现二叉树的序列化与反序列化。这里不限…

c语言 图形化贪吃蛇 多种功能 无需安装第三方库 课设 (附代码)

前言 类贪吃蛇是利用c语言模仿并实现经典游戏贪吃蛇&#xff0c;使其在窗口有贪吃蛇活动的规定范围&#xff0c;并完成一系列包括但不限于模仿蛇的移动&#xff0c;方向控制&#xff0c;吃到食物加分&#xff0c;撞上墙壁及蛇头碰到蛇身死亡等游戏功能。 附加功能&#xff1a…

软件测试复习03:动态测试——白盒测试

作者&#xff1a;非妃是公主 专栏&#xff1a;《软件测试》 个性签&#xff1a;顺境不惰&#xff0c;逆境不馁&#xff0c;以心制境&#xff0c;万事可成。——曾国藩 文章目录逻辑覆盖法&#xff1a;最常用程序插桩技术基本路径法点覆盖边覆盖边对覆盖主路径覆盖符号测试错误…

前端leaflet框选下载bing遥感图

微软必应bing遥感图。bing地图比百度遥感图清晰很多&#xff0c;19级&#xff0c;百度是18级&#xff0c;同样的18级&#xff0c;bing地图比百度也清晰很多。所以没有必要用百度地图了。不过bing地图仅用于学习&#xff0c;商用要付费。参考了https://xiaozhuanlan.com/topic/6…

CV+Deep Learning——网络架构Pytorch复现系列——Detection(二:RtinaNet)更换backbones

上一话 CVDeep Learning——网络架构Pytorch复现系列——Detection(一&#xff1a;SSD:Single Shot MultiBox Detector 4.推理Detect)https://blog.csdn.net/XiaoyYidiaodiao/article/details/128683973?spm1001.2014.3001.5501 复现Object Detection&#xff0c;会复现的网络…

设计模式-门面模式

医院的例子 现代的软件系统都是比较复杂的&#xff0c;设计师处理复杂系统的一个常见方法便是将其"分而治之"&#xff0c;把一个系统划分为几个较小的子系统。如果把医院作为一个子系统&#xff0c;按照部门职能&#xff0c;这个系统可以划分为挂号、门诊、划价、化…

Web--Jedis

# Redis 1. 概念&#xff1a; redis是一款高性能的NOSQL系列的非关系型数据库 1.1.什么是NOSQL NoSQL(NoSQL Not Only SQL)&#xff0c;意即“不仅仅是SQL”&#xff0c;是一项全新的数据库理念&#xff0c;泛指非关系型的数据库。 随着互联网web2.0网…

Arch Linux 来报道!!!

导读Ubuntu 的制造商 Canonical 早已和微软进行合作&#xff0c;让我们体验了极具争议的 Bash on Windows。外界对此也是褒贬不一&#xff0c;许多 Linux 重度用户则是质疑其是否有用&#xff0c;以及更进一步认为 Bash on Windows 是一个安全隐患。 Unix 的 Bash 是通过 WSL (…

LabVIEW使用VI脚本创建和打开VI

LabVIEW使用VI脚本创建和打开VI按照下列步骤&#xff0c;可以创建一个VI&#xff0c;该VI使用VI脚本创建和打开VI。创建VI前&#xff0c;需先了解VI脚本的基本内容。必须启用VI脚本&#xff0c;才能显示VI脚本选板&#xff0c;使用相关属性和方法。1. 选择文件新建VI&#xff0…

第1章 ESP32-VSCODE环境搭建

ESP32-VSCODE环境搭建 环境安装 在Windows中安装ESP-IDF在vscode中安装Espressif IDF插件开始配置Espressif IDF插件 在vscode最上方点击&#xff1a;查看->命令面板&#xff0c;输入esp-idf:config&#xff0c;选择ESP-IDF:Configure ESP-IDF extension 选择EXPRESS Sele…

java07-面向对象2

一&#xff1a;面向对象的第二个特征&#xff1a;继承&#xff0c;关键字extends 1.继承的好处&#xff1a; 1&#xff09;减少代码的冗余&#xff0c;提高代码的复用​​​​​性。 2&#xff09;便于功能的扩展 3&#xff09;为之后多态性的使用&#xff0c;提供了前提 …

【阶段三】Python机器学习27篇:机器学习项目实战:数据降维:主成分分析PCA、基本原理与PCA模型:人脸识别

本篇的思维导图: 数据降维:主成分分析PCA 建立模型分析特征数据时,很可能会面临特征数据维度过大的问题。例如,根据已有的信用卡持有人信息及其违约数据来建立信用卡违约预测模型时,数据可能包含申请人的收入、年龄、性别、婚姻状况、工作单位等数百个维度的特征。…

【图像分类】基于yolov5的钢板表面缺陷分类(附代码和数据集)

写在前面&#xff1a; 首先感谢兄弟们的订阅&#xff0c;让我有创作的动力&#xff0c;在创作过程我会尽最大能力&#xff0c;保证作品的质量&#xff0c;如果有问题&#xff0c;可以私信我&#xff0c;让我们携手共进&#xff0c;共创辉煌。 Hello&#xff0c;大家好&#xf…

ArcGIS基础实验操作100例--实验100三维可视性分析

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 空间分析篇--实验100 三维可视性分析 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;1&a…

JavaScript---DOM---高级事件---1.8

注册事件&#xff08;绑定事件&#xff09; 给元素添加事件称为注册事件或绑定事件。注册事件有两种方式&#xff1a;传统方式、方法监听注册方式。 传统注册方式&#xff1a; 利用on开头的事件onclick&#xff1a; <button onclick"alert(hi~)"></butt…

测试用例具体的设计方法

等价类法由于输入的集合是无穷的&#xff0c;不能全部覆盖到&#xff0c;所以通过划分若干个等价类&#xff0c;选出有代表性的达到尽量多的功能覆盖有效等价类&#xff1a;根据规格说明书是合理的、有意义的输入数据构成的集合无效等价类&#xff1a;根据需求说明书是不合理&a…