[Js-Spring]Bean的装配

Bean 的装配

Bean 的装配:即 Bean 对象的创建。容器根据代码要求创建 Bean 对象后再传递给代码的过程中,称为 Bean 的装配

Spring 的默认装配方式是容器首先调用 Bean 类的无参构造器,创建空值的实例对象

<bean id="someService" class="com.neu.ba01.SomeServiceImpl"></bean>

动态工厂 Bean

有时候项目可能需要通过工厂类来创建 Bean 实例,这时候我们有两种方案

一种是,只配置(创建)一个 Factory 工厂 Bean,在代码中调用 factory 的 getXxx() 方法获取所需要的对象实例,显然这种做法使得耦合度太高(代码里面都写死了调用什么方法)

另一种是(推荐),使用 Spring 的动态工厂 Bean ,factory-bean 指定的是相应的工厂 Bean,factory-method 指定创建所用方法,这时我们至少要定义两个 Bean ,工厂类 Bean,与所要创建的目标类 Bean

<!-- 动态工厂Bean -->
<bean id="serviceFactory" class="com.neu.ba02.ServiceFactory"></bean>
<!-- 目标Bean -->
<bean id="someService" factory-bean="serviceFactory" factory-method="getService"></bean>

 

代码中直接获取 someService 的 Bean 即可

ISomeService service = (ISomeService) ac.getBean("someService");

 

静态工厂 Bean

因为静态工厂是通过调用工厂类的静态方法来创建实例的,所以不需要工厂对象,所以直接在配置文件中配置目标类 Bean 即可,当然工厂类 class 和工厂方法 factory-method 要配置

<!-- 静态态工厂Bean -->
<bean id="someService" class="com.neu.ba03.ServiceFactory" factory-method="getService"></bean>

 

容器中 Bean 的作用域

  • singleton:单态模式。在整个容器中,使用 singleton 定义的 Bean 将会是单例的,只有一个实例
  • prototype:原型模式。每次调用 getBean() 方法都是一个新的实例
  • request:每次 HTTP 请求,都会产生一个不同的 Bean 实例
  • session:对于每个不同的 HTTP session,都将产生一个不同的 Bean 的实例

注:

scope 为 singleton 的 Bean 对象,在容器被创建时即装配好了,这是 Bean 的默认 scope 值

scope 为 protoscope 的 Bean 对象,Bean 实例在使用该 Bean 实例的时候才会被创建

Bean 后处理器

Bean 后处理器是一种特殊的 Bean,容器中所有的 Bean 在初始化的时候,均会执行此类的两个方法。代码中需要自定义后处理器,实现 BeanPostProcessor 接口,该接口中包含两个方法,分别在目标 Bean 初始化完毕之前与之后执行,它们的返回值是:功能被扩展或增强后的Bean对象

在配置文件中配置 Bean 

<bean class="com.neu.ba05.MyBeanPostProcessor"></bean>

 

自定义 BeanPostProcessor

package com.neu.ba05;

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

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

public class MyBeanPostProcessor implements BeanPostProcessor {

    public MyBeanPostProcessor() {
        super();
        System.out.println("初始化MyBeanPostProcessor对象");
    }

    // bean:当前调用执行Bean后处理器的Bean对象
    // beanName:当前调用执行Bean后处理器的Bean对象的ID
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("执行MyBeanPostProcessor的postProcessBeforeInitialization()方法");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("执行MyBeanPostProcessor的postProcessAfterInitialization()方法");
        Object proxy = null;
        if ("someService1".equals(beanName)) {
            proxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(),
                    new InvocationHandler() {

                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            Object result = method.invoke(bean, args);
                            if (result != null) {
                                result = ((String) result).toUpperCase();
                            }
                            return result;
                        }
                    });
            return proxy;
        }
        return bean;
    }

}

 

观察上面代码,不说也很容易推测出 beanName 是我们获取到的 Bean 实例的名字,bean 是我们获取到的 Bean 实例,返回的是通过 JDK 动态代理得到的强化过的 Bean 实例

定制 Bean 的生命始末

可以为 Bean 定制初始化后的生命行为,也可以为 Bean 定制销毁前的生命行为。

定制的流程为首先这些方法在 Bean 类中事先定义好(方法名随意的 public void 方法),然后在 Bean 标签中添加如下属性,

init-method:指定初始化方法的方法名

destroy-method:指定销毁方法的方法名

注:

若想看到结果,需要

1)Bean 为 singleton 

2)要确保容器关闭,接口 ApplicationContext 没有 close() 方法,但其实现类有。所以,可以将 ApplicationContext 强转为实现类对象关闭

<?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 definitions here -->
    <bean id="someService" class="com.neu.ba06.SomeServiceImpl"
        init-method="initAfter" destroy-method="preDestory"></bean>

</beans>

 

package com.neu.ba06;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {

    @Test
    public void test01() {
        // 加载Spring配置文件,创建Spring容器对象
        String resource = "com/neu/ba06/applicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
        // 从容器中获取指定的Bean对象
        ISomeService service = (ISomeService) ac.getBean("someService");
        service.doFirst();
        service.doSecond();
        // 销毁方法执行有两个要求:
        // 1)被销毁的对象需要是singleton的,即单例的
        // 2)容器需要显式关闭
        ((ClassPathXmlApplicationContext) ac).close();
    }
}

 

Bean 的生命周期

Bean 实例从创建到最后阶段经过很多过程,执行很多生命周期方法

Step1:调用无参构造函数,创建实例对象

Step2:调用参数的 setter,为属性注入值

Step3:若 Bean 实现了 BeanNameAware 接口,则会执行接口方法 setBeanName(String beanId),使 Bean 类可以获得其在容器中的 id 名称

Step4:若 Bean 实现了 BeanFactoryAware 接口,则会执行接口方法 setBeanFactory(BeanFactory factory),使 Bean 类可以获取到 BeanFactory 对象

Step5:若定义并注册了 Bean 后处理器 BeanPostProcessor,则执行接口方法 postProcessBeforeInitialization()

Step6:若 Bean 实现了 InitializingBean 接口,则执行接口方法 afterPropertiesSet(),该方法在 Bean 的所有属性的 set 方法执行完毕之后执行,标志着 Bean 初始化结束

Step7:若设置了init-method 方法,则执行

Step8:若定义并注册了 Bean 后处理器 BeanPostProcessor,则执行接口方法 postProcessAfterInitialization()

Step9:执行业务方法

Step10:若 Bean 实现了 DisposableBean 接口,则执行接口方法 destroy()

Step11:若设置了 destroy-method 方法,则执行

ISomeService.java

package com.neu.ba07;

public interface ISomeService {
    public String doFirst();

    public void doSecond();
}

SomeServiceImpl.java

package com.neu.ba07;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class SomeServiceImpl
        implements ISomeService, BeanNameAware, BeanFactoryAware, InitializingBean, DisposableBean {
    private String adao;
    private String bdao;

    public void setAdao(String adao) {
        System.out.println("Step2:执行setAdao()方法");
        this.adao = adao;
    }

    public void setBdao(String bdao) {
        System.out.println("Step2:执行setBdao()方法");
        this.bdao = bdao;
    }

    public SomeServiceImpl() {
        System.out.println("Step1:对象的创建");
    }

    @Override
    public String doFirst() {
        System.out.println("Step9:(执行主业务方法)执行doFirst()方法");
        return null;
    }

    @Override
    public void doSecond() {
        System.out.println("执行doSecond()方法");
    }

    public void initAfter() {
        System.out.println("Step7:--初始化之后--");
    }

    public void preDestory() {
        System.out.println("Ste11:---销毁之前---");
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("Step3:beanName = " + name);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("Step4:获取到BeanFactory容器");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Step6:当前Bean的初始化工作已经完毕");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("Step10:准备开始销毁工作,进行销毁流程");
    }

    @Override
    public String toString() {
        return "SomeServiceImpl [adao=" + adao + ", bdao=" + bdao + "]";
    }

}

 

MyBeanPostProcessor.java

package com.neu.ba07;

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

public class MyBeanPostProcessor implements BeanPostProcessor {

    // bean:当前调用执行Bean后处理器的Bean对象
    // beanName:当前调用执行Bean后处理器的Bean对象的ID
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Step5:执行MyBeanPostProcessor的postProcessBeforeInitialization()方法");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Step8:执行MyBeanPostProcessor的postProcessAfterInitialization()方法");
        
        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 definitions here -->
    <bean id="someService" class="com.neu.ba07.SomeServiceImpl" init-method="initAfter" destroy-method="preDestory">
        <property name="adao" value="AAA"></property>
        <property name="bdao" value="BBB"></property>
    </bean>
    <bean class="com.neu.ba07.MyBeanPostProcessor"></bean>

</beans>

 

MyTest.java

package com.neu.ba07;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {

    @Test
    public void test01() {
        // 加载Spring配置文件,创建Spring容器对象
        String resource = "com/neu/ba07/applicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
        // 从容器中获取指定的Bean对象
        ISomeService service = (ISomeService) ac.getBean("someService");
        service.doFirst();

        ((ClassPathXmlApplicationContext) ac).close();
    }
}

 

执行结果:(控制台输出)

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
Step1:对象的创建
Step2:执行setAdao()方法
Step2:执行setBdao()方法
Step3:beanName = someService
Step4:获取到BeanFactory容器
Step5:执行MyBeanPostProcessor的postProcessBeforeInitialization()方法
Step6:当前Bean的初始化工作已经完毕
Step7:--初始化之后--
Step8:执行MyBeanPostProcessor的postProcessAfterInitialization()方法
Step9:(执行主业务方法)执行doFirst()方法
Step10:准备开始销毁工作,进行销毁流程
Ste11:---销毁之前---

 

<bean/>标签的 id 属性与 name 属性

一般情况下,命名<bean/>使用 id 属性,而不使用 name 属性。在没有 id 属性的情况下,name 属性与 id 属性的作用是相同的。但是当<bean/>中含有一些特殊字符的时候,就必须要使用 name 属性了。

id 的命名必须要满足 XML 对 ID 的命名规范:必须以字幕开头,可以包含字母,数字,下划线,连字符,句号,冒号

name 属性值则可以包含各种字符

posted @ 2018-03-18 23:47  Js_zero  阅读(647)  评论(0编辑  收藏  举报