【如何在静态方法/main方法中调用Controller】 @PostConstruct注解使用

如何在静态方法/main方法中调用Controller

前言

根据功能需求,一般Controller层是用来处理外部请求的,最常见的就是@RequestMapping("../..")这样的书写,但是有时会遇到不通过外部,而由自己手动发起去调用这个控制层去发起某个操作,就是在main方法中调用调用 Controller。

静态方法的问题

main方法在一个类中属于一个静态方法,所以不难想到,要在这个main方法里使用Controller,就必须将这个Controller也声明为静态的,

@SpringBootApplication
@MapperScan("com.test.mapper")
public class DemoApplication {
    @Autowired
    private static MyController myController;
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
        myController.test();
    }

这样看上去似乎没有任何问题,我一开始也是这么想的,但是运行之后,就会出现空指针异常!

即使加了 static ,此时自动装配的myController仍然是空的,即使在这一步手动new一个Controller出来,但在接下来的Controller调用Service的时仍然会有Service层的空指针异常,这层让我一度怀疑,是不是不能在main方法中调用Controller??!

空指针原因分析

我们再仔细的看看刚刚空指针异常给出的日志

静态字段不支持自动注入!!

@PostConstruct注解

从Java EE5规范开始,Servlet增加了两个影响Servlet声明周期的注解,@PostConstruct和@PreDestory,用来修饰一个非静态的void方法。先看一下这个注解在一个类中与构造器和@Autowired的执行顺序:

Constructor > @Autowired > @PosConstruct

下面这一段是根据源码里的注释的,翻译软件翻译而来 多少少少能消化一点

 PostConstruct注解用于需要执行的方法完成依赖注入后执行任何初始化。这个方法必须在类投入使用之前调用。这个支持依赖项的所有类都必须支持注解注入。用PostConstruct注解的方法必须调用 如果类没有要求注入任何资源。只有一个方法可以使用此注解。

应用PostConstruct注释必须满足以下所有要求标准:
1.该方法不得有任何参数,除非是拦截器,在这种情况下,它采用InvocationContext对象由拦截器规范定义。
2.在拦截器类上定义的方法必须有一个
 void< METHOD>(InvocationContext)
 Object< METHOD>(InvocationContext)抛出异常
3.注意:PostConstruct拦截器方法不能抛出应用程序异常,但可能会声明抛出已检查的异常,包括 java.lang.Exception,如果相同的拦截器方法插入生命周期事件之外的业务或超时方法。如果一个PostConstruct拦截器方法返回一个值,它被忽略容器。
4.在非拦截器类上定义的方法必须具有签名后: void< METHOD>()
5.应用PostConstruct的方法可以是公共的,受保护的,包私人或私人。
6.除应用程序客户端外,方法不得为静态。
7.方法可能是最终的。
8.如果方法抛出未经检查的异常,则不得放入类服务,除了EJB可以处理异常的EJB的情况甚至从他们那里恢复过来。

被@PostConstruct注解的方法,会在依赖自动注入后执行! 

解决方案

有了上面的一些知识跟错误原因后,既然静态字段不支持自动装配,那么如何解决呢?理一下思路:想在静态的main方法里使用,肯定controller也要被static修饰为静态的,而此时又需要controller自动装配,那就声明两个controller,一个静态的供调用,一个普通的自动装配并将这个赋给静态的controller! 回想一下上面提到的,@PostConstruct修饰的方法会在自动装配后调用。

代码

    @Autowired
    private MyController myController2; //自动装配的controller
    private static MyController myController ; //供静态main方法调用的controller
    @PostConstruct
    public void init() {
        myController= myController2; //完成赋予操作
    }

此时,在main方法里对myController就能正常使用了,后续Controller调用Service层也是正常的,如果想在main函数中直接调用Service层也是差不多的做法。

结语

仅仅是一个小问题,看起来也就多加了5行的代码,但去发掘这个原因,理解这个原因,看明白这个解决方案花了我整整一早上的时间,但这都是小事!最可怕的是,知道哪里报错,却不知道错在哪!因为根本知道搜索什么,方向不知道,或许是搜“SpringBoot如何手动控制发起某个Controller”,“main方法如何调用Controller”,“main方法调用Controller空指针异常”,“自动装配报了空指针”······等等一系列问题,然而现实告诉我这些都搜不到解决方案,!所以遇到问题,正确的搜索姿势才能解决。

仔细分析一下在这次调用自动装配有以往使用什么不同就能找到搜索姿势了,首先是在一个静态main方法里,其次就是这个自动装配的字段使用了static静态修饰。

 附一下在静态方法中调用service代码的链接 https://blog.csdn.net/qq_20552525/article/details/88863430

【本文属个人理解与看法,如有错误或不同看法,烦请指教】 2019-08-08 TheJam

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页