2

本周解决的一些问题

 2 years ago
source link: https://segmentfault.com/a/1190000041473402
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

问题1 @Autowired 注入失败

image.png

@Autowired
    private DingService dingService;

在项目中service是用 @Autowired依赖注入,用debug测试的时候看到service确实为null。

一开始想法:想用new的形式手动生成一个service,但是在查找资料之后发现这种方式是有弊端的,于是不采用。

DingServiceImpl dingService1 = new DingServiceImpl();

弊端:在spring中如果使用new创建一个对象时,这个对象将不在受spring管理器管理,这样的话就绕过了容器的依赖注入过程,也可能出现获取不到应有的属性这种情况。
说明:Spring是一个bean的容器,由容器负责对象的初始化和依赖注入。当我们想要从中获取一个Bean的实例时,就从Spring容器中获取。


最后查找资料之后发现原因:
@EntityListeners(LogListener.class)
这里是在Listener中使用了@Autowired,导致的注入失败。

在应用的Filter或Listener中使用了@Autowired ,注入为空web容器启动是按照一定顺序的,即:Listener --> Filter -->Servlet。
因为Filter和Listener加载顺序优先于spring容器初始化实例,所以会出现null。Spring的入口就在Servlet里。可以用ApplicationContext根据bean名称(注意名称为实现类而不是接口)去获取bean。

之前学长就采用的这种方法:ApplicationContext去获取bean。
传送门:https://segmentfault.com/a/11...

这种方法需要新建文件,自定义实现ApplicationContextAware。

对于Listener来说,我找到了一种更方便一点的方法,不需要新建文件来实现类。

@Component
public class LogListener implements ServletContextListener {

    @Autowired
    private DingService dingService;
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        WebApplicationContextUtils.getRequiredWebApplicationContext(sce.getServletContext())
                .getAutowireCapableBeanFactory().autowireBean(this);
    }

只要继承ServletContextListener,并在在监听类的contextInitialized的方法中加上如上代码即可。
原理是一样的,都是从ApplicationContext中获取bean.

总结一下@Autowired为null的几种情况:
1.在应用的Filter或Listener中使用了@Autowired
2.组件上面没有加入了合适的注解。例如:@Service, @Component等,Bean没有交付给Spring容器。
3.把@Autowired注解加在了一个静态属性上,注入为空
4.检查@Autowired注入类使用的方法是否为private,如果为private的话在生成动态代理的话@Autowired注入的依赖将为空。
5.检查本文件中是不是new了一个对象,这样的话就绕过了容器的依赖注入过程,也可能出现获取不到应有的属性这种情况。

目前对于ApplicationContext和Servlet这些还不太熟悉,待有了解之后再来补充。长路漫漫。

2.定时器误差

目前项目是2分钟发送一次定时任务,并且会判断当前发送任务是否与上次间隔2分钟,如果是则发送,这导致了本次的定时任务没有发送,可能发生一些错误。经过老师的说明和谷歌的搜索,才了解这种误差。一般会有1到2毫秒的延迟,写代码的时候需要考虑进去这种误差。
image.png

3.双线程导致的问题

image.png

解决:在保存前对数据库重新获取最后交互时间字段

环境也是一方面的问题:
lQLPDhsxKMSoYqN-zQFZsMJ_EXYu4_MvAiE3OV_AvwA_345_126.png
今天突然docker的mysql用不了了,之后弄了很久,重新初始化了数据库,直接在控制台跑的mysql,然后就不用docker了。

本周的主要感受就是修bug有时候很不容易,特别是别人写的代码。很多时候费时间的不是修bug的时间,而是找bug发生在哪里的问题。跑了很久的前后台,打了很多断点到控制台,才发现哪里有问题。不过这也是一种锻炼,加强了我的测试能力和阅读代码的能力。

目前解决了@Autowired的问题后,rizhi系统目前暂时没有问题。很多时间自己测试的时候没有问题,直到集成测试的时候才暴露问题,还是测试不够充分。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK