7.17周总结

最近在忙项目中有关OData服务的开发,由于知识储备的不足、项目的特殊复杂性,总体来说做的比较头疼。抽时间可以把自己做过的这一块东西回顾、总结一下。在今天这个悠闲的周末傍晚,静下心来总结一下这周了解到的有关Spring的一些扩展接口的其他小玩意,喵喵喵~~~

目录:

  1. Spring扩展接口
  1. 小玩意

1. Spring 扩展接口

Spring整个框架严格遵循“开闭原则”,即“对扩展开放,对修改关闭”。个人理解为,Spring框架核心之一就是IOC,即"Bean Container",整个"Bean Container"的生命周期大致为:加载(XML或者Anotation)、初始化(初始化相应的Bean)、runtime(在runtime提供Bean)、销毁,也就是说,无论在什么情况下,Spring都是按照这一套流程走下来的,没有提供相应的类、接口、方法来改变这个过程,最多提供一些接口来“丰富”一下这个过程,即对“扩展开发”。这些接口包括:

  1. BeanFactoryPostProcessor
  1. InstantiationAwareBeanPostProcessor
  2. BeanNameAware
  3. BeanFactoryAware
  4. BeanPostProcessor
  5. InitializingBean
  6. DiposibleBean
  7. FactoryBean
  8. 在Bean生命周期中相应接口调用

对于整个 Bean Container 的扩展

  • BeanFactoryPostProcessor
public interface BeanFactoryPostProcessor {

    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

从接口定义上可以得知,其只有一个方法

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

参数类型为ConfigurableListableBeanFactory,追根溯源,该接口的定义如下:

public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {

    void ignoreDependencyType(Class<?> type);

    void ignoreDependencyInterface(Class<?> ifc);

    void registerResolvableDependency(Class<?> dependencyType, Object autowiredValue);

    boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor)throws NoSuchBeanDefinitionException;

    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    Iterator<String> getBeanNamesIterator();

    void clearMetadataCache();

    void freezeConfiguration();

    boolean isConfigurationFrozen();

    void preInstantiateSingletons() throws BeansException;

}

其中有一个方法

BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

通过传入相应的Bean Name,就能拿到对应的BeanDefinition,其对应着一个Bean的元信息描述。
有关BeanDefinition的接口描述:


public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

    int ROLE_APPLICATION = 0;

    int ROLE_SUPPORT = 1;

    int ROLE_INFRASTRUCTURE = 2;

    String getParentName();

    void setParentName(String parentName);

    String getBeanClassName();

    void setBeanClassName(String beanClassName);

    String getFactoryBeanName();

    void setFactoryBeanName(String factoryBeanName);

    String getFactoryMethodName();

    void setFactoryMethodName(String factoryMethodName);

    String getScope();

    void setScope(String scope);

    boolean isLazyInit();

    void setLazyInit(boolean lazyInit);

    String[] getDependsOn();

    void setDependsOn(String... dependsOn);

    boolean isAutowireCandidate();

    void setAutowireCandidate(boolean autowireCandidate);

    boolean isPrimary();

    void setPrimary(boolean primary);

    ConstructorArgumentValues getConstructorArgumentValues();

    MutablePropertyValues getPropertyValues();

    boolean isSingleton();

    boolean isPrototype();

    boolean isAbstract();

    int getRole();

    String getDescription();

    String getResourceDescription();

    BeanDefinition getOriginatingBeanDefinition();

}

其中里边有几个比较常用的方法:

void setFactoryBeanName(String factoryBeanName);
void setBeanClassName(String beanClassName);
void setScope(String scope);
void setLazyInit(boolean lazyInit);

以及一些相应的Get方法。
即在runtime时,可以通过以上接口来动态修改Bean的元描述信息:name、isLazyInit,scope

所以让我们回到最初探索的地方,扩展接口BeanFactoryPostProcessor:实现这个接口的postProcessBeanFactory,来根据需要在Spring启动时动态修改相应Bean的元描述信息。

  • BeanFactoryAware

该接口的详细描述如下:

public interface BeanFactoryAware extends Aware {

    void setBeanFactory(BeanFactory beanFactory) throws BeansException;

}

也只有一个方法

void setBeanFactory(BeanFactory beanFactory) throws BeansException;

同样可以实现该接口,在runtime获得该BeanFactory

对于 Bean 的扩展

  • InstantiationAwareBeanPostProcessor

该接口的定义如下:

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

    Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;

    boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;

    PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;

}

其中包含了三个方法:

    Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;

    boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;

    PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;

这三个方法的作用时期是在Bean的实例化阶段。之前我也不太清楚“实例化”和“初始化”的区别,后来查了资料,发现大概是这样的:
实例化----实例化的过程是一个创建Bean的过程,即调用Bean的构造函数,单例的Bean放入单例池中。
初始化----初始化的过程是一个赋值的过程,即调用Bean的setter,设置Bean的属性

  • BeanNameAware

该接口的详细描述如下:


public interface BeanNameAware extends Aware {

    void setBeanName(String name);

}

这个接口很简单,只有一个方法

void setBeanName(String name);

在实际开发中,可以实现该接口,动态地获取每一个被加载到"Bean Container"中的Bean Name

  • BeanPostProcessor

该接口的详细描述如下:


public interface BeanPostProcessor {

    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

}

其中包含了两个方法:

Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

这两个方法分别是在Bean初始化的前后起作用,我们可以根据beanName来筛选出相应的Bean,并结合具体的业务需求来对某些Bean进行一些有针对性的预处理。

  • InitializingBean

其接口的详细描述如下:


public interface InitializingBean {

    void afterPropertiesSet() throws Exception;

}

该接口只有一个方法

void afterPropertiesSet() throws Exception;

很明显,该接口是在某个Bean的所有Properties初始化完成之后起作用。该方法没有任何参数,可以根据具体业务需求来自定义处理。

扩展: 在Spring对于XML配置Bean的规范中,提供了一个属性init-method,作用于该方法一样。该属性的具体用法大致如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
    
    <bean id="common0" class="org.xrq.bean.common.CommonBean" init-method="initMethod">
        <property name="commonName" value="common0"/>
    </bean>
    
    <bean id="common1" class="org.xrq.bean.common.CommonBean" init-method="initMethod">
        <property name="commonName" value="common1"/>
    </bean>
</beans>
  • DisposableBean

该接口的具体描述如下:


public interface DisposableBean {

    void destroy() throws Exception;

}

其中也只有一个方法

void destroy() throws Exception;

该方法是在某个Bean的结束时(Bean Container被销毁时)起作用。

  • FactoryBean

该接口的详细描述如下:

public interface FactoryBean<T> {

    T getObject() throws Exception;

    Class<?> getObjectType();

    boolean isSingleton();

}

其中有三个方法,实现方法getObject,就可以加载自定义的Bean

在Bean生命周期中相应接口调用:

参考文章:Spring Bean的生命周期(非常详细)

2. 小玩意

之前一直对Spring体系中的BeanFactoryApplicationContext搞不明白,这次查了一点资料,逐渐理清了。

  • BeanFactory:是一个对于IOC容器行为最基本的规范接口,比如getBean()
    有关BeanFactory的具体实现,常见XmlBeanFactory,不过该类已经被弃用了。
  • ApplicationContext: 继承BeanFactory,不仅具有BeanFactory的功能,还支持国际化message处理,比如MessageSource接口,事件监听
    有关ApplicationContext的具体实现,常见XmlWebApplicationContext,ClassPathXmlApplicationContext,FileSystemApplicationContext,AnnotationConfigApplicationContext

有关ApplicationContext的扩展:获取ApplicationContext的几种方式:

  • 直接通过上面列举的几种描述来获得,比如
pplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml"); 
  • 通过Spring提供的工具类获取ApplicationContext对象,比如
ApplicationContext ac = WebApplicationContextUtils.getRequiredWebApplicationContext(ServletContext sc); 
  • 继承自抽象类ApplicationObjectSupport
    Spring初始化时,会通过该抽象类的setApplicationContext(ApplicationContext context)方法将ApplicationContext 对象注入

  • 继承自抽象类WebApplicationObjectSupport
    说明:类似上面方法,调用getWebApplicationContext()获取WebApplicationContext

  • 实现接口ApplicationContextAware

  • 通过Spring提供的ContextLoader

WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();

最后提供一种不依赖于servlet,不需要注入的方式。但是需要注意一点,在服务器启动时,Spring容器初始化时,不能通过以下方法获取Spring 容器

参考文章

  1. Spring8:一些常用的Spring Bean扩展接口
  2. Spring Bean的生命周期(非常详细)
  3. Spring在代码中获取bean的几种方式

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 118,319评论 14 132
  • Spring容器高层视图 Spring 启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相...
    码农老K阅读 17,198评论 5 45
  • Spring容器高层视图 Spring 启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相...
    Theriseof阅读 2,158评论 0 24
  • 拿到小文友赠送的上海书展的门票,还在犹豫是否决定真的践行,问了小墨,他决定要去,那母子俩就冒着闷热的天气去上海冒充...
    一玄子阅读 183评论 0 0
  • 姓名:王成茗 日精进打卡第26天 【打卡始于2017.10.12持续于2017.11.6】 【知~学习】 ...
    王成茗阅读 19评论 0 0