Bean简介和Xml装配
标签:Spring

Bean简介和Xml装配

1. IoC容器装配Bean(xml配置方式)

1.1 Spring 提供配置Bean 三种实例化方式

  1. 使用类构造器实例化(默认无参数)
<bean id=“personService" class="cn.itcast.bean.impl.PersonServiceImpl"/>
  1. 使用静态工厂方法实例化(简单工厂模式)
<bean id="personService" class="com.itcast.factory.PersonServiceFactory"    factory-method="createPersonService" />
public class PersonServiceFactory {
    public  static PersonService createPersonService(){
     	return new PersonServiceImpl();
    }
}
  1. 使用实例工厂方法实例化(工厂方法模式):
 <bean id=“personServiceFactory" class="com.itcast.factory.PersonServiceFactory"/>

 <bean id="personService" factory-bean=“personServiceFactory" 
factory-method="createPersonService" />
public class PersonServiceFactory {
    public  PersonService createPersonService(){
     	return new PersonServiceImpl();
     }
}

1.2 Bean的其它属性配置

<bean> 元素的id属性 和 name属性的区别

早期Spring开发中 Bean的 id属性 ,遵守xml语法 id约束

如果元素没有id只有name ,name 属性值可以作为id 使用

1.3 Bean的作用域

类别 说明
singleton (默认的) 在Spring IoC容器中仅存在一个Bean实例,Bean以单例方式存在
prototype 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时 ,相当于执行new XxxBean()
request 每次HTTP请求都会创建一个新的Bean,将Bean放入request范围,该作用域仅适用于WebApplicationContext环境
session 同一个HTTP Session 共享一个Bean,不同Session使用不同Bean,仅适用于WebApplicationContext 环境
globalSession 一般用于Porlet应用环境,分布式系统存在全局session概念,该作用域仅适用于WebApplicationContext 环境

1.4 Bean的生命周期

在配置 元素,通过 init-method 指定Bean的初始化方法,通过 destroy-method 指定Bean销毁方法

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
applicationContext.close();

Bean的完整的生命周期(十一步)

  1. instantiate bean对象实例化
  2. populate properties 封装属性
  3. 如果Bean实现BeanNameAware 执行 setBeanName
  4. 如果Bean实现BeanFactoryAware 或者 ApplicationContextAware 设置工厂 setBeanFactory 或者上下文对象 setApplicationContext
  5. 如果存在类实现 BeanPostProcessor(后处理Bean) ,执行postProcessBeforeInitialization
  6. 如果Bean实现InitializingBean 执行 afterPropertiesSet
  7. 调用 <bean init-method="init"> 指定初始化方法 init
  8. 如果存在类实现 BeanPostProcessor(处理Bean) ,执行postProcessAfterInitialization
  9. 执行业务处理
  10. 如果Bean实现 DisposableBean 执行 destroy
  11. 调用 <bean destroy-method="customerDestroy"> 指定销毁方法 customerDestroy

第三步和第四步,使Bean 了解Spring容器

第五步和第八步,使用BeanPostProcessor 就是钩子函数,作用用来对Bean对象进行扩展

1.4.1 测试Bean的生命周期

UserDAO

package lifecycle;

/**
 * Created By liuyao on 2018/5/6 14:01.
 */

/**
 * 用户数据库操作
 */
public interface UserDAO {
    void add();

    void search();
}

UserDAOImpl

package lifecycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * Created By liuyao on 2018/5/6 14:02.
 */
public class UserDAOImpl implements UserDAO, BeanNameAware, ApplicationContextAware, InitializingBean, DisposableBean {
    private String username;

    public UserDAOImpl() {
        System.out.println("step 1: bean对象实例化");
    }

    public void setUsername(String username) {
        this.username = username;
        System.out.println("step 2: 封装属性");
    }

    @Override
    public void add() {
        System.out.println("step 9: 业务操作-添加");
    }

    @Override
    public void search() {
        System.out.println("step 9: 业务操作-查询");
    }

    @Override
    public void setBeanName(String beanName) {
        System.out.println("step 3: 将XML配置的Bean的id设置到程序中 " + beanName);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("step 4: 将工厂上下文对象设置到bean中");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("step 6: 属性设置完成后的方法");
    }

    public void myinit() {
        System.out.println("step 7: 自己配置的初始化方法");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("step 10: 无需配置的的销毁方法");
    }

    public void mydestroy() {

        System.out.println("step 11: 自己配置的销毁方法");
    }
}

MyBeanPostProccessor:

package lifecycle;

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

/**
 * Created By liuyao on 2018/5/6 14:17.
 */

/**
 * 自定义后处理bean
 */
public class MyBeanPostProccessor implements BeanPostProcessor {


    /**
     * bean 就是对象实例
     * beanName 就是xml配置Bean的id或者name
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("step 5: 执行后处理bean的初始化完成前方法");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("step 8: 执行后处理Bean的初始化完成后的方法");
        return bean;
    }
}

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">
    <bean id="userDAO" class="lifecycle.UserDAOImpl" init-method="myinit" destroy-method="mydestroy">
        <property name="username" value="liuyao"></property>
    </bean>
    <!--必须配置后处理Bean,这个bean没有id,因为由Spring框架内部调用-->
    <bean class="lifecycle.MyBeanPostProccessor"></bean>
</beans>

UserDAOImplTest:

package lifecycle;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created By liuyao on 2018/5/6 14:35.
 */
@RunWith(BlockJUnit4ClassRunner.class)
public class UserDAOImplTest {

    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
    
    @Test
    public void testLifeCycle() {
        UserDAO userDAO = (UserDAO) this.applicationContext.getBean("userDAO");
        userDAO.add();
        userDAO.search();
        this.applicationContext.close();
    }
}

最后执行结果:

可见,上面依次执行了Bean的生命周期里面的所有方法。

2. 依赖注入Bean的属性

对于类成员变量,注入方式有三种

Spring支持前两种

2.1 构造器注入

Person:

package di;

/**
 * Created By liuyao on 2018/5/6 16:22.
 */
public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

ApplicationContext.xml

 <bean id="person" class="di.Person">
        <constructor-arg index="0" value="liuyao"/>
        <constructor-arg index="1" value="20"/>
    </bean>

测试结果为:

2.2 Set方法注入

Friend:

package di;

/**
 * Created By liuyao on 2018/5/6 16:36.
 */
public class Friend {
    private Person person;
    private String name;

    public void setPerson(Person person) {
        this.person = person;
    }

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

    @Override
    public String toString() {
        return "Friend{" +
                "person=" + this.person +
                ", name='" + this.name + '\'' +
                '}';
    }
}

ApplicationContext.xml

    <bean id="friend" class="di.Friend">
        <property name="name" value="zhangsan"></property>
        <property name="person" ref="person"></property>
    </bean>

测试结果:

2.3 P空间

为了简化XML文件配置,Spring从2.5开始引入一个新的p名称空间

导入约束:

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

上面的进行改写:

<bean id="friend" class="di.Friend" p:name="zhangsan" p:person-ref="person">

2.4 spEL表达式

spring3.0之后引入 spEL 表达式,通过#号的方式来属性注入。

Car

package di;

/**
 * Created By liuyao on 2018/5/7 17:17.
 */
public class Car {
    private String carname;

    private int price;

    public void setPrice(int price) {
        this.price = price;
    }

    public void setCarname(String carname) {
        this.carname = carname;
    }

    @Override
    public String toString() {
        return "Car{" +
                "carname='" + this.carname + '\'' +
                ", price=" + this.price +
                '}';
    }
}

CarInfo:

package di;

/**
 * Created By liuyao on 2018/5/7 17:18.
 */
public class CarInfo {
    public String getName() {
        return "Car-Info";
    }

    public int calculatePrice() {
        return 10000;
    }
}

ApplicationContext.xml

 <bean id="carInfo" class="di.CarInfo"></bean>

<bean id="car" class="di.Car">
        <property name="carname" value="#{carInfo.name}"></property>
        <property name="price" value="#{carInfo.calculatePrice()}"></property>
</bean>

测试结果:

3. 集合属性注入

Spring对象java.utils中常用集合对象提供了专门的配置标签

CollectionBean:

package di;

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

/**
 * Created By liuyao on 2018/5/7 17:42.
 */
public class CollectionBean {
    private List<String> hobbies;

    private Set<Integer> numbers;

    private Map<String, String> map;

    public void setHobbies(List<String> hobbies) {
        this.hobbies = hobbies;
    }

    public void setNumbers(Set<Integer> numbers) {
        this.numbers = numbers;
    }

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

    @Override
    public String toString() {
        return "CollectionBean{" +
                "hobbies=" + this.hobbies +
                ", numbers=" + this.numbers +
                ", map=" + this.map +
                '}';
    }
}

ApplicationContext.xml

    <bean class="di.CollectionBean" id="collectionBean">
        <property name="hobbies">
            <list>
                <value>音乐</value>
                <value>体育</value>
            </list>
        </property>
        <property name="numbers">
            <set>
                <value>1</value>
                <value>2</value>
            </set>
        </property>
        <property name="map">
            <map>
                <entry key="aa" value="bb"></entry>
                <entry key="cc" value="dd"></entry>
            </map>
        </property>
    </bean>

4. 在Spring框架中引入多个XML配置文件

第一种 并列引入多个XML

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans1.xml", "beans2.xml");

第二种 引入总xml文件,在总xml文件引入 子xml文件

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

applicationContext.xml

<import resource="classpath:bean1.xml"/>
<import resource="classpath:bean2.xml"/>

在开发中主要使用 第二种 , 将配置文件分离配置 便于维护管理

  • 9 min read

CONTRIBUTORS


  • 9 min read