一起学SF框架系列5.3-spring-Beans-bean与Spring容器的交互方式

  正常情况下,应用中的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实现了InitializingBean接口,则会调用afterPropertiesSet方法;
7、如果bean有初始化方法(@PostConstruct标注或xml配置),则执行;
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();
    }
}

特殊Bean-FactoryBean

大多数情况下,应用bean都由SF的BeanFactory实例化和管理。但如果应用有需要,可以通过的自己工厂bean(FactoryBean)创建bean。FactoryBean需实现接口FactoryBean<T>或SmartFactoryBean<T>,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;
    }
}

特殊Bean-InstantiationAwareBeanPostProcessor

如果应用中有实现了InstantiationAwareBeanPostProcessor接口的bean,且在其中创建了要生成的bean,直接返回,且后续框架针对bean的初始化过程均不执行,不再执行“Bean实例化详细过程”(见本文第一节)第三步开始的内容。
示例如下:

@Component
public class DemoInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor{
	//---------------------------------------------------------------------
	// Implementation of InstantiationAwareBeanPostProcessor interface
	//---------------------------------------------------------------------
	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		if(!beanName.equals("DemoOptional"))
			return null;
		//DemoOptional类的实例在本处创建
		System.out.println("new DemoOptional in DemoInstantiationAwareBeanPostProcessor");
		return new DemoOptional();
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乐享技术

每一个打赏,都是对我最大的鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值