温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何使用Spring扩展点

发布时间:2021-10-14 11:45:21 来源:亿速云 阅读:138 作者:iii 栏目:开发技术

这篇文章主要讲解了“如何使用Spring扩展点”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何使用Spring扩展点”吧!

Spring常见扩展点

「BeanFactoryPostProcessor#postProcessBeanFactory」

有时候整个项目工程中bean的数量有上百个,而大部分单测依赖都是整个工程的xml,导致单测执行时需要很长时间(大部分时间耗费在xml中数百个单例非懒加载的bean的实例化及初始化过程)

解决方法:利用Spring提供的扩展点将xml中的bean设置为懒加载模式,省去了Bean的实例化与初始化时间

public class LazyBeanFactoryProcessor implements BeanFactoryPostProcessor {     @Override     public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {         DefaultListableBeanFactory fac = (DefaultListableBeanFactory) beanFactory;         Map<String, AbstractBeanDefinition> map = (Map<String, AbstractBeanDefinition>) ReflectionTestUtils.getField(fac, "beanDefinitionMap");         for (Map.Entry<String, AbstractBeanDefinition> entry : map.entrySet()) {             //设置为懒加载             entry.getValue().setLazyInit(true);         }     } }

「InstantiationAwareBeanPostProcessor#postProcessPropertyValues」

非常规的配置项比如

<context:component-scan base-package="com.zhou" />

Spring提供了与之对应的特殊解析器

正是通过这些特殊的解析器才使得对应的配置项能够生效

而针对这个特殊配置的解析器为 ComponentScanBeanDefinitionParser

在这个解析器的解析方法中,注册了很多特殊的Bean

public BeanDefinition parse(Element element, ParserContext parserContext) {   //...   registerComponents(parserContext.getReaderContext(), beanDefinitions, element);     //...   return null; }
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(    BeanDefinitionRegistry registry, Object source) {    Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);   //...     //@Autowire   if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {    RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);    def.setSource(source);    beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));   }    // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.    //@Resource   if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {       //特殊的Bean    RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);    def.setSource(source);    beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));   }   //...   return beanDefs;  }

以@Resource为例,看看这个特殊的bean做了什么

public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor   implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {             public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds,        Object bean, String beanName) throws BeansException {           InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass());           try {             //属性注入             metadata.inject(bean, beanName, pvs);           }           catch (Throwable ex) {             throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);           }           return pvs;     }      }

我们看到在postProcessPropertyValues方法中,进行了属性注入

「invokeAware」

实现BeanFactoryAware接口的类,会由容器执行setBeanFactory方法将当前的容器BeanFactory注入到类中

@Bean class BeanFactoryHolder implements BeanFactoryAware{         private static BeanFactory beanFactory;          public void setBeanFactory(BeanFactory beanFactory) throws BeansException {         this.beanFactory = beanFactory;     } }

「BeanPostProcessor#postProcessBeforeInitialization」

实现ApplicationContextAware接口的类,会由容器执行setApplicationContext方法将当前的容器applicationContext注入到类中

@Bean class ApplicationContextAwareProcessor implements BeanPostProcessor {      private final ConfigurableApplicationContext applicationContext;      public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {       this.applicationContext = applicationContext;     }      @Override     public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {       //...       invokeAwareInterfaces(bean);       return bean;     }      private void invokeAwareInterfaces(Object bean) {         if (bean instanceof ApplicationContextAware) {           ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);         }     } }

我们看到是在BeanPostProcessor的postProcessBeforeInitialization中进行了setApplicationContext方法的调用

class ApplicationContextHolder implements ApplicationContextAware{         private static ApplicationContext applicationContext;          public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {         this.applicationContext = applicationContext;     } }

「afterPropertySet()和init-method」

目前很多Java中间件都是基本Spring  Framework搭建的,而这些中间件经常把入口放到afterPropertySet或者自定义的init中

「BeanPostProcessor#postProcessAfterInitialization」

熟悉aop的同学应该知道,aop底层是通过动态代理实现的

当配置了时候,默认开启aop功能,相应地调用方需要被aop织入的对象也需要替换为动态代理对象

不知道大家有没有思考过动态代理是如何「在调用方无感知情况下替换原始对象」的?

根据上文的讲解,我们知道:

<aop:aspectj-autoproxy/>

Spring也提供了特殊的解析器,和其他的解析器类似,在核心的parse方法中注册了特殊的bean

这里是一个BeanPostProcessor类型的bean

class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {  @Override  public BeanDefinition parse(Element element, ParserContext parserContext) {     //注册特殊的bean   AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);   extendBeanDefinition(element, parserContext);   return null;     } }

将于当前bean对应的动态代理对象返回即可,该过程对调用方全部透明

public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {   public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {         if (bean != null) {           Object cacheKey = getCacheKey(bean.getClass(), beanName);           if (!this.earlyProxyReferences.containsKey(cacheKey)) {             //如果该类需要被代理,返回动态代理对象;反之,返回原对象             return wrapIfNecessary(bean, beanName, cacheKey);           }         }         return bean;  } }

正是利用Spring的这个扩展点实现了动态代理对象的替换

「destroy()和destroy-method」

bean生命周期的最后一个扩展点,该方法用于执行一些bean销毁前的准备工作,比如将当前bean持有的一些资源释放掉

感谢各位的阅读,以上就是“如何使用Spring扩展点”的内容了,经过本文的学习后,相信大家对如何使用Spring扩展点这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI