GVKun编程网logo

在测试过程中注入@Autowired私有字段(在测试sql注入时,哪种方式不可取)

15

在本文中,您将会了解到关于在测试过程中注入@Autowired私有字段的新资讯,同时我们还将为您解释在测试sql注入时,哪种方式不可取的相关在本文中,我们将带你探索在测试过程中注入@Autowired

在本文中,您将会了解到关于在测试过程中注入@Autowired私有字段的新资讯,同时我们还将为您解释在测试sql注入时,哪种方式不可取的相关在本文中,我们将带你探索在测试过程中注入@Autowired私有字段的奥秘,分析在测试sql注入时,哪种方式不可取的特点,并给出一些关于@Autowired 注入为 null 问题分析、@Autowired 注入在接口的实现类上 报错、@Autowired 注入失败等问题、@Autowired 还可以注入 List 和 Map的实用技巧。

本文目录一览:

在测试过程中注入@Autowired私有字段(在测试sql注入时,哪种方式不可取)

在测试过程中注入@Autowired私有字段(在测试sql注入时,哪种方式不可取)

我有一个组件安装程序,它实际上是一个应用程序的启动器。它的配置如下:

@Componentpublic class MyLauncher {    @Autowired    MyService myService;    //other methods}

MyService带有@ServiceSpring注释,并自动连接到我的启动器类中,没有任何问题。

我想为MyLauncher编写一些jUnit测试用例,为此,我启动了一个这样的类:

public class MyLauncherTest    private MyLauncher myLauncher = new MyLauncher();    @Test    public void someTest() {    }}

我可以为MyService创建一个Mock对象,然后将其注入测试类中的myLauncher吗?由于Spring正在处理自动装配,因此我目前在myLauncher中没有吸气剂或吸气剂。如果可能的话,我不想添加getter和setter。我可以告诉测试用例使用@Beforeinit方法将模拟对象注入自动接线的变量中吗?

如果我要彻底解决这个问题,请随意说。我还是这个新手。我的主要目标是只具有一些Java代码或注释,即可将模拟对象放入该@Autowired变量中,而无需编写setter方法或使用applicationContext-test.xml文件。我宁愿在.java文件中维护测试用例的所有内容,而不必只为测试维护单独的应用程序内容。

我希望将 Mockito
用于模拟对象。过去,我是通过使用org.mockito.Mockito和创建对象来完成此操作的Mockito.mock(MyClass.class)

答案1

小编典典

您可以在测试中绝对在MyLauncher上注入模拟。我敢肯定,如果您显示您正在使用的模拟框架,将会很快提供答案。使用mockito,我会考虑使用@RunWith(MockitoJUnitRunner.class)并为myLauncher使用注释。它看起来像下面的样子。

@RunWith(MockitoJUnitRunner.class)public class MyLauncherTest    @InjectMocks    private MyLauncher myLauncher = new MyLauncher();    @Mock    private MyService myService;    @Test    public void someTest() {    }}

@Autowired 注入为 null 问题分析

@Autowired 注入为 null 问题分析

题说明

最近看到 Spring 事务,在学习过程中遇到一个很苦恼问题                                                  

搭建好 Spring 的启动环境后出现了一点小问题

在启动时候却出现 [java.lang.NullPointerException]

不过因为当时一个小小的疏忽 很 low 的问题 请往下看 ... 

工程结构

代码片段

spring.xml

复制代码
1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xmlns:context="http://www.springframework.org/schema/context"
 5     xsi:schemaLocation="
 6         http://www.springframework.org/schema/beans
 7         http://www.springframework.org/schema/beans/spring-beans.xsd
 8         http://www.springframework.org/schema/context
 9         http://www.springframework.org/schema/context/spring-context.xsd">
10 
11     <!-- Spring注解扫描 -->
12     <context:component-scan base-package="com.*" />
13 
14     <!-- 1. 数据源对象: C3P0连接池 -->
15     <bean id="dataSource"
16         class="com.mchange.v2.c3p0.ComboPooledDataSource">
17         <property name="driverClass" value="org.h2.Driver"></property>
18         <property name="jdbcUrl"
19             value="jdbc:h2:tcp://192.168.190.1/~/test"></property>
20         <property name="user" value="sa"></property>
21         <property name="password" value="123"></property>
22     </bean>
23 
24     <!-- 2. JdbcTemplate工具类实例 -->
25     <bean id="jdbcTemplate"
26         class="org.springframework.jdbc.core.JdbcTemplate">
27         <property name="dataSource" ref="dataSource"></property>
28     </bean>
29 
30     <!-- 3.配置事务 -->
31     <bean id="dataSourceTransactionManager"
32         class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
33         <property name="dataSource" ref="dataSource"></property>
34     </bean>
35 
36 </beans>
复制代码

 

 Test.java

复制代码
1 public class Test {
2     public static void main(String[] args) {
3         ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(
4                 "spring.xml");
5         ServiceIF service = (ServiceIF) classPathXmlApplicationContext.getBean("serviceImpl");
6         service.add("小王", 23);
7     }
8 }
复制代码

TransactionUtil.java

 

复制代码
1 @Component("transactionUtil")
 2 public class TransactionUtil {
 3 
 4     /**
 5      * 初始化数据源
 6      */
 7     @Autowired
 8     private DataSourceTransactionManager dataSourceTransactionManager;
 9 
10     /**
11      * 开启事务
12      * 
13      * @return
14      */
15     public TransactionStatus begin() {
16         TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionDefinition());
17         System.out.println(" 开启事务成功 ");
18         return transaction;
19     }
20 
21     /**
22      * 提交事物
23      * 
24      * @param transaction
25      */
26     public void commit(TransactionStatus transaction) {
27         dataSourceTransactionManager.commit(transaction);
28         System.out.println(" 事物提交成功 ");
29     }
30 
31     /**
32      * 回滚事务
33      * 
34      * @param transaction
35      */
36     public void rollback(TransactionStatus transaction) {
37         dataSourceTransactionManager.rollback(transaction);
38         System.err.println(" 事物进行回滚 ");
39     }
40 }
复制代码

 

ServiceImpl.java

复制代码
1 @Service("serviceImpl")
 2 public class ServiceImpl implements ServiceIF {
 3 
 4     @Autowired
 5     TransactionUtil transactionUtil;
 6 
 7     private TransactionStatus transactionStatus = null;
 8 
 9     @Override
10     public void add(String name, Integer age) {
11         transactionStatus = transactionUtil.begin();
12         try {
13             new DaoImpl().add(name, age);
14             transactionUtil.commit(transactionStatus);
15         } catch (Exception e) {
16             System.err.println("ERROR >>> 执行出现异常 即将进行回滚操作");
17             transactionUtil.rollback(transactionStatus);
18         }
19     }
20 }
复制代码

DaoImpl.java

复制代码
1 public class DaoImpl implements DaoIF{
 2 
 3     /**
 4      * 注入jdbc模板类
 5      */
 6     @Autowired
 7     private JdbcTemplate jdbcTemplate;
 8 
 9     /**
10      * 第一条插入语句
11      */
12     private final String SQL_INSERT_01 = "insert into user values (?,?)";
13 
14     /**
15      * 添加sql执行
16      * 
17      * @param name
18      * @param age
19      */
20     public void add(String name, Integer age) {
21         jdbcTemplate.update(SQL_INSERT_01, name, age);
22     }
23 }
复制代码

运行结果

 

 问题分析

 


解决思路

我在想 为什么会没有注入进来呢 我明明加了 @Autowired 注解

后来猜到可能是 Spring.xml 配置的问题

看完也没有问题 我就从 Java Source 一步一步看 发现....

我靠 我就猜测是不是如果用「new Object ()」的方式创建实例后 其 class 中的 Bean 的注解会失效呢?

然后我尝试在 ServiceImpl.java 中以注解的方式把 DaoIF 的实例注入到 ServiceImpl,

并在 DaoImpl.java 的类上面添加 @Repository,

把 ServiceImpl.java 中 new DaoImpl () 替换成注入的 daoImpl。

 

改修代码

ServiceImpl.java 修改后

DaoImpl.java 修改后


改修后调试

 


 

其实我懂得也不太多 Spring 注入的流程那

首先他会把项目中 target -> classes 目录下的「.class」文件进行解析

通过 Spring.xml 中的「context:component-scan」进行注解扫描

如果这个路径下的「.class」文件的类上面是否存在 @Component 声明的注解

如果被此类注解修饰,Spring 会把所有被注解修饰的 bean 进行实例化操作  供给 @Autowired 进行注入

(在 spring 注解的源码中 @Service 和 @Repository 等等都继承了 @Component 注解)

 

 

  结论 

在使用 Spring 的 Bean 容器时 千万要确保

                配置的注解扫描路径正确

                Jar 的依赖是否存在

                是否在 bean 的上面加「@Service @Repository @Component … 」

                要细心 遇到异常不要紧 慢慢分析!!!

 

https://www.cnblogs.com/cat-/p/10014477.html

@Autowired 注入在接口的实现类上 报错

@Autowired 注入在接口的实现类上 报错

@Autowired

priate 接口 接口;正确

priate 接口实现类 接口实现类;报错

 

 

@Autowired 注入失败等问题

@Autowired 注入失败等问题

问题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.总结

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

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

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

@Autowired 还可以注入 List 和 Map

@Autowired 还可以注入 List 和 Map

@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
这个 restTemplates 能够将所有标注了 @LoadBalanced 的 RestTemplate 自动注入进来呢?这就要说说 @Autowired 注解和 @Qualifier 这两个注解了。
大家日常使用很多都是用 @Autowired 来注入一个 bean, 其实 @Autowired 还可以注入 List 和 Map, 比如我定义两个 Bean:

@Bean("user1")
User user1() {
return new User("1", "a");
}

@Bean("user2"))
User user2() {
return new User("2", "b");
}

然后我写一个 Controller:
import com.example.demo.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
public class MyController {

@Autowired(required = false)
private List<User> users = Collections.emptyList();

@Autowired(required = false)
private Map<String,User> userMap = new HashMap<>();

@RequestMapping("/list")
public Object listUsers() {
return users;
}
@RequestMapping("/map")
public Object mapUsers() {
return userMap;
}
}

在 controller 中通过:
@Autowired(required = false)
private List<User> users = Collections.emptyList();

@Autowired(required = false)
private Map<String,User> userMap = new HashMap<>();

就可以自动将两个 bean 注入进来,当注入 map 的时候,map 的 key 必须是 String 类型,然后 bean name 将作为 map 的 key, 本例,map 中将有两个 key 分别为 user1 和 user2,value 分别为对应的 User Bean 实例。
访问 http://localhost:8080/map:

{
"user1": {
"id": "1",
"name": "a"
},
"user2": {
"id": "2",
"name": "b"
}
}

访问 http://localhost:8080/list:
[
{
"id": "1",
"name": "a"
},
{
"id": "2",
"name": "b"
}
]

然后我们给 user1 和 user2 分别打上 @Qualifier 修饰符:
@Bean("user1")
@Qualifier("valid")
User user1() {
return new User("1", "a");
}

@Bean("user2")
@Qualifier("invalid")
User user2() {
return new User("2", "b");
}

然后将 controller 中的 user list 和 user map 分别也打上 @Qualifier 修饰符:
import com.example.demo.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
public class MyController {

@Autowired(required = false)
@Qualifier("valid")
private List<User> users = Collections.emptyList();

@Autowired(required = false)
@Qualifier("invalid")
private Map<String,User> userMap = new HashMap<>();

@RequestMapping("/list")
public Object listUsers() {
return users;
}
@RequestMapping("/map")
public Object mapUsers() {
return userMap;
}
}
那么所有标注了 @Qualifier ("valid") 的 user bean 都会自动注入到 List<user> users 中去 (本例是 user1),所有标注了 @Qualifier ("invalid") 的 user bean 都会自动注入到 Map<String,User> userMap 中去(本例是 user2),我们再次访问上面两个 url:


访问 http://localhost:8080/list:

[
{
"id": "1",
"name": "a"
}
]
访问 http://localhost:8080/map:
{
"user2": {
"id": "2",
"name": "b"
}
}

看到这里我们可以理解 @LoadBalanced 的用处了,其实就是一个修饰符,和 @Qualifier 一样,比如我们给 user1 打上 @LoadBalanced:
@Bean("user1")
@LoadBalanced
User user1() {
return new User("1", "a");
}

@Bean("user2")
User user2() {
return new User("2", "b");
}

然后 controller 中给 List<User> users 打上 @LoadBalanced 注解:
@Autowired(required = false)
@LoadBalanced
private List<User> users = Collections.emptyList();


访问 http://localhost:8080/list:
[
{
"id": "1",
"name": "a"
}
]

和 @Qualifier 注解效果一样,只有 user1 被注入进了 List,user2 没有修饰符,没有被注入进去。
另外当 spring 容器中有多个相同类型的 bean 的时候,可以通过 @Qualifier 来进行区分,以便在注入的时候明确表明你要注入具体的哪个 bean, 消除歧义。
---------------------
作者:xiao_jun_0820
来源:CSDN
原文:https://blog.csdn.net/xiao_jun_0820/article/details/78917215
版权声明:本文为博主原创文章,转载请附上博文链接!

关于在测试过程中注入@Autowired私有字段在测试sql注入时,哪种方式不可取的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于@Autowired 注入为 null 问题分析、@Autowired 注入在接口的实现类上 报错、@Autowired 注入失败等问题、@Autowired 还可以注入 List 和 Map的相关信息,请在本站寻找。

本文标签: