最近在做项目的时候,发现程序运行的时候有一个nullpointer exception,一脸懵逼因为感觉程序没什么逻辑。后来发现是因为new出来的component不会自动注入它的元素。
现象:@Component修饰的自定义普通类中@Autowired属性为null
原因:如果是通过new实例化的对象,脱离了Spring的管理,所以获取不到Spring注解的属性值。
在新线程中也会存在注解获取不到Spring管理的Bean,也是因为new出来的线程,脱离了Spring容器
我在实际开发中遇到有一段公共的代码,几个方法都需要掉,但如果单独拉出来写一个方法的话,入参又不同,所以想到了用泛型。
比如这是一段公共代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
//保存订单信息,需要多个方法调用 OrderFilterRequest orderFilterRequest = new OrderFilterRequest(); btOrderFilterRequest.setUserId( "1" ); btOrderFilterRequest.setStatus( "0" ); List<Order> orderResultList = orderService.findOrders(orderFilterRequest); Order result = null ; if (CollectionUtils.isEmpty(orderResultList )){ Order order = CopierUtils.convert(request, Order. class ); order.setRealName(customer.getRealName()); order.setIdcardNo(customer.getIdcardNo()); order.setOrderNo( "order" + DateUtil.getYMDHMS()); order.setStatus( "0" ); order.setCreateTime( new Date()); order.setUpdateTime( new Date()); order.setUserId( "1" ); result = orderService.createOrder(Order); } else { Order orderResult = orderResultList.get( 0 ); CopierUtils.copy(request, orderResult); orderResult.setUpdateTime( new Date()); result = orderService.updateOrder(btOrderResult); } |
将这段代码提炼成泛型类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
@Transactional (readOnly = true ) @Component public class OrderRequest<T>{ @Autowired private OrderService orderService; @Transactional public Order orderInfoSave(T request) { OrderFilterRequest orderFilterRequest = new OrderFilterRequest(); btOrderFilterRequest.setUserId( "1" ); btOrderFilterRequest.setStatus( "0" ); List<Order> orderResultList = orderService.findOrders(orderFilterRequest); Order result = null ; if (CollectionUtils.isEmpty(orderResultList )){ Order order = CopierUtils.convert(request, Order. class ); order.setRealName(customer.getRealName()); order.setIdcardNo(customer.getIdcardNo()); order.setOrderNo( "order" + DateUtil.getYMDHMS()); order.setStatus( "0" ); order.setCreateTime( new Date()); order.setUpdateTime( new Date()); order.setUserId( "1" ); result = orderService.createOrder(Order); } else { Order orderResult = orderResultList.get( 0 ); CopierUtils.copy(request, orderResult); orderResult.setUpdateTime( new Date()); result = orderService.updateOrder(btOrderResult); } return result; } } |
最开始我是这么调用的:
1
2
3
4
5
6
7
8
9
|
public void method1(Request1 request ) { OrderRequest<Request1> orderCreateRequest = new OrderRequest <Request1>(); Order result = OrderCreateRequest.orderInfoSave(request); } public void method2(Request2 request ) { OrderRequest<Request2> orderCreateRequest = new OrderRequest <Request2>(); Order result = OrderCreateRequest.orderInfoSave(request); } |
但是OrderRequest中orderService为null。(在controller层中注入service接口,在service层中注入orderService是有值的),尝试可很多解决办法,最后发现,原来spring自定义的类实例化时也需要用注入的方式,不能用new,否则脱离了spring的管理。改成如下方式就可以了:
1
2
3
4
5
6
7
8
9
10
11
12
|
@Autowired private OrderRequest<Request1> request1; @Autowired private OrderRequest<Request2> request2; public void method1(Request1 request ) { Order result = request1.orderInfoSave(request); } public void method2(Request2 request ) { Order result = request2.orderInfoSave(request); } |
总结:
如果在A类中的属性b有@Autowired这样的注解,则类A的实例化不能用new 操作,必须要用注入的方式,否则脱离了spring的管理;
解决方法:
调用ApplicationContextUtil.getApplicationContext().getBean("XXX", XXX.class);方法获取component