正常情况下,应用中的bean同spring容器关系如下图:
尽管应用bean是Spring容器创建并建立依赖关系,应用只需使用bean即可,因此对bean来说Spring容器就是无感知的(无侵入编程)。但是还是存在需求需要应用bean同Spring容器进行交互,以便利用容器的能力完成相关工作。本篇就是讲述应用Bean如何与容器进行交互的。
创建
Bean实例化详细过程
框架加载BeanDefiniation,初始化容器环境,然后进行Bean的实例化:
1、如果有实现BeanPostProcessor的bean,则优先创建;
2、框架选择合适的Bean构建函数,创建Bean对象;
3、框架设置Bean属性;
4、如果bean实现了Aware接口,则执行;
5、如果存在BeanPostProcessor类,则执行postProcessBeforeInitialization;
6、如果bean有初始化方法(@PostConstruct标注或xml配置),则执行;
7、如果Bean实现了InitializingBean接口,则会调用afterPropertiesSet方法;
8、如果存在BeanPostProcessor类,则执行postProcessAfterInitialization;
9、如果bean有SmartInitializingSingleton,则在所有单实例bean实例化后执行afterSingletonsInstantiated
上述过程中存在“如果”的地方,就意味着应用可与容器交互的地方。
BeanPostProcessor
BeanPostProcessor接口主要是在bean初始化前后,应用可加入自己处理。注意:该类是针对所有应用bean的,因此处理时可根据Bean类做处理。
示例代码如下:
@Component
public class DemoBeanPostProcessor implements BeanPostProcessor {
ApplicationContext ctx;
DemoBeanPostProcessor(){
System.out.println("Spring DemoBeanPostProcessor contructing...");
}
//---------------------------------------------------------------------
// Implementation of BeanPostProcessor interface
//---------------------------------------------------------------------
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 可根据beanName 或 instanceof 针对性处理
System.out.println("Spring DemoBeanPostProcessor postProcessBeforeInitialization "+beanName+": "+bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Spring DemoBeanPostProcessor postProcessAfterInitialization "+beanName+": "+bean);
return bean;
}
}
Aware
感知类接口(接口名称格式:xxxAware),让实现的类可以感知容器的某些能力。SF的依赖注入亮点之一就是所有的Bean实现时都不需要考虑运行时要如何注入Spring容器(就是无感知),Bean和Spring容器耦合度很低(就是无侵入编程)。实际开发的时候,有时Bean需要用到Spring容器本身的功能资源,就需要提供一种机制让Bean能意识到Spring容器到存在并能调用Spring所提供的资源,这个机制就是由Aware来实现的。示例代码如下:
@Component
public class DemoAware implements ApplicationContextAware{
//ctx在初始化过程中通过Aware方式注入
ApplicationContext ctx;
//---------------------------------------------------------------------
// Implementation of ApplicationContextAware interface
//---------------------------------------------------------------------
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException{
System.out.println("DemoAware set ApplicationContextAware");
this.app = applicationContext;
System.out.println(app);
}
}
详见:https://blog.csdn.net/davidwkx/article/details/130790874
初始化方法(@PostConstruct)
bean的初始化方法在框架加载中会执行,标注初始化方法有两种:注解@PostConstruct或xml。
注解方式示例如下:
@PostConstruct
public void init() {
System.out.println("DemoInteractiveInInitialing init");
}
xml方式配置如下:
<bean id = "demoInteractiveInInitialing " class="com.learnsf.demo.spring.DemoInteractiveInInitialing " init-method="init"></bean>
afterPropertiesSet
InitializingBean接口定义了方法afterPropertiesSet,表示在Bean的属性设置后执行。
示例代码如下:
@Component
public class DemoInitializingBean implements InitializingBean{
//---------------------------------------------------------------------
// Implementation of InitializingBean interface
//---------------------------------------------------------------------
public void afterPropertiesSet() {
System.out.println("DemoInteractiveInInitialing afterPropertiesSet ");
}
}
afterSingletonsInstantiated
SmartInitializingSingleton接口定义了方法afterSingletonsInstantiated,表示所有单例bean初始化后执行。
示例代码如下:
@Component
public class DemoSmartInitializingSingleton implements SmartInitializingSingleton{
//---------------------------------------------------------------------
// Implementation of SmartInitializingSingleton interface
//---------------------------------------------------------------------
public void afterSingletonsInstantiated(){
System.out.println("DemoSmartInitializingSingleton::SmartInitializingSingleton在该类构建后被触发执行");
}
}
应用中
Aware
在bean初始化过程通过Aware方式获得相关容器资源,直接使用即可。
MethodInterceptor
通过实现接口MethodInterceptor,可在执行方法前后做其它处理。
示例代码如下:
@Component
public class ProxyInterceptor implements MethodInterceptor {
private String className;
private String methodName;
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
className=o.getClass().getName();
methodName=methodProxy.getSuperName();//method.getName();
before();
//调用被代理类的方法
Object result = methodProxy.invokeSuper(o, objects);
after();
return result;
}
// 预处理方法
private void before() {
System.out.println(String.format("%s.%s before excute: [%s] ",this.className, this.methodName,new Date()));
}
// 后处理方法
private void after() {
System.out.println(String.format("%s.%s after excute: [%s] ",this.className, this.methodName, new Date()));
}
}
AOP注解
通过AOP注解和实现完成所需工作。
销毁
bean销毁前,bean可以有两种方式介入:继承DisposableBean接口或@PreDestroy或xml模式配置。
DisposableBean / @PreDestroy
应用bean可在实现org.springframework.beans.factory.DisposableBean接口中完成销毁前工作。
@Component
@Scope("singleton")
public class DemoDisposableBean implements DisposableBean{
//---------------------------------------------------------------------
// Implementation of DisposableBean interface
//---------------------------------------------------------------------
@Override
public void destroy() throws Exception{
System.out.println("DemoDisposableBean destory start... ");
}
@PreDestroy
public void preDestory() throws Exception{
System.out.println("DemoDisposableBean @PreDestory start... ");
}
}
xml配置
<bean id = "DemoDisposableBean" class="com.learnsf.demo.spring.DemoDisposableBean" destory-method="destroy"></bean>
destory()方法不生效原因
实际使用可能出现destory()方法不起作用,有以下原因导致:
1、bean的作用域必须是单例的(singleton),不能是prototype。
2、容器没有正常关闭:如果容器不在Servlet或者EJB容器中,需要手动调用ApplicationContext子类中的close()方法,去实现相应关闭的功能。
示例如下:
public class LearnMain {
public static void main(String[] args) {
//创建springframework容器,初始化文件为app.xml
ApplicationContext context = new ClassPathXmlApplicationContext("app.xml");
...
//容器关闭才能执行bean。destory()方法
((ClassPathXmlApplicationContext)context).close();
}
}
特殊FactoryBean
大多数情况下,应用bean都由SF的BeanFactory实例化和管理。但如果应用有需要,可以通过的自己工厂bean(FactoryBean)创建bean。FactoryBean需实现接口FactoryBean或SmartFactoryBean,T就是FactoryBean要创建的Bean。
FactoryBean被容器加载后,然后执行getObject()获得bean,容器就完成使命了,也不再执行“Bean实例化详细过程”(见本文第一节)第三步开始的内容。
下面是一个FactoryBean实例:
@Component("studentFacoryBean")
public class StudentFacoryBean implements FactoryBean<Student>{
private static final String STUDENT_NAME = "Zhangsan";
public Student getObject() {
Student student = new Student();
student.setName(STUDENT_NAME);
return student;
}
public Class<?> getObjectType() {
return Student.class;
}
}