Spring Bean管理(XML)

Spring工厂类

在这里插入图片描述
BeanFactory为ApplicationContext的子接口,使用的BeanFactory接口用于工厂类后需要调用getBean()方法才能创建实体类对象,而使用ApplicationContext则会在加载配置文件时,就对配置文件中的类进行实例化。

而创建工厂类也提供了两个实体类,FileSystemXmlApplicationContext可以从本地磁盘中读取配置文件,而ClassPathXmlApplicationContext则会从项目的类路径中读取配置文件。

SpringBean的实例化

使用类构造器实例化对象

在配置文件中直接添加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="employee" class="com.spring.test.service.entity.Employee"/>
</beans>

这种方法也是默认的、最常用的一种方法

使用静态工厂类实例化对象

首先创建静态工厂

package com.spring.test.service.entity;

public class EmployeeFactory {
    public static Employee getEmployee() {
        return new Employee();
    }
}

在配置文件中class属性指向新建的工厂类,再新增一个属性factory-method指向静态工厂用于创建类的方法

<?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="employee" class="com.spring.test.service.entity.EmployeeFactory" factory-method="getEmployee"/>
</beans>

使用实例工厂实例化对象

实例工厂与静态工厂的区别主要在于获取实例的方法是否为静态方法,创建实例工厂:

package com.spring.test.service.entity;

public class EmployeeFactory {
    public Employee getEmployee() {
        return new Employee();
    }
}

<?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="employeeFactory" class="com.spring.test.service.entity.EmployeeFactory"/>
    <bean id="employee" factory-bean="employeeFactory" factory-method="getEmployee"/>
</beans>

首先创建bean标签指向实例工厂,生成一个工厂实例,再创建一个bean标签使用factory-bean属性指向工厂实例的bean标签,再设置factory-method调用该实例的方法获取实例。

Bean的配置

id、name

id、name都是用来标记bean标签的名称,且在IOC中必须是唯一的,两个属性唯一的区别就在于如果名称中包含特殊字符就只能使用name

class

用于设置类的完整路径,主要用于IOC容器生成类的实例

scope(作用域)

类别说明
singleton在SpringIOC容器中仅存在一个Bean实例,即以单例模式的方式存在
prototype每次调用getBean()时都会返回一个新的实例
request在每次HTTP请求时都会创建一个新的Bean
session同一个Session共享一个Bean

SpringIOC默认是使用单例模式创建实例

示例:

<?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="employee" class="com.spring.test.service.entity.Employee" scope="prototype"/>
</beans>
package com.spring.test;

import com.spring.test.service.UserService;
import com.spring.test.service.entity.Employee;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestSpring {
    @Test
    public void test() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        Employee employee = (Employee) applicationContext.getBean("employee");
        Employee employee1 = (Employee) applicationContext.getBean("employee");

        System.out.println(employee);
        System.out.println(employee1);
    }
}

在这里插入图片描述
由此可见使用prototype属性后,每次创建的对象都指向不同的内存地址

生命周期

在初始化或销毁bean时需要做处理工作时,可以使用init-method属性和destory-method属性指定初始化和销毁方法,使得对象在创建或销毁时完成指定业务。

在实现Bean的实例化到销毁过程中,需要执行以下步骤,也就是Bean的完整的生命周期

  1. instantiate bean调用Bean的构造方法实例化对象
  2. populate properties 封装属性
  3. 如果Bean实现BeanNameAware类,执行setBeanName方法将配置文件中的指定的Bean的名称代入方法中
  4. 如果Bean实现BeanNameAwareApplicationContextAware,执行setBeanFactory方法或者上下文对象setApplicationContext方法,使Bean了解工厂信息
  5. 如果存在某一个类实现了BeanPostProcessor(后处理Bean),将会执行postProcessBeforeInitialization方法,在类的实例化前去执行该方法
package com.spring.test.entity;

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

public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        System.out.println("第五步:初始化前执行该方法");
        return o;
    }

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        System.out.println("第八步:初始化后执行该方法");
        return o;
    }
}

MyBeanPostProcessor 类在创建实例时会被Spring自动调用所以在配置时不需要配置再配置bean的id属性

<?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="employee" class="com.spring.test.entity.Employee" init-method="init" destroy-method="customerDestroy">
        <property name="name" value="Mary"/>
    </bean>
	<bean class="com.spring.test.service.entity.MyBeanPostProcessor"/>
</beans>
  1. 如果bean实现了InitializingBean,执行afterPropertiesSet方法,在属性设置后执行该方法
  2. 调用<bean init-method="init"> 指定初始化方法
  3. 如果存在类实现后方法BeanPostProcessor(处理Bean),执行postProcessAfterInitialization
  4. 执行Bean的其他业务方法
  5. 如果Bean实现了DisposableBean执行destroy方法
  6. 调用<bean destory-method="customerDestroy">通过指定的销毁方法销毁实例
package com.spring.test.entity;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class Employee implements BeanNameAware, ApplicationContextAware, InitializingBean, DisposableBean {
    private String name;

    public Employee() {
        System.out.println("第一步:初始化");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("第二步:设置属性");
        this.name = name;
    }

    @Override
    public void setBeanName(String s) {
        System.out.println("第三步:设置Bean名称" + s);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("第四步:了解工厂信息");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("第六步:属性后设置");
    }

    private void init() {
        System.out.println("第七步:执行指定方法初始化实例");
    }

    public void say() {
        System.out.println("第九步:执行其他业务方法");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("第十步:实现DisposableBean的destroy方法");
    }

    private void customerDestroy() {
        System.out.println("第十一步:调用指定方法销毁实例");
    }
}

以上的11个步骤就是Bean实例化话到销毁的整个过程,而利用postProcessAfterInitialization方法可以对业务方法进行增强处理

示例:

创建一个接口UserService和其实现类UserServiceImpl

package com.spring.test.service;

public interface UserService {
    void findAll();

    void save();
}

package com.spring.test.service.impl;

import com.spring.test.service.UserService;

public class UserServiceImpl implements UserService {
    @Override
    public void findAll() {
        System.out.println("查询所有记录...");
    }

    @Override
    public void save() {
        System.out.println("保存记录");
    }
}

当在调用findAll方法时需要对该方法增加权限限制,则可使用postProcessAfterInitialization方法对该方法进行增强

package com.spring.test.service.entity;

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

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        System.out.println("第五步:初始化前执行该方法");
        return o;
    }

    /**
     *
     * @param o Bean类
     * @param s Bean的名称
     * @return Bean类
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        System.out.println("第八步:初始化后执行该方法");

        if ("userService".equals(s)) {
            // 使用对象代理
            Object proxy = Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    if ("findAll".equals(method.getName())) {
                        System.out.println("校验权限");
                        return method.invoke(o, args);
                    }

                    return method.invoke(o, args);
                }
            });

            return proxy;
        } else {
            return o;
        }
    }
}

在测试类中调用findAll方法时,可以查看结果:
在这里插入图片描述

Spring属性注入

Spring属性注入主要依靠依赖一下两种方法:

构造方法

创建一个实体类,使用带参的构造方法创建实例:

package com.spring.test.entity;

public class User {
    private String name;
    private Integer age;

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

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

在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="user" class="com.spring.test.entity.User">
        <constructor-arg name="name" value="张三"/>
        <constructor-arg name="age" value="25"/>
    </bean>
</beans>

使用constructor-arg标签,其中属性name指定实体类的属性名称,value指定该属性注入的值

此时在测试方法中创建实例,并打印该实例,可以得到该实例的属性信息

setter方法

在实体类中创建对应属性的setter方法

package com.spring.test.entity;

public class User {
    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

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

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

在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="user" class="com.spring.test.entity.User">
        <property name="name" value="张三"/>
        <property name="age" value="25"/>
    </bean>
</beans>

对于在一个实体类中包含另一个实体类的情况,可以使用propertyref属性指定其他的bean的idname属性,例如:

新增一个用户组类,用户类中增加用户组类的属性,指定该用户所述的组别

package com.spring.test.entity;

public class UserGroup {
    private String groupName;

    public String getGroupName() {
        return groupName;
    }

    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }

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

<?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="user" class="com.spring.test.entity.User">
        <property name="name" value="张三"/>
        <property name="age" value="18"/>
        <property name="userGroup" ref="userGroup"/>
    </bean>

    <bean id="userGroup" class="com.spring.test.entity.UserGroup">
        <property name="groupName" value="管理员"/>
    </bean>
</beans>

p空间属性注入

为了简化属性注入,在Spring2.5引入了p空间的概念。p:<属性名>="常量值"注入常量属性,p:<属性名>-ref="Bean对象"注入Bean类型

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       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="user" class="com.spring.test.entity.User" p:name="张三" p:age="30" p:userGroup-ref="userGroup"/>
    <bean id="userGroup" class="com.spring.test.entity.UserGroup" p:groupName="管理员"/>
</beans>

SpEL注入

SpEL(Spring exprission lauguage)通过Spring表达式为类进行属性注入。SpEL支持常量属性注入、引用其他Bean、使用其他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="userpw" class="com.spring.test.entity.UserPw"/>
    <bean id="userGroup" class="com.spring.test.entity.UserGroup">
        <property name="groupName" value="#{'管理员'}"/>
    </bean>
    <bean id="user" class="com.spring.test.entity.User">
    	<!-- 直接为属性赋值 -->
        <property name="name" value="#{'张三'}"/>
        
        <!-- 调用其他Bean的方法为该Bean的属性赋值 -->
        <property name="password" value="#{userpw.getPassword()}"/>
        
        <property name="age" value="#{30}"/>
        
        <!-- 将其他Bean注入进该Bean -->
        <property name="userGroup" value="#{userGroup}"/>
    </bean>
</beans>

复杂类型数据注入

对于Array、List、Map、Set、Properties类型的属性,Spring也提供了相应的标签对复杂类型进行数据注入,例如:

新建一个类,设置Array、List、Map、Set、Properties类型的属性

package com.spring.test.service.entity;

import java.util.*;

public class CollectionBean {
    private String[] arr;
    private List<String> list;
    private Map<String, String> map;
    private Set<String> set;
    private Properties properties;

    public String[] getArr() {
        return arr;
    }

    public void setArr(String[] arr) {
        this.arr = arr;
    }

    public List<String> getList() {
        return list;
    }

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

    public Map<String, String> getMap() {
        return map;
    }

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

    public Set<String> getSet() {
        return set;
    }

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

    public Properties getProperties() {
        return properties;
    }

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

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

在配置文件中对该类进行数据注入:

<?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="collectionBean" class="com.spring.test.service.entity.CollectionBean">
        <property name="arr">
            <list>
            	<!-- <ref bean="beanName"> -->
                <value>abc</value>
                <value>abc</value>
                <value>abc</value>
            </list>
        </property>
        <property name="list">
            <list>
            	<!-- <ref bean="beanName"> -->
                <value>123</value>
                <value>123</value>
                <value>123</value>
            </list>
        </property>
        <property name="map">
            <map>
            	<!-- <entry key="key" value-ref="value"> -->
                <entry key="1" value="aaa"/>
                <entry key="2" value="aaa"/>
                <entry key="3" value="aaa"/>
            </map>
        </property>
        <property name="set">
            <set>
            	<!-- <ref bean="beanName"> -->
                <value>abc</value>
                <value>abd</value>
                <value>abe</value>
            </set>
        </property>
        <property name="properties">
            <props>
                <prop key="1">1</prop>
                <prop key="2">1</prop>
                <prop key="3">1</prop>
            </props>
        </property>
    </bean>
</beans>

如果集合的值为数据类型可以直接使用value属性为属性赋值,如果使用的类型集合则可以使用value-ref去引入其他bean。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值