20190514面试SPRING扩展机制

1.SPRING扩展机制

  • 通过基于XML和基于Java的配置扩展,可以使用户通过Spring使用我们研发的组件,提供很好的易用性。
  • 通过Spring容器最常用的两个扩展点:BeanFactoryPostProcessorBeanPostProcessor,可以使我们的程序逻辑和Spring容器紧密合作,无缝插入到用户bean的生命周期中,发挥更强大的作用。

2.spring的扩展接口

  • 1. FactroyBean 我们熟悉的AOP基础bean 
  • 2. BeanPostProcess 在每个bena初始化成前后做操作。 
  • 3. InstantiationAwareBeanPostProcessor 在Bean实例化前后做一些操作。 
  • 4. BeanNameAware、ApplicationContextAware 和 BeanFactoryAware 针对bean工厂,可以获取上下文,可以获取当前bena的id。 
  • 5. BeanFactoryPostProcessor Spring允许在Bean创建之前,读取Bean的元属性,并根据自己的需求对元属性进行改变,比如将Bean的scope从singleton改变为prototype。 
  • 6. InitialingBean 在属性设置完毕后做一些自定义操作 DisposableBean 在关闭容器前做一些操作。
     

相关知识

一扩展方式

1。基于XML配置的扩展

1.首先需要定义一套XML Schema来描述组件所提供的功能。schema中就需要描述我们期望用户提供的namespace以及namespace之间的排序等元数据。

2.除了XML Schema,我们还需要创建一个自定义的NamespaceHandler来负责解析用户在XML中的配置。

  • 为了简化代码,我们一般会继承一个helper类:NamespaceHandlerSupport,然后在init方法中注册处理我们自定义节点的BeanDefinitionParser
  • 自定义的BeanDefinitionParser负责解析xml中的config节点信息,记录用户的配置信息,为后面和Spring整合做好铺垫。

3.注册Spring handler和Spring schema,让Spring解析xml配置文件的过程中识别我们的自定义节点,并且转交到我们的NamespaceHandler处理。

  • 1)首先需要在META-INF目录下创建一个spring.handlers文件,来配置我们自定义的XML Schema Namespace到我们自定义的NamespaceHandler映射关系。
  • 2)在META-INF目录下创建一个spring.schemas,来配置我们自定义的XML Schema地址到实际Jar包中的classpath映射关系(避免Spring真的去服务器上下载不存在的文件)

2.基于Java配置的扩展

从Spring 3.0开始,一种新的基于Java的配置方式出现了。

通过这种方式,我们在开发Spring项目的过程中再也不需要去配置繁琐的xml文件了,只需要在Configuration类中配置就可以了,大大的简化了Spring的使用。

另外,这也是Spring Boot默认的配置方式,所以建议也支持这一特性。

2.1 @Import注解

支持Java配置扩展的关键点就是@Import注解,Spring 3.0提供了这个注解用来支持在Configuration类中引入其它的配置类,包括Configuration类, ImportSelector和ImportBeanDefinitionRegistrar的实现类。

我们可以通过这个注解来引入自定义的扩展Bean。

2.2 自定义注解

和基于XML配置类似的,我们需要提供给用户一个注解来配置需要注入到Spring Property Sources的namespaces和order。

2.3 自定义ImportBeanDefinitionRegistrar实现

ImportBeanDefinitionRegistrar接口定义了registerBeanDefinitions方法,从而允许我们向Spring注册必要的Bean。

  1. 记录用户配置的参数
  2. 向Spring注册Bean:PropertySourcesProcessor,这个bean后面会实际处理用户配置的参数,从而完成配置注入到Spring中的功能

三扩展点

Spring容器最常用的两个扩展点:BeanFactoryPostProcessorBeanPostProcessor

3.1 BeanFactoryPostProcessor

BeanFactoryPostProcessor提供了一个方法:postProcessBeanFactory

这个方法会被Spring在容器初始化过程中调用,调用时机是所有bean的定义信息都已经初始化好,但是这些bean还没有实例化。

实现该接口,可以在spring的bean创建之前,修改bean的定义属性。也就是说,Spring允许BeanFactoryPostProcessor在容器实例化任何其它bean之前读取配置元数据,并可以根据需要进行修改,例如可以把bean的scope从singleton改为prototype,也可以把property的值给修改掉。可以同时配置多个BeanFactoryPostProcessor,并通过设置'order'属性来控制各个BeanFactoryPostProcessor的执行次序。
注意:BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的。接口方法的入参是ConfigurrableListableBeanFactory,使用该参数,可以获取到相关bean的定义信息,



	
	
		
		
	
	
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
 
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("调用MyBeanFactoryPostProcessor的postProcessBeanFactory");
        BeanDefinition bd = beanFactory.getBeanDefinition("myJavaBean");
        System.out.println("属性值============" + bd.getPropertyValues().toString());
        MutablePropertyValues pv =  bd.getPropertyValues();  
        if (pv.contains("remark")) {  
            pv.addPropertyValue("remark", "把备注信息修改一下");  
        }  
        bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
    }
 
}

实际应用:

20190514面试SPRING扩展机制_第1张图片

20190514面试SPRING扩展机制_第2张图片

3.2 BeanPostProcessor

BeanPostProcessor提供了两个方法:postProcessBeforeInitializationpostProcessAfterInitialization,主要针对bean初始化提供扩展。

  • postProcessBeforeInitialization会在每一个bean实例化之后、初始化(如afterPropertiesSet方法)之前被调用。
  • postProcessAfterInitialization则在每一个bean初始化之后被调用。

我们常用的@Autowired注解就是通过postProcessBeforeInitialization实现的(AutowiredAnnotationBeanPostProcessor)。

BeanFactoryPostProcessor在bean实例化之前执行,之后实例化bean(调用构造函数,并调用set方法注入属性值),然后在调用两个初始化方法前后,执行了BeanPostProcessor。初始化方法的执行顺序是,先执行afterPropertiesSet,再执行init-method。如下



	
	
		
		
	
	
	
	
public class MyJavaBean implements InitializingBean {
    private String desc;
    private String remark;
    
    public MyJavaBean() {
        System.out.println("MyJavaBean的构造函数被执行啦");
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        System.out.println("调用setDesc方法");
        this.desc = desc;
    }
    public String getRemark() {
        return remark;
    }
    public void setRemark(String remark) {
        System.out.println("调用setRemark方法");
        this.remark = remark;
    }
    public void afterPropertiesSet() throws Exception {
        System.out.println("调用afterPropertiesSet方法");
        this.desc = "在初始化方法中修改之后的描述信息";
    }
    public void initMethod() {
        System.out.println("调用initMethod方法");
    }
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("[描述:").append(desc);
        builder.append(", 备注:").append(remark).append("]");
        return builder.toString();
    }
}
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
 
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("调用MyBeanFactoryPostProcessor的postProcessBeanFactory");
        BeanDefinition bd = beanFactory.getBeanDefinition("myJavaBean");
        MutablePropertyValues pv =  bd.getPropertyValues();  
        if (pv.contains("remark")) {  
            pv.addPropertyValue("remark", "在BeanFactoryPostProcessor中修改之后的备忘信息");  
        }  
    }
 
}
public class MyBeanPostProcessor implements BeanPostProcessor {
 
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor,对象" + beanName + "调用初始化方法之前的数据: " + bean.toString());
        return bean;
    }
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor,对象" + beanName + "调用初始化方法之后的数据:" + bean.toString());
        return bean;
    }
}

20190514面试SPRING扩展机制_第3张图片

BeanPostProcessor的执行,取决于配置文件中bean的定义,如果定义的bean是singleton并且不是抽象类,也不延迟初始化,则BeanPostProcessor是在第11步中执行;而对于prototype的bean,BeanPostProcessor是在程序getBean的时候执行的。在第6步中,调用registerBeanPostProcessors方法,注册所有实现BeanPostProcessor接口的bean
 

参考

https://juejin.im/post/5ba45a94f265da0aa94a0d71

https://nobodyiam.com/2017/02/26/several-ways-to-extend-spring/

https://blog.csdn.net/qq_38182963/article/details/78795058

https://blog.csdn.net/caihaijiang/article/details/35552859

 

你可能感兴趣的:(曼哈顿计划)