在本文中,您将会了解到关于在测试过程中注入@Autowired私有字段的新资讯,同时我们还将为您解释在测试sql注入时,哪种方式不可取的相关在本文中,我们将带你探索在测试过程中注入@Autowired
在本文中,您将会了解到关于在测试过程中注入@Autowired私有字段的新资讯,同时我们还将为您解释在测试sql注入时,哪种方式不可取的相关在本文中,我们将带你探索在测试过程中注入@Autowired私有字段的奥秘,分析在测试sql注入时,哪种方式不可取的特点,并给出一些关于@Autowired 注入为 null 问题分析、@Autowired 注入在接口的实现类上 报错、@Autowired 注入失败等问题、@Autowired 还可以注入 List 和 Map的实用技巧。
本文目录一览:- 在测试过程中注入@Autowired私有字段(在测试sql注入时,哪种方式不可取)
- @Autowired 注入为 null 问题分析
- @Autowired 注入在接口的实现类上 报错
- @Autowired 注入失败等问题
- @Autowired 还可以注入 List 和 Map
在测试过程中注入@Autowired私有字段(在测试sql注入时,哪种方式不可取)
我有一个组件安装程序,它实际上是一个应用程序的启动器。它的配置如下:
@Componentpublic class MyLauncher { @Autowired MyService myService; //other methods}
MyService带有@Service
Spring注释,并自动连接到我的启动器类中,没有任何问题。
我想为MyLauncher编写一些jUnit测试用例,为此,我启动了一个这样的类:
public class MyLauncherTest private MyLauncher myLauncher = new MyLauncher(); @Test public void someTest() { }}
我可以为MyService创建一个Mock对象,然后将其注入测试类中的myLauncher吗?由于Spring正在处理自动装配,因此我目前在myLauncher中没有吸气剂或吸气剂。如果可能的话,我不想添加getter和setter。我可以告诉测试用例使用@Before
init方法将模拟对象注入自动接线的变量中吗?
如果我要彻底解决这个问题,请随意说。我还是这个新手。我的主要目标是只具有一些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 问题分析
题说明
最近看到 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
priate 接口 接口;正确
priate 接口实现类 接口实现类;报错
@Autowired 注入失败等问题
问题1 @Autowired 注入失败
@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毫秒的延迟,写代码的时候需要考虑进去这种误差。
3.总结
环境也是一方面的问题:
今天突然docker的mysql用不了了,之后弄了很久,重新初始化了数据库,直接在控制台跑的mysql,然后就不用docker了。
本周的主要感受就是修bug有时候很不容易,特别是别人写的代码。很多时候费时间的不是修bug的时间,而是找bug发生在哪里的问题。跑了很久的前后台,打了很多断点到控制台,才发现哪里有问题。不过这也是一种锻炼,加强了我的测试能力和阅读代码的能力。
目前解决了@Autowired的问题后,rizhi系统目前暂时没有问题。很多时间自己测试的时候没有问题,直到集成测试的时候才暴露问题,还是测试不够充分。
@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的相关信息,请在本站寻找。
本文标签: