AnthonyZero's Bolg

Spring:常用扩展接口

前言

Spring是一款非常强大的框架,可以说是几乎所有的企业级Java项目使用了Spring,而Bean又是Spring框架的核心。Spring框架运用了非常多的设计模式,从整体上看,它的设计严格遵循了OCP—-开闭原则,即:

1、保证对修改关闭,即外部无法修改Spring整个运作的流程
2、提供对扩展开放,即可以通过继承、实现Spring提供的众多抽象类与接口来改变类加载的行为

Spring中的核心类

  • BeanFactory:产生一个新的实例,可以实现单例模式
  • BeanWrapper:提供统一的get及set方法
  • ApplicationContext:提供框架的实现,包括BeanFactory的所有功能

Spring常用的类和接口

A:ApplicationContextAware接口
当一个类需要获取ApplicationContext实例时,可以让该类实现ApplicationContextAware接口。
B:ApplicationEvent抽象类
当需要创建自定义事件时,可以新建一个继承自ApplicationEvent抽象类的类。
C:ApplicationListener接口
当需要监听自定义事件时,可以新建一个实现ApplicationListener接口的类,并将该类配置到Spring容器中。
D:BeanNameAware接口
当bean需要获取自身在容器中的id/name时,可以实现BeanNameAware接口。
E:InitializingBean接口
需要在bean的全部属性设置成功后做些特殊的处理,可以让该bean实现InitializingBean接口。
效果等同于bean的init-method属性的使用或者@PostContsuct注解的使用。
三种方式的执行顺序:先注解,然后执行InitializingBean接口中定义的方法,最后执行init-method属性指定的方法。
F:DisposableBean接口
当需要在bean销毁之前做些特殊的处理,可以让该bean实现DisposableBean接口。
效果等同于bean的destroy-method属性的使用或者@PreDestory注解的使用。
三种方式的执行顺序:先注解,然后执行DisposableBean接口中定义的方法,最后执行destroy-method属性指定的方法。
G:BeanPostProcessor接口
当需要对受管bean进行预处理时,可以新建一个实现BeanPostProcessor接口的类,并将该类配置到Spring容器中。
H:BeanFactoryPostProcessor接口
当需要对Bean工厂进行预处理时,可以新建一个实现BeanFactoryPostProcessor接口的类,并将该类配置到Spring容器中。

InitialingBean和DisposableBean

这两个接口是一组的,功能类似,因此放在一起:前者顾名思义在Bean属性都设置完毕后调用afterPropertiesSet()方法做一些初始化的工作,后者在Bean生命周期结束前调用destory()方法做一些收尾工作,afterPropertiesSet()方法就如同它的名字所表示的那样,是在Bean的属性都被设置完毕之后,才会调用
1、InitializingBean接口、Disposable接口可以和init-method、destory-method配合使用,接口执行顺序优先于配置
2、InitializingBean接口、Disposable接口底层使用类型强转.方法名()进行直接方法调用,init-method、destory-method底层使用反射,前者和Spring耦合程度更高但效率高,后者解除了和Spring之间的耦合但是效率低,使用哪个看个人喜好
3、afterPropertiesSet()方法是在Bean的属性设置之后才会进行调用,某个Bean的afterPropertiesSet()方法执行完毕才会执行下一个Bean的afterPropertiesSet()方法,因此不建议在afterPropertiesSet()方法中写处理时间太长的方法

Bean的生命周期

Alt text

  • Spring容器 从XML 文件中读取bean的定义,并实例化bean。
  • Spring根据bean的定义填充所有的属性。
  • 如果bean实现了BeanNameAware 接口,Spring 传递bean 的ID 到 setBeanName方法。
  • 如果Bean 实现了 BeanFactoryAware 接口, Spring传递beanfactory 给setBeanFactory 方法。
  • 如果有任何与bean相关联的BeanPostProcessors,Spring会在postProcesserBeforeInitialization()方法内调用它们.
  • 如果bean实现IntializingBean了,调用它的afterPropertySet方法,如果bean声明了初始化方法,调用此初始化方法。
  • 如果有BeanPostProcessors 和bean 关联,这些bean的postProcessAfterInitialization() 方法将被调用。
  • 如果bean实现了 DisposableBean,它将调用destroy()方法.

The bean 标签有两个重要的属性(init-method和destroy-method)。用它们你可以自己定制初始化和注销方法。它们也有相应的注解(@PostConstruct和@PreDestroy)。

BeanNameAware、ApplicationContextAware和BeanFactoryAware

@Component
public class AwareBean implements BeanNameAware,  BeanFactoryAware, ApplicationContextAware{
    private String                     beanName;
    private ApplicationContext        applicationContext;
    private BeanFactory                beanFactory;
    public void setBeanName(String beanName){
        System.out.println("Enter  AwareBean.setBeanName(), beanName = " + beanName + "\n");
        this.beanName = beanName;
    }
    public void setApplicationContext(ApplicationContext  applicationContext) throws BeansException{
        System.out.println("Enter  AwareBean.setApplicationContext(), applicationContext = "  + applicationContext + "\n");
        this.applicationContext = applicationContext;
    }
    public void setBeanFactory(BeanFactory beanFactory)  throws BeansException {
        System.out.println("Enter  AwareBean.setBeanFactory(), beanfactory = " + beanFactory  + "\n");
        this.beanFactory = beanFactory;
    }
}

如果你的BeanName、ApplicationContext、BeanFactory有用,那么就自己定义一个变量将它们保存下来,如果没用,那么只需要实现setXXX()方法,用一下Spring注入进来的参数即可

FactoryBean

传统的Spring容器加载一个Bean的整个过程,都是由Spring控制的,换句话说,开发者除了设置Bean相关属性之外,是没有太多的自主权的。FactoryBean改变了这一点,开发者可以个性化地定制自己想要实例化出来的Bean,方法就是实现FactoryBean接口。

1、getObject()方法是最重要的,控制Bean的实例化过程
2、getObjectType()方法获取接口返回的实例的class
3、isSingleton()方法获取该Bean是否为一个单例的Bean

BeanPostProcessor

针对每一个Bean的生成前后做一些逻辑操作,PostProcessor则帮助我们做到了这一点
BeanPostProcess接口有两个方法,都可以见名知意:
1、postProcessBeforeInitialization:在初始化Bean之前
2、postProcessAfterInitialization:在初始化Bean之后
值得注意的是,这两个方法是有返回值的,不要返回null,否则getBean的时候拿不到对象

@Component
public class PostProcessorBean implements BeanPostProcessor
{
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
    {
        System.out.println("Enter ProcessorBean.postProcessAfterInitialization()\n");
        return bean;
    }
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
    {
        System.out.println("Enter ProcessorBean.postProcessBeforeInitialization()");
        return bean;
    }
}

每一个Bean在初始前后 Spring都会调用BeanPostProcessor接口的两个方法。(容器级生命周期接口方法)

BeanFactoryPostProcessor

Spring允许在Bean创建之前,读取Bean的元属性,并根据自己的需求对元属性进行改变,比如将Bean的scope从singleton改变为prototype,最典型的应用应当是PropertyPlaceholderConfigurer,替换xml文件中的占位符,替换为properties文件中相应的key对应的value

BeanFactoryPostProcessor就可以帮助我们实现上述的功能,下面来看一下BeanFactoryPostProcessor的使用,定义一个BeanFactoryPostProcessor的实现类:

@Component
public class FactoryPostProcessorBean implements BeanFactoryPostProcessor
{
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurablelistablebeanfactory)
            throws BeansException
    {
        System.out.println("Enter FactoryPostProcessorBean.postProcessBeanFactory()\n");
    }
}

运行一下Spring容器,结果为:
Enter FactoryPostProcessorBean.postProcessBeanFactory()
....................................
....................................
....................................

1、BeanFactoryPostProcessor的执行优先级高于BeanPostProcessor
2、BeanFactoryPostProcessor的postProcessBeanFactory()方法只会执行一次
注意到postProcessBeanFactory方法是带了参ConfigurableListableBeanFactor的,这就和我之前说的可以使用BeanFactoryPostProcessor来改变Bean的属性相对应起来了。ConfigurableListableBeanFactory功能非常丰富,最基本的,它携带了每个Bean的基本信息,比如我简单写一段代码:

public void postProcessBeanFactory(ConfigurableListableBeanFactory     configurablelistablebeanfactory) throws BeansException
{
    BeanDefinition beanDefinition = configurablelistablebeanfactory.getBeanDefinition("xxx");
    MutablePropertyValues beanProperty = beanDefinition.getPropertyValues();
    System.out.println("scope before change:" + beanDefinition.getScope());
    beanDefinition.setScope("singleton");
    System.out.println("scope after change:" + beanDefinition.getScope());
    System.out.println("beanProperty:" + beanProperty);
}
这样就获取了xxx这个Bean的生命周期以及重新设置了Bean的生命周期

InstantiationAwareBeanPostProcessor

在Bean实例化前后做一些操作: InstantiationAwareBeanPostProcessor继承自BeanPostProcess接口

InstantiationAwareBeanPostProcessor 里有3 个方法,分别是 postProcessBeforeInstantiation (实例化之前),postProcessAfterInstantiation (实例化之后),postProcessPropertyValues (在处理Bean属性之前),开发者可以在这三个方法中添加自定义逻辑

1、Bean构造出来之前调用postProcessBeforeInstantiation()方法

2、Bean构造出来之后调用postProcessAfterInstantiation()方法

不过通常来讲,我们不会直接实现InstantiationAwareBeanPostProcessor接口,而是会采用继承InstantiationAwareBeanPostProcessorAdapter这个抽象类的方式来使用

实例化—-实例化的过程是一个创建Bean的过程,即调用Bean的构造函数,单例的Bean放入单例池中
初始化—-初始化的过程是一个赋值的过程,即调用Bean的setter,设置Bean的属性