无法在Spring Boot的控制器之外实现依赖注入。

huangapple go评论69阅读模式
英文:

Can't achieve dependency injection oustide a controller in Spring Booot

问题

我是Spring MVC框架的新手,目前正在开发一个使用会话范围Bean控制某些数据流的Web应用程序。我可以在控制器中使用*@Autowired注解访问应用程序上下文中的这些Bean,没有任何问题。但是,当我在服务层中使用一个没有任何请求映射(@RequestMapping*、@GetMapping或*@PostMapping*)注解的类时,问题就出现了。当我尝试直接访问应用程序上下文,或者使用*@Autowired@Resource注解时,该Bean的值为null*。

我有一个如下所示的配置类:

@Configuration
@EnableAspectJAutoProxy
@EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class, basePackages = "com.quantumx.nitididea.NITIDideaweb.repository")
public class AppConfig implements WebMvcConfigurer {
	
	@Bean (name = "lastTemplate")
	@SessionScope
	public LastTemplate getlastTemplate() {
		return new LastTemplate();
	}
//一些额外的代码

}

POJO类定义如下:

public class LastTemplate {
	
	private Integer lastId;
	
	public LastTemplate(){
		
	}

	public Integer getLastId() {
		return lastId;
	}

	public void setLastId(Integer lastId) {
		this.lastId = lastId;
	}

}

然后我有一个被注解为服务的测试类,没有任何请求映射的注解方法:

//@Controller
@Service
public class Test {
	
//	 @Autowired
//	 private ApplicationContext context;	
	
//	@Autowired
	@Resource(name = "lastTemplate")
	public LastTemplate lastTemplate;
	
//	@Autowired
//	public void setLastTemplate(LastTemplate lastTemplate) {
//		this.lastTemplate = lastTemplate;
//	}

	public Test() {
	}
	
//	@RequestMapping("/test")
	public String testing() {
//		TemplateForma last = (TemplateForma) context.getBean("lastInsertedTemplate");
//		System.out.println(last);
		System.out.println(lastTemplate);
//		System.out.println(context.containsBean("lastTemplate"));
//		System.out.println(context.getBean("lastTemplate"));
		System.out.println("Testing complete");
		return "Exit from testing method";
//		return "/Messages/Success";
	}
}

正如您所见,有很多被注释掉的代码,展示了我尝试访问应用程序上下文的所有方式,包括使用应用程序上下文依赖项、自动装配、声明资源以及尝试使用请求映射。如果不使用控制器注解和请求映射方法,则Bean为空,并且在使用上下文的getBean()方法时会抛出Java空指针异常。

最后,我只是在我的应用程序中的一个控制器中测试了一下我的类:

@RequestMapping("/all")
public String showAll(Model model) {
	
	Test test = new Test();
	test.testing();

	return "/Administrator/test";
}

值得一提的是,我还尝试将Bean的范围更改为应用程序范围和单例,但没有成功。如何在没有通过控制器映射请求的情况下,在服务类中访问我的应用程序上下文呢?

英文:

I am new at spring MVC framework and i am currently working in a web application that uses a session scoped bean to control some data flow.
I can access these beans in my application context using @Autowired annotation without any problem in the controllers. The problem comes when I use a class in service layer that does not have any request mapping (@RequestMapping, @GetMapping nor @PostMapping) annotation.
When I try to access the application context directly or using @Autowired or even the @Resource annotation the bean has a null value.

I have a configuration class as follow:

@Configuration
@EnableAspectJAutoProxy
@EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class, basePackages = "com.quantumx.nitididea.NITIDideaweb.repository")
public class AppConfig implements WebMvcConfigurer {
	
	@Bean (name = "lastTemplate")
	@SessionScope
	public LastTemplate getlastTemplate() {
		return new LastTemplate();
	}
//Some extra code

}

The POJO class is defined as :

public class LastTemplate {
	
	private Integer lastId;
	
	public LastTemplate(){
		
	}

	public Integer getLastId() {
		return lastId;
	}

	public void setLastId(Integer lastId) {
		this.lastId = lastId;
	}

}

The I have a Test class that is annotated as service and does not have any request mapping annotated method:

//@Controller
@Service
public class Test {
	
//	 @Autowired
//	 private ApplicationContext context;	
	
//	@Autowired
	@Resource(name = "lastTemplate")
	public LastTemplate lastTemplate;
	
//	@Autowired
//	public void setLastTemplate(LastTemplate lastTemplate) {
//		this.lastTemplate = lastTemplate;
//	}

	public Test() {
	}
	
//	@RequestMapping("/test")
	public String testing() {
//		TemplateForma last = (TemplateForma) context.getBean("lastInsertedTemplate");
//		System.out.println(last);
		System.out.println(lastTemplate);
//		System.out.println(context.containsBean("lastTemplate"));
//		System.out.println(context.getBean("lastTemplate"));
		System.out.println("Testing complete");
		return "Exit from testing method";
//		return "/Messages/Success";
	}
}

As you can see, there is a lot of commented code to show all the ways i have been trying to access my application context, using an Application context dependency, autowiring, declaring a resource and trying with a request mapping. The bean is null if no controller annotation and request mapping method is used and throws a java null pointer exception when I use the context getBean() methods.

Finally I just test my class in a controller that i have in my app:

@RequestMapping("/all")
	public String showAll(Model model) {
		
		Test test = new Test();
		test.testing();

		return "/Administrator/test";
	}

Worth to mention that I also tried to change the scope of the bean to a Application scope and singleton, but it not worked. How can access my application context in a service class without mapping a request via controller?

答案1

得分: 0

> 值得提到的是,我还尝试将Bean的范围更改为应用程序范围(Application scope)和单例(singleton),但这并没有起作用。

在这种情况下,它应该是可以工作的。

> 在不通过控制器映射请求的情况下,如何在服务类中访问我的应用程序上下文?

尝试以下之一:

@Autowired private ApplicationContext appContext;

或者

在你想要访问它的类中实现 ApplicationContextAware 接口。

编辑:

如果你仍然想从非 Spring 管理的类中访问 ApplicationContext。这是一篇教程,展示了如何实现这一目标。

这个页面提供了一个示例,展示了如何在非 Spring 管理的类中获取 Spring 应用程序上下文对象

英文:

> Worth to mention that I also tried to change the scope of the bean to a Application scope and singleton, but it not worked

It should have worked in this case.

> How can access my application context in a service class without mapping a request via controller?

Try one of these :-

@Autowired
private ApplicationContext appContext;

OR

Implement ApplicationContextAware interface in the class where you want to access it.

Edit:

If you still want to access ApplicationContext from non spring managed class. Here is the link to article which shows how it can be achieved.

This page gives an example to get spring application context object with in non spring managed classes as well

答案2

得分: 0

以下是翻译好的部分:

我成功的做法是将会话范围的 Bean 从应用程序配置声明中移除,并移到 POJO 定义中,如下所示:

    @Component
    @SessionScope    
    public class LastTemplate {
        
        private Integer lastId;
        
        public LastTemplate(){
            
        }
    
        public Integer getLastId() {
            return lastId;
        }
    
        public void setLastId(Integer lastId) {
            this.lastId = lastId;
        } 
    }

然后我使用 *@Autowired* 注解来调用这个 Bean。
英文:

What worked for me is that session scoped bean had to be removed in the application configuration declaration and moved to the POJO definition as follows:

@Component
@SessionScope    
public class LastTemplate {
    
    private Integer lastId;
    
    public LastTemplate(){
        
    }

    public Integer getLastId() {
        return lastId;
    }

    public void setLastId(Integer lastId) {
        this.lastId = lastId;
    } 
}

The I just call the bean using @Autowired annotation.

huangapple
  • 本文由 发表于 2020年10月14日 11:02:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/64346017.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定