前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot整合自定义注解

SpringBoot整合自定义注解

作者头像
写一点笔记
发布2020-08-25 14:31:01
8380
发布2020-08-25 14:31:01
举报
文章被收录于专栏:程序员备忘录程序员备忘录

之前我们学习了java的自定义注解,而且我们可以非常方便的进行注解值到实体真实值得转变。那么我们如何将这些标记值设置到spring容器中?那么我们就需要了解一些spring的知识。我们知道spring提供了很多扩展的接口。这其中有一个BeanPostProcessor的接口。

话不多说,直接上代码

代码语言:javascript
复制
public class MyBeanPostProcessor implements BeanPostProcessor {
    //在bean实例化之后调用
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }
    //在bean实例化之后调用
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)  {
     try {
            parseAnnotation(bean);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return bean;
    }
      //在bean实例化之后进行参数赋值,处理完毕之后,spring容器中的bean就是注解中的值了。
    public void parseAnnotation(Object bean) throws IllegalAccessException {
        //获取公有和私有的属性
        Field[] fields = bean.getClass().getDeclaredFields();
        for (int i=0;i<fields.length;i++){
            //抑制对private的检测
            fields[i].setAccessible(true);
            Object value=fields[i].get(bean);
            MyField myField=fields[i].getAnnotation(MyField.class);
            //如果默认传入的是空的
            if (null!=myField&& StringUtils.isEmpty(value)){
                fields[i].set(bean,myField.myName());
            }
        }
    }
}
代码语言:javascript
复制
@SpringBootApplication
public class tet implements ApplicationContextAware {

    @Bean(initMethod = "initSon")
    public Son son(){
        return new Son();
    }
    
    //不能采用其他注解修饰拥有BeanPostProcessor接口,只能用@Bean。
    @Bean
    public MyBeanPostProcessor getMybean(){
        return new MyBeanPostProcessor();
    }

    private static Son son;

    private static ApplicationContext context;
    
    public static void main(String[] args) {
        SpringApplication.run(tet.class, args);
        son= context.getBean(Son.class);
        System.out.println("新的:"+son.toString());
    }
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context=applicationContext;
    }
}

我们看到我们已经拿到注解的值并修改了spring容器中bean的值了。同样的道理,我们也可以通过bean来遍历方法,然后拿到方法上的注解属性。但是使用方法上的注解的时候都是AOP来兼容代码。也就是说在切面里接受注解上边的属性。这个咋后期再研讨。现在咋没爬一爬代码,看看刚才的BeanPostProcessor是如何调用的。

首先我们看到BeanPostProcessor的两个接口。前置和后置的处理器。通过上边的例子,我们知道如果我们什么多不做,那么return bean就应该注册到Spring的容器中了。

代码语言:javascript
复制
public interface BeanPostProcessor {
    //在bean实例化之后调用
  default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }
    //在bean实例化之后调用
  default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }
}

通过代码跟踪,在initalizeBean中

代码语言:javascript
复制
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
        //执行aware接口
        invokeAwareMethods(beanName, bean);
        return null;
      }, getAccessControlContext());
    }
    else {
    //aware接口
      invokeAwareMethods(beanName, bean);
    }
    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
      //beanPostProcessors的前置接口
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }
    try {
    //intit接口
      invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
      throw new BeanCreationException(
          (mbd != null ? mbd.getResourceDescription() : null),
          beanName, "Invocation of init method failed", ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
     //beanPostProcessors的前置接口
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
  }

可以看出方法执行的顺序为

代码语言:javascript
复制
invokeAwareMethods->
applyBeanPostProcessorsBeforeInitialization->
invokeInitMethods->
applyBeanPostProcessorsAfterInitialization

调用的aware接口方法

代码语言:javascript
复制
private void invokeAwareMethods(final String beanName, final Object bean) {
    if (bean instanceof Aware) {
      if (bean instanceof BeanNameAware) {
        ((BeanNameAware) bean).setBeanName(beanName);
      }
      if (bean instanceof BeanClassLoaderAware) {
        ClassLoader bcl = getBeanClassLoader();
        if (bcl != null) {
          ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
        }
      }
      if (bean instanceof BeanFactoryAware) {
        ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
      }
    }
  }

调用的BeanPostProcessors接口方法

代码语言:javascript
复制
@Override
  public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
      throws BeansException {


    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
      Object current = processor.postProcessBeforeInitialization(result, beanName);
      if (current == null) {
        return result;
      }
      result = current;
    }
    return result;
  }


  @Override
  public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
      throws BeansException {


    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
      Object current = processor.postProcessAfterInitialization(result, beanName);
      if (current == null) {
        return result;
      }
      result = current;
    }
    return result;
  }

调用的InitializingBean接口方法

代码语言:javascript
复制
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
      throws Throwable {


    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
      if (logger.isTraceEnabled()) {
        logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
      }
      if (System.getSecurityManager() != null) {
        try {
          AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
            ((InitializingBean) bean).afterPropertiesSet();
            return null;
          }, getAccessControlContext());
        }
        catch (PrivilegedActionException pae) {
          throw pae.getException();
        }
      }
      else {
        ((InitializingBean) bean).afterPropertiesSet();
      }
    }

所以接口的执行顺序为aware->beanpostprocess->InitializingBean->beanpostprocess

而我们的getBeanPostProcessors()就是用来获取所有实现了beanpostprocessors接口的类。那么这些类是如何放到beanfactory里的呐?

我们返爬一下代码,在beanfactory中。发现

代码语言:javascript
复制


    @Override
  public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
    Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
    // Remove from old position, if any
    this.beanPostProcessors.remove(beanPostProcessor);
    // Track whether it is instantiation/destruction aware
    if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
      this.hasInstantiationAwareBeanPostProcessors = true;
    }
    if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
      this.hasDestructionAwareBeanPostProcessors = true;
    }
    // Add to end of list
    this.beanPostProcessors.add(beanPostProcessor);
  }
    @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
{
    int factoryId = System.identityHashCode(beanFactory);
    if (this.factoriesPostProcessed.contains(factoryId)) {
      throw new IllegalStateException(
          "postProcessBeanFactory already called on this post-processor against " + beanFactory);
    }
    this.factoriesPostProcessed.add(factoryId);
    if (!this.registriesPostProcessed.contains(factoryId)) {
      // BeanDefinitionRegistryPostProcessor hook apparently not supported...
      // Simply call processConfigurationClasses lazily at this point then.
      processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
    }
    enhanceConfigurationClasses(beanFactory);
    beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
  }

我们继续向调用者跟踪,发现了核心代码。就这这个registerBeanPostProcessors方法中。

代码语言:javascript
复制
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
        //通过beanfactory获取实现了beanPostProcessor接口的类的名称。
    String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
    //实现了beanPostProcessor接口的类数量
    int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
    //做了
    beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
    //具有优先级的
    List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();


    //实现ordered接口的
    List<String> orderedPostProcessorNames = new ArrayList<>();
    //一般的
    List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    for (String ppName : postProcessorNames) {
      if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
        //优先级接口
        BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
        priorityOrderedPostProcessors.add(pp);
        if (pp instanceof MergedBeanDefinitionPostProcessor) {
          internalPostProcessors.add(pp);
        }
      }
      else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
        //如实现Orderd接口
        orderedPostProcessorNames.add(ppName);
      }
      else {
        nonOrderedPostProcessorNames.add(ppName);
      }
    }
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    //注册优先级的beanpostprocessors
    registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
    List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
    for (String ppName : orderedPostProcessorNames) {
      //进行实例化
      BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
      orderedPostProcessors.add(pp);
      if (pp instanceof MergedBeanDefinitionPostProcessor) {
        internalPostProcessors.add(pp);
      }
    }
    sortPostProcessors(orderedPostProcessors, beanFactory);
    //注册ordered的beanpostprocessors
    registerBeanPostProcessors(beanFactory, orderedPostProcessors);
        //一般的beanpostprocessors
    List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
    for (String ppName : nonOrderedPostProcessorNames) {
      BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
      nonOrderedPostProcessors.add(pp);
      if (pp instanceof MergedBeanDefinitionPostProcessor) {
        internalPostProcessors.add(pp);
      }
    }
    //注册一般的beanpostprocessors
    registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
    //排序
    sortPostProcessors(internalPostProcessors, beanFactory);
    registerBeanPostProcessors(beanFactory, internalPostProcessors);
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
  }

这里的getbean就是spring的实例化bean的过程。也就是registerBeanPostProcessors方法之后,实现BeanPostProcessors接口的类都已经实例化好了。

我们再向前走一步。

而其中的onRefresh方法是spring留给子类进行bean的初始化的。而且该方法也添加了synchronized锁,而beanPostProcessors类在其他bean初始化之前已经初始化了。所以根据上边的解释。bean初始化结束之后肯定会调用postProcessAfterInitialization,而不存在beanPostProcessors类还没有初始化的问题,就被其他类调用的问题。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-08-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员备忘录 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档