JavaWeb开发(三)3.3——Spring Bean详解(基于XML方式)

news2024/11/24 4:57:47

一、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/169746.html

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

相关文章

JupyterLab,极其强大的 10 个秘密技巧

之前一篇文章&#xff1a;整理了上千个 Python 工具库&#xff0c;涵盖24个大方向 没想到火了。喜欢的可以看一下。 今天我给大家分享一下 Jupyter Lab 的一些内容。 JupyterLab 是 Jupyter 主打的最新数据科学生产工具&#xff0c;某种意义上&#xff0c;它的出现是为了取代…

瑞芯微的接口结构学习总结

MPI 接口使用的主要数据结构&#xff1a; 瑞芯微提供的媒体处理软件平台&#xff08;Media Process Platform&#xff0c;简称 MPP&#xff09;是适用于瑞芯微芯片系列的 通用媒体处理软件平台。该平台对应用软件屏蔽了芯片相关的复杂底层处理&#xff0c;其目的是为了屏蔽不 …

2022 全球网络黑产常用攻击方法 Top 10

近几年&#xff0c;借助互联网产业发展的东风&#xff0c;网络黑产也迎来更加巅峰的状态&#xff0c;不论是从攻击效率&#xff0c;组织规模&#xff0c;亦或是收益变现能力&#xff0c;都在一天天变的成熟完善。根据艾瑞咨询 2020 年发布的《现代网络诈骗分析报告》&#xff0…

哪些数据库开了全文索引

大家好&#xff0c;才是真的好。 今天我们讨论Domino运维管理问题&#xff1a;哪些数据库开启了全文索引&#xff1f; 在前面的某些篇章中&#xff0c;我们介绍过什么是Notes应用的全文索引Full Text Index&#xff0c;以下简称FTI。它是Notes库中的单词的文本索引或列表&…

HTML零基础教程,九大知识点带你玩转前端(下)

博主&#xff1a;冰小九&#xff0c;新人博主一只&#xff0c;欢迎大佬前来指导 冰小九的主页喜欢请给个三连加关注呀&#xff0c;谢谢&#x1f337;&#x1f337;&#x1f337;三连加关注&#xff0c;追文不迷路&#xff0c;你们的支持就是我最大的动力&#xff01;&#xff0…

javaAPI操作-Zookeeper

## 4)ZooKeeper JavaAPI 操作 4.1)Curator介绍 •Curator 是 Apache ZooKeeper 的Java客户端库。 •常见的ZooKeeper Java API &#xff1a; •原生Java API •ZkClient •Curator •Curator 项目的目标是简化 ZooKeeper 客户端的使用。 •Curator 最初是 Netfix 研发的…

电影购票系统项目实战

电影购票系统项目实战电影购票系统简介、项目功能演示。日志框架搭建、系统角色分析首页、登录、商家界面、用户界面实现商家功能-展示详情、影片上架、退出商家功能-影片下架、影片修改用户功能-展示全部影片用户功能-购票功能用户功能-评分功能用户功能-根据片名查询全部影片…

绝缘手套穿戴智能识别算法 yolov5

绝缘手套穿戴智能识别算法通过opencvpython深度学习技术&#xff0c;对现场人员是否佩戴绝缘手套进行识别检测&#xff0c;当检测到现场人员违规行为未佩戴绝缘手套时立刻抓拍告警。我们使用YOLO(你只看一次)算法进行对象检测。YOLO是一个聪明的卷积神经网络(CNN)&#xff0c;用…

初学者C语言练习题-入门

一、入门 C语言一经出现就以其功能丰富、表达能力强、灵活方便、应用面广等特点迅速在全世界普及和推广。C语言不但执行效率高而且可移植性好&#xff0c;可以用来开发应用软件、驱动、操作系统等。C语言也是其它众多高级语言的鼻祖语言&#xff0c;所以说学习C语言是进入编程世…

Python SciPy 模块列表

SciPy 模块列表以下列出了 SciPy 常用的一些模块及官网 API 地址&#xff1a;模块名功能参考文档scipy.cluster向量量化cluster APIscipy.constants数学常量constants APIscipy.fft快速傅里叶变换fft APIscipy.integrate积分integrate APIscipy.interpolate插值interpolate API…

Android自定义控件(八) Android仿招商银行APP手势解锁

前言 目前大部分APP的登录方式有多种类型&#xff0c;其中手势解锁就是其中比较常见的一种方式&#xff0c;经常使用的招商银行APP&#xff08;IOS&#xff09;端的手势解锁体验不错的&#xff0c;就仿照它自定义下手势解锁功能。 说明 1、招行APP手势解锁效果 2、绘制分析 …

【技术推荐】前端JS攻防对抗

简介 网络爬虫一直以来是让网站维护人员头痛的事情&#xff0c;即要为搜索引擎开方便之门&#xff0c;提升网站排名、广告引入等&#xff0c;又要面对恶意爬虫做出应对措施&#xff0c;避免数据被非法获取&#xff0c;甚至出售。因此促生出爬虫和反爬虫这场旷日持久的战斗。 爬…

Java中的Arrays类

1、问题Arrays类是什么&#xff0c;Arrays常用方法。2、方法了解Arrays类的概念Arrays 位于java.util包下,Arrays是一个操作数组的工具类。Arrays常用方法Arrays.fill&#xff1a;替换数组原元素&#xff1b;Arrays.sort:对数组进行排序&#xff08;递增&#xff09;&#xff1…

23种设计模式(六)——装饰模式【单一职责】

文章目录意图什么时候使用装饰真实世界类比装饰模式的实现装饰模式的优缺点亦称&#xff1a; 装饰者模式、装饰器模式、Wrapper、Decorator 意图 装饰者模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象扩展新的功能&#xff0c;同时不改变其结构。主要解决…

Allegro如何快速找到差分不耦合处操作指导

Allegro如何快速找到差分不耦合处操作指导 做PCB设计的时候,需要检查差分对不耦合的地方,让差分不耦合的地方高亮出来 具体操作如下 用Allegro172版本打开pcb,选择View选择Vision Manager

抖快社交,变道求生

配图来自Canva可画 抖音、快手再一次杀回了社交市场。 2022年12月底&#xff0c;快手App store版本更新&#xff0c;在原有的快手热榜、朋友动态、快手拍摄的基础上&#xff0c;新增亲密贴贴、快手直播等新锁屏组件&#xff0c;通过强化产品的交互功能&#xff0c;增强用户的…

针对游戏开发CG制作的搬砖人员的资源搜索技巧分享—【持续补充篇】

一.常用搜索技巧分享 1.视频参考类(bilibili,youtube,常用的视频官网,其实可以满足了,再不行就在百度/Google搜一下) 2.教程和代码类 github Bootstrap Well magebox realtimevfx

Python项目(Django框架)天天生鲜在CentOS7.9搭建运行

CentOS安装python3 为方便管理&#xff0c;在CentOS桌面创建一个文件夹&#xff0c;将软件包下载到这里&#xff0c;右键--在终端打开 安装python3.9.7 : wget https://www.python.org/ftp/python/3.9.7/Python-3.9.7.tgz &#xff08;命令前的sudo如果是root用户可以去掉&…

深度学习目标检测基础_sigmoid和softmax函数

文章目录sigmoid和softmaxsigmoid函数softmax函数总结sigmoid和softmax sigmoid和softmax都是分类函数&#xff0c;他们的区别如下 sigmoid函数 Sigmoid 多标签分类问题多个正确答案非独占输出&#xff08;例如胸部X光检查、住院&#xff09;。构建分类器&#xff0c;解决有…

威纶通触摸屏配方功能的使用方法示例

威纶通触摸屏配方功能的使用方法示例 本次和大家分享通过触摸屏内部指针+偏移地址+控制元件实现配方功能的具体方法, 另外以前给大家分享过利用宏指令实现配方功能的方法,具体可参考以下链接中的内容: 威纶通触摸屏的配方功能具体使用方法介绍(宏指令写入PLC) 如下图所示…