原文地址
?
?
?
前面因为总结的累了,把IoC的两个步骤,只写了一半,就仅仅把容器启动的方面说了说,对于实例化的阶段,我前面并没有说,在这节中,准备讲一讲,实例化阶段。
这个部分,其实实例化,一般都是用反射或者cglib,底层封装的也比较深,我随着代码debug的过程中,也没有接触到这个部分。但是在实例化bean的过程中,还是看到了挺多东西。
生命周期的图,基本上有可能是以下这种
从图中可以看到,在这个阶段,最重要的不是实例化本身,而是实例化前后会做的一些操作。实例化有些不同的,应该就是在实例化时可能会遇到绑定属性的相关操作,这个时候不是用传统的反射来做,而是用BeanWrapper来包装绑定。有个印象即可。
BeanFactory
ApplicationContext
以上两图为借用
当对象实例化完成并且相关属性以及依赖设置完成之后,spring容器会检查当前对象实例是否实现了一系列的以Aware命名结尾的接口定义。如果是,则将这些Aware接口定义中规定的依赖注入给当前对象实例。
下面总结一下各种Aware接口以及作用
LoadTimeWeaverAware 加载Spring Bean时织入第三方模块,如AspectJ BeanClassLoaderAware 加载Spring Bean的类加载器 ResourceLoaderAware 底层访问资源的加载器 BeanFactoryAware 得到BeanFactory引用 ServletConfigAware 得到ServletConfig ServletContextAware 得到ServletContext MessageSourceAware 国际化 ApplicationEventPublisherAware 应用事件我们看一下这个接口
monospace; white-space: pre-wrap; background: #23241f;" class="hljs armasm">package org.springframework.beans.factory.config;
import org.springframework.beans.BeansException;
/**
*
*/
public interface BeanPostProcessor {
/**
* 初始化之前做操作
*/
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
/**
* 初始化之后做操作
*/
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
① 在注解时使用
在使用Spring构建目的时候,现在应该很多人都习惯于用注解了,因为注解简单。@Component @Controller @Service @Repository @Autowired 等注解来便捷开发,下面来探讨BeanPostProcessor在@Autowired 中的运用。
在使用@Autowired之前需要在容器中配置AutowiredAnnotationBeanPostProcessor。
② 处理Aware接口类
我们可以来看一小段ApplicationContextAwareProcessor的代码
package org.springframework.context.support;
/**
* 可以看到是实现自BeanPostProcessor的
*/
class ApplicationContextAwareProcessor implements BeanPostProcessor {
/**
* 略去部分代码
*/
/**
* 在初始化之前做的操作
*/
@Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareInterfaces(bean);
return null;
}
}, acc);
}
else {
// 直奔重点,invoke这些Aware接口
invokeAwareInterfaces(bean);
}
return bean;
}
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(
new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
/**
* 初始化之后就没有做其他操作了
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
当然,每个人都可以自己写一个BeanPostProcessor的实现类。
不过写完之后注意要在Spring配置文件中配置一下。具体操作:
http://blog.csdn.net/caihaijiang/article/details/35552859
这个两个东西,其实都是做一件事,就是在bean的初始化阶段做一些其他的操作。
比如,在有些情况下,某个业务对象实例化完成后,还不能处于可以使用状态。这个时候就可以让该业务对象实现该接口,并在方法afterPropertiesSet()中完成对该业务对象的后续处理。
以上这段文字是摘抄下来的,但是我真的想不到,到底为什么要这样操作,你说要改变初始化的状态,那在一开始初始化时直接改成那个状态不就可以了吗?为什么要在这里做变化?不懂。但是操作就是,在bean初始化阶段做操作。
这种操作,有三种方式来做InitializingBean、init-method和@PostConstruct。
这是一个接口,只有一个方法。
public interface InitializingBean {
function">void afterPropertiesSet() throws Exception;
}
如果一个bean想要在初始化阶段做操作,第一种方法就是实现这个接口
public Person implements InitializingBean {
void afterPropertiesSet() throws Exception{
System.out.println(" 初始化阶段操作 ")
}
}
但是这种方式,其实还是会有点儿问题,这个对象和Spring的耦合度比较高。如果想使这个耦合度比较低,那么就用其他的两种方法了。
用一个例子,就能很好的把这个东西说清楚。
Person
class Person{
...
void eat(){
System.out.println("I am eating...");
}
}
beans.xml
<beans>
<bean id="person" class="Person" .
init-method="eat">
</bean>
...
</beans>
到时候实例化Person的时候,就会调用这个eat方法了。
其实这个注解和init-method是一样的。
person
class Person{
...
@PostContruct
void eat(){
System.out.println("I am eating...");
}
}
在Bean销毁之前肯定也可以做些操作,这三者的特点和用法,其实都和初始化那部分差不多。不同的地方在下面这部分代码处体现。
Person
class Person{
...
@PostContruct
void eat(){
System.out.println("I am eating...");
}
@PreDestroy
void sleep(){
System.out.println("I will go to sleep...");
}
}
Main
class Main{
public static void main(String [] args){
ApplicationContext ac=new ClasspathXmlApplicationContext("beans.xml");
Person person = (Person) ac.getBean("person");
// 不一样之处,销毁时要调用,不然没人知道你什么不要。
person.sleep();
}
beans.xml
<beans>
<bean id="person" class="Person" >
...
</bean>
</beans>
?
原文地址