ApplicationContextUtil手动注入的Spring Bean,解决new对象的无法调用@Autowired注入的Bean

前言

我发现当前类含有@Autowired注入Spring Bean的成员对象时候,则当前类必须也是Spring Bean才能调用它,也就是说该类必须写上注解@Component、@Configuration加入Spring Bean管理该类。然后运用时候通过@Resource或者@Autowired来注入Bean,这样才能调用该类的某bean成员对象的方法,不能用new xxx()来获得对象,这种方式获得的对象无法调用@Autowired注入的Bean成员对象的方法。

例子

@Component
public class Children {
    public void test(){
        System.out.println("test for get Bean Children");
    }
}

//加入Spring Pool
注解效果如下:
<bean id=“children” class=“com.machome.testtip.impl.Children” >
</bean>

@Component
public class Parent {
    @Resource
    Children children;
    public void testParent(){
        System.out.println("test Parent");
        children.test();
    }
}

//加入Spring Pool
注解效果如下:
<bean id=“parent” class=“com.machome.testtip.impl.Parent” >
</bean>

@Resource注入bean正常调用

@RunWith(SpringRunner.class)
@SpringBootTest
public class TokenApplicationTests {

    @Resource
    Parent parent;

    @Test
    public void contextLoads() {
      parent.testParent();
    }

}

结果:
在这里插入图片描述

new对象调用Spring Bean的成员对象空指针异常

@RunWith(SpringRunner.class)
@SpringBootTest
public class TokenApplicationTests {

//    @Resource
//    Parent parent;

    @Test
    public void contextLoads() {
        Parent parent = new Parent();
      parent.testParent();
    }

}

结果:
在这里插入图片描述
使用new创建的对象,该对象中@Autowired注入的成员对象为null。

所以如果一个类中有spring容器注入的对象,则不能使用new来创建对象,最好使用@Autowired、@Resource来创建该对象。那么还有其他方法吗?

解决方法一:手动注入的Spring Bean

ApplicationContextUtil手动注入的Spring Bean

ApplicationContextUtil代码如下:

package com.example.token.kit;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * 手动注入bean
 * @author andrew
 *
 */
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
    @Autowired
    private static ApplicationContext context;

    /**
     * 插入ApplicationContext
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }
    /**
     * 获取ApplicationContext
     */
    public static ApplicationContext getApplicationContext() {
        return context;
    }


    /**
     * 通过name获取 Bean
     */
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }


    /**
     * 通过class获取Bean.
     */
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    /**
     *通过name,以及Clazz返回指定的Bean
     */
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }
}

测试代码:

@RunWith(SpringRunner.class)
@SpringBootTest
public class TokenApplicationTests {

//    @Resource
//    Parent parent;

    @Test
    public void contextLoads() {
      Parent parent = (Parent) ApplicationContextUtil.getBean("parent");
      parent.testParent();
    }

结果正常:
在这里插入图片描述

解决方法二:取消注解注入Bean成员对象,通过new对象调用方法

修改Parent代码,让Parent的成员对象children不通过@Resource注入,而是通过ApplicationContextUtil手动注入,这样Parent就不含有通过注解注入Bean的成员对象,从而可以Parent可以通过new的形式调用该成员对象的方法。不需要将自己加入到Spring Bean管理,也就是可以把Parent类的注解@Component去掉。

public class Parent {
//    @Resource
//    Children children;
    public void testParent(){
        System.out.println("test Parent");
        Children children = (Children) ApplicationContextUtil.getBean("children");
        children.test();
    }
}
@RunWith(SpringRunner.class)
@SpringBootTest
public class TokenApplicationTests {

//    @Resource
//    Parent parent;

    @Test
    public void contextLoads() {
      Parent parent = new Parent();
      parent.testParent();
    }

}

结果:
在这里插入图片描述

如果这篇文章对您有帮助,可否支持一下博主?
点赞+关注呗,谢谢您。

在这里插入图片描述

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
面试高级开发的期间整理的面试题目,记录我面试遇到过的spring题目以及答案 目录 spring ThreadLocal的底层对象; 为什么@Service和@Repository放到实现类上面而不是接口类上面; spring 三种注入(就是从spring容器中将bean放入对象属性值中) Spring下描述依赖关系@Resource, @Autowired和@Inject的区别与联系 SpringBeanFactory和ApplicationContext的区别 谈谈Spring IOC的理解,原理与实现? bean的生命周期,详细看上面 SpringBoot自动装配的过程的原理: spring的缓存; spring是如何解决的循环依赖; BeanFactory和FactoryBean有什么区别; Spring中用到的设计模式; SPI 机制(Java SPI 实际上是“基于接口的编程+策略模式+配置文件”组合实现的动态加载机制), 很多地方有用到: AOP Spring的AOP的底层实现原理; 为什么jdk动态代理是必须是接口 两种动态代理的区别 AOP实现方式:aop注解或者xml配置;后来工具jar包aspects; aop的属性 事务 事务编码方式: 事务注意事项; 为什么同一个类A调用b方法事务,A方法一定要有事务(编码式的不用) @transaction多个数据源事务怎么指定数据源 传播特性有几种?7种; 某一个事务嵌套另一个事务的时候怎么办? REQUIRED_NEW和REQUIRED区别 Spring的事务是如何回滚的,实现原理; 抽象类和接口的区别,什么时候用抽象类什么时候用接口; StringBuilder和StringBuffer的区别 java值传递和引用传递

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶孤崖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值