【问题标题】:Init method in Spring Controller (annotation version)Spring Controller中的init方法(注解版)
【发布时间】:2011-07-22 03:20:52
【问题描述】:

我正在将控制器转换为较新的注释版本。在旧版本中,我曾经在 springmvc-servlet.xml 中指定 init 方法,使用:

<beans>
    <bean id="myBean" class="..." init-method="init"/>
</beans>

如何使用注解版本指定init方法?

【问题讨论】:

标签: java spring annotations controller


【解决方案1】:

你可以使用

@PostConstruct
public void init() {
   // ...
}

【讨论】:

  • 你说得对,它的“Common Annotations 1.0”,Java1.7 也可以。
  • 如果你需要使用来自SecurityContextHolder的User,在PostConstruct时刻它没有被初始化。它需要像无状态方法一样使用。 (getUser()... { return Security...user(); }
  • 公共或私人
【解决方案2】:

或者,您可以让您的类实现InitializingBean 接口以提供回调函数 (afterPropertiesSet()),ApplicationContext 将在构造 bean 时调用该函数。

【讨论】:

    【解决方案3】:

    在Spring中有几种方法可以拦截初始化过程。如果您必须初始化所有 bean 并自动装配/注入它们,我知道至少有两种方法可以确保这一点。我只有第二个testet,但我相信两者的工作方式相同。

    如果你使用@Bean,你可以通过initMethod引用,像这样。

    @Configuration
    public class BeanConfiguration {
    
      @Bean(initMethod="init")
      public BeanA beanA() {
        return new BeanA();
      }
    }
    
    public class BeanA {
    
      // method to be initialized after context is ready
      public void init() {
      }
    
    } 
    

    如果您使用@Component,您可以像这样使用@EventListener 进行注释。

    @Component
    public class BeanB {
    
      @EventListener
      public void onApplicationEvent(ContextRefreshedEvent event) {
      }
    }
    

    就我而言,我有一个遗留系统,我现在正在使用 IoC/DI,其中 Spring Boot 是选择的框架。旧系统给表带来了许多循环依赖,因此我必须大量使用 setter-dependency。这让我有些头疼,因为我无法信任 @PostConstruct,因为 setter 的自动装配/注入尚未完成。顺序是构造函数,@PostConstruct 然后是自动装配的设置器。我使用 @EventListener 注释解决了它,该注释将在所有 bean 的“同一”时间最后运行。该示例还显示了 InitializingBean 的实现。

    我有两个相互依赖的类(@Component)。就本示例而言,这些类看起来相同,仅显示其中一个。

    @Component
    public class BeanA implements InitializingBean {
      private BeanB beanB;
    
      public BeanA() {
        log.debug("Created...");
      }
    
      @PostConstruct
      private void postConstruct() {
        log.debug("@PostConstruct");
      }
    
      @Autowired
      public void setBeanB(BeanB beanB) {
        log.debug("@Autowired beanB");
        this.beanB = beanB;
      }
    
      @Override
      public void afterPropertiesSet() throws Exception {
        log.debug("afterPropertiesSet()");
      }
    
      @EventListener
      public void onApplicationEvent(ContextRefreshedEvent event) {
        log.debug("@EventListener");
      } 
    }
    

    这是显示容器启动时调用顺序的日志输出。

    2018-11-30 18:29:30.504 DEBUG 3624 --- [           main] com.example.demo.BeanA                   : Created...
    2018-11-30 18:29:30.509 DEBUG 3624 --- [           main] com.example.demo.BeanB                   : Created...
    2018-11-30 18:29:30.517 DEBUG 3624 --- [           main] com.example.demo.BeanB                   : @Autowired beanA
    2018-11-30 18:29:30.518 DEBUG 3624 --- [           main] com.example.demo.BeanB                   : @PostConstruct
    2018-11-30 18:29:30.518 DEBUG 3624 --- [           main] com.example.demo.BeanB                   : afterPropertiesSet()
    2018-11-30 18:29:30.518 DEBUG 3624 --- [           main] com.example.demo.BeanA                   : @Autowired beanB
    2018-11-30 18:29:30.518 DEBUG 3624 --- [           main] com.example.demo.BeanA                   : @PostConstruct
    2018-11-30 18:29:30.518 DEBUG 3624 --- [           main] com.example.demo.BeanA                   : afterPropertiesSet()
    2018-11-30 18:29:30.607 DEBUG 3624 --- [           main] com.example.demo.BeanA                   : @EventListener
    2018-11-30 18:29:30.607 DEBUG 3624 --- [           main] com.example.demo.BeanB                   : @EventListener
    

    如您所见,@EventListener 在一切准备就绪并配置完毕后最后运行。

    【讨论】:

      【解决方案4】:

      @PostConstruct、实现InitializingBean、指定init-method它们有调用命令。所以你不能用它们来替换init-method。你可以试试这个:

      @Bean(initMethod = "init")
      public MyBean mybean() {
          return new MyBean();
      }
      
      
      
      class MyBean {
      public void init() {
          System.out.println("MyBean init");
      }
      

      }

      在你的类中,你可以声明一个名为 init() 的方法。

      参考: https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#:~:text=Multiple%20lifecycle%20mechanisms%20configured%20for%20the%20same%20bean%2C%20with%20different%20initialization%20methods%2C%20are%20called%20as%20follows%3A

      【讨论】:

        【解决方案5】:
        public class InitHelloWorld implements BeanPostProcessor {
        
           public Object postProcessBeforeInitialization(Object bean,
                     String beanName) throws BeansException {
               System.out.println("BeforeInitialization : " + beanName);
               return bean;  // you can return any other object as well
           }
        
           public Object postProcessAfterInitialization(Object bean,
                     String beanName) throws BeansException {
               System.out.println("AfterInitialization : " + beanName);
               return bean;  // you can return any other object as well
           }
        
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-10-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-12
          • 1970-01-01
          • 2013-06-13
          相关资源
          最近更新 更多