Bean 的装配
Bean 的装配:即 Bean 对象的创建。容器根据代码要求创建 Bean 对象后再传递给代码的过程中,称为 Bean 的装配
Spring 的默认装配方式是容器首先调用 Bean 类的无参构造器,创建空值的实例对象
动态工厂 Bean
有时候项目可能需要通过工厂类来创建 Bean 实例,这时候我们有两种方案
一种是,只配置(创建)一个 Factory 工厂 Bean,在代码中调用 factory 的 getXxx() 方法获取所需要的对象实例,显然这种做法使得耦合度太高(代码里面都写死了调用什么方法)
另一种是(推荐),使用 Spring 的动态工厂 Bean ,factory-bean 指定的是相应的工厂 Bean,factory-method 指定创建所用方法,这时我们至少要定义两个 Bean ,工厂类 Bean,与所要创建的目标类 Bean
代码中直接获取 someService 的 Bean 即可
ISomeService service = (ISomeService) ac.getBean("someService");
静态工厂 Bean
因为静态工厂是通过调用工厂类的静态方法来创建实例的,所以不需要工厂对象,所以直接在配置文件中配置目标类 Bean 即可,当然工厂类 class 和工厂方法 factory-method 要配置
容器中 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
自定义 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 强转为实现类对象关闭
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
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 = someServiceStep4:获取到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 属性值则可以包含各种字符