简体   繁体   中英

Spring Boot @Autowired MessageSource works in one classes and doesn't in another

I'm learning Spring boot framework (version 2.0.7.RELEASE) for developing web application. When I try to autowire MessageSource class it works for one classes, but doesn't for another:

Here is my WebConfig class:

package net.local.mis.phog.config;
@Configuration
public class WebConfig implements WebMvcConfigurer {
    [...]
    @Bean
    public MessageSource messageSource() {
        // This is the only place around application where messageSource is created
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasename("classpath:messages");
        messageSource.setDefaultEncoding("UTF-8");

        return messageSource;
    }
    [...]
}

Everything works fine in controller classes, for example:

package net.local.mis.phog.controller;
@Controller
@Transactional
public class AlbumController {
    [...]
    @Autowired
    private MessageSource messageSource; (works fine)
    [...]
}

But when I try to inject messagSource in model classes it failes:

package net.local.mis.phog.model;
@Component
public class AlbumModel {
    [...]
    @Autowired
    private MessageSource messageSource; (null)
    [...]
}

In spring - component autowired in one class but not in another Balaji Krishnan says: "You are not using spring to obtain Account instance - so spring did not get a chance to autowire it". Perhaps I should do something of the kind, but I cannot understand how.

Can anybody please help me.

Thank you, Mikhail.

For spring to leverage dependency injection, the beans must all be managed by spring. The AlbumModel object creation should be managed by spring, so that the MessageSource can be autowired. If AlbumModel should not be managed by spring and you want to create the object yourself (which I doubt because you annotated it with @Component ) then you could also use constructor injection.

Whereas you can have something like this:

package net.local.mis.phog.model;
@Component
public class AlbumModel {
    [...]

    private MessageSource messageSource; 
    [...]

    @Autowired
    public AlbumModel(MessageSource messageSource) {
        this.messageSource = messageSource;
    }
}

With the solution above, when you manually create an AlbumModel , you could pass in the MessageSource object, which is already autowired by the calling class (for example the controller or any service layer class). But also when AlbumModel creation is manage by spring it is advisable to use constructor injection. Read more about it on an article by a Spring contributor

Thank you guys for your answers.

Amit Bera, I create AlbumModel object just by calling its constructor:

package net.local.mis.phog.controller;

@Controller
@Transactional
public class AlbumController {
    [...]
    @Autowired
    private JenreDao jenreDao;
    @Autowired
    private MessageSource messageSource;

    [...]
    @RequestMapping(value={"/album"},method=RequestMethod.GET)
    public String albumShowHandler(Model model,
                                   HttpServletRequest request,
                                   @RequestParam(value="jenreIdSelected") Long jenreIdSelected,
                                   @CookieValue(value="thumbnailOrder",defaultValue="ordDefault") String thumbnailOrder,
                                   [...]) {
        [...]
        ThumbnailOrderAux thumbnailOrderAux = new ThumbnailOrderAux(thumbnailOrder);
        JenreAux jenreAux = new JenreAux(jenreDao.getLstJenreModel(null,jenreIdSelected),jenreIdSelected);
        AlbumModel albumModel = new AlbumModel(jenreAux,thumbnailOrderAux);
        [...]

        model.addAttribute("albumModel",albumModel);

        return "album";
    }
    [...]
}

And here is code of AdminModel constructors:

package net.local.mis.phog.model;

@Component
public class AlbumModel {
    private JenreAux jenreAux;
    private ThumbnailAux thumbnailAux;
    [...]

    public AlbumModel() {
        super();
    }
    public AlbumModel(JenreAux jenreAux,ThumbnailOrderAux thumbnailOrderAux) {
        super();

        this.jenreAux = jenreAux;
        this.thumbnailOrderAux = thumbnailOrderAux;
    }
    [...]
}

Nazeem, I added @Component annotation to AlbumModel class in hope that MessageSource bean would be injected. Unfortunately it was not.

I could pass MessageSource as argument and it works even if I don't annotate constructor @Autowired. If I understand it right MessageSource bean is injected to AlbumController because it managed by Spring, and it isn't injected to AlbumModel because it doesn't managed by Spring. Right? If so, is there any way I make Spring manage AlbumModel object?

I had the same problem on a spring 3.1.1-RELEASE old application. In my case during debug I've got two different MessageResource objects as if the wold have been instanziated twice.

I've solved moving the bean definition:

<bean id="messageSource"
      class="org.springframework.context.support.ReloadableResourceBundleMessageSource">

from dispatcher-servlet.xml xml-based configuration file to the applicationContext.xml ones.

In other words, there exists two contexts : the application context and the dispatcher servlet contexts . The application context is the parent of the dispatcher servlet context (I guess that many servlet contexts may exists under the same application context if your application consists of many servlet).

Thus, beans defined in the application context are visible to the servlet context, but not vice versa . While the servlet context contains those beans that are specifically related to MVC, the application context is used to define broader beans like services.

Since @Controller annotation is a @Component annotated ones:

@Component
public @interface Controller

i guess Spring autowires beans in @Controller and @Component differently, looking for beans in the two different contexts mentioned above.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM