I'm currently working on a Spring web application which makes use of both Spring MVC and Spring Websocket. The configuration is annotation based. I'm using the AbstractAnnotationConfigDispatcherServletInitializer class as initializer, and I am confused about the servlet mappings I should provide, and the way I should do so.
I'd like to have all my MVC controller mapped under "/webservices/" path, and my Websocket endpoint to be under "/websockets/".
Among my #Configuration classes, one is dedicated to configure Spring MVC (#EnableWebMVC) and another one is dedicated to Spring WebSocket (#EnableWebSocketMessageBroker).
I implemented my initializer as follows :
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {WebMVCConfiguration.class, WebSocketConfiguration.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/webservices/*","/websockets/*"};
}
Also please note that I imported all of my configuration classes through the use of #Import on my Root Configuration class. I'm not sure if I should import the MVC and Websocket configuration though, as I already declared them in the getServletConfigClasses() method... But I did.
Anyway, It worked fine this way until now. But I recently added the use of #PropertySource annotation to my app (To inject my app properties through the use of #Value("${}") expressions), and thanks to that I noticed that at least the WebSocket Configuration class is ... scanned (?) twice : The first time with the #Value field value properly injected, but not the second time (Which caused an error).
While troubleshooting I noticed that I don't have this "double scanning" problem when I remove the WebSocketConfiguration class from the getServletConfigClasses() method : it is scanned only once, with the property valye properly injected. What surprised me is that even without declaring the WebSocketConfiguration in getServletConfigClasses(), the "/websockets" endpoints still works ! My guess is that it is scanned thanks to the #Import on my Root config class... but then how Spring knows it should bind the WebSocketConfiguration to the "/websockets" path ?
All of this made me wonder about my understanding of when / how I should import configurations classes. So here are my questions :
Do I really need to declare two servlet mappings to keep my services and websockets paths separated as they are ?
Is it necessary to declare as much Servlet Config classes as I have Servlet Mappings ? (Seeing how removing the WebSocketConfiguration class from getServletConfigClasses() didn't alter the WebSocket functionality... Or is it just a fluke ?)
Will Spring use the same DispatcherServlet for all the Servlet Config classes ? Or will it create one for each mapping I provide ?
From what I tried it looks like Spring cannot inject properties through the use of #Value in the configuration classes provided thanks to getServletConfigClasses()... It works only when it is imported via #Import, or a standard component scanning. Does it seems logical to you ?
Thanks for your help !
Related
I have a multi-datasource web application with following technique:
Spring boot 1.5.12
Mybats-Spring-boot-starter 1.3.2
And I prefered Java based configuration. Therefore, I have Datasource1Config.java and Datasource2Config.java.
I defined SqlSessionTemplate respectively, and using MapperScannerConfigure to inject my mapper. Following is for datasource1, and the datasource2 just substitute the number.
#Bean(name = "dataSource1MapperScannerConfigurer")
public MapperScannerConfigurer msc() {
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setSqlSessionFactoryBeanName("dataSource1SqlSessionFactory");
msc.setSqlSessionTemplateBeanName("dataSource1SqlSessionFactory");
msc.setBasePackage("demo.mybatisspring.mapper.ds1");
return msc;
}
And then, the error happend
file [C:\...target\classes\demo\mybatisspring\mapper\ds1\UserMapper.class] required a single bean, but 2 were found:
- dataSource1SqlSessionFactory: defined by method 'sqlSessionFactoryBean' in class path resource [demo/mybatisspring/config/DataSource1Config.class]
- dataSource2SqlSessionFactory: defined by method 'sqlSessionFactoryBean2' in class path resource [demo/mybatisspring/config/DataSource2Config.class]
However, if I inject mappers with #MapperScan as following, everything will work fine. (also worked fine when one using #MapperScan and the other using #Bean MapperScannerConfigurer)
#MapperScan(basePackages = "demo.mybatisspring.mapper.ds1", sqlSessionTemplateRef = "dataSource1SqlSessionFactory")
public class DataSource1Config {...}
#MapperScan(basePackages = "demo.mybatisspring.mapper.ds2", sqlSessionTemplateRef = "dataSource2SqlSessionFactory")
public class DataSource2Config {...}
I've tried to trace with debug mode and search so many articles on internet, still can not get the answer instead. So if anyone can help me?
Thanks for your time.
I think answer is here. https://mybatis.org/spring/mappers.html
Scanning for mappers There is no need to register all your mappers one
by one. Instead, you can let MyBatis-Spring scan your classpath for
them.
There are three different ways to do it:
Using the element. Using the annotation #MapperScan
Using a classic Spring xml file and registering the
MapperScannerConfigurer Both and #MapperScan are
features introduced in MyBatis-Spring 1.2.0. #MapperScan requires
Spring 3.1+.
Since 2.0.2, mapper scanning feature support a option
(lazy-initialization) that control lazy initialization
enabled/disabled of mapper bean. The motivation for adding this option
is supporting a lazy initialization control feature supported by
Spring Boot 2.2. The default of this option is false (= not use lazy
initialization). If developer want to use lazy initialization for
mapper bean, it should be set to the true expressly.
Does anyone have any reference project with Spring-boot and Tapestry5? I can't seem to find any samples.
I have diificulties in configuring the tapestry bean & Context using a #configuration class without an web.xml.
This should be what you're looking for https://github.com/trust-wenderson/tapestry-spring
I've been looking for such an example myself, and I happen to have found one today:
https://github.com/code8/tapestry-boot
The tapestry-boot library implements following features:
bootstraps tapestry framework inside embedded servlet container managed by spring-boot
provides injection of spring-services into tapestry-services
provides injection of tapestry-services into spring-services
To use tapestry-boot simple marks tapestry application module with
#TapestryApplication annotation.
See DemoApplicationTests.
This works for me:
Register TapestrySpringFilter
#Bean
public FilterRegistrationBean tapesSpringFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new TapestrySpringFilter());
registration.setName("app");
registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
return registration;
}
Add context aprameters to application.yml
server:
context_parameters:
tapestry:
use-external-spring-context: true
app-package: com.test.admin
development-modules: ...
qa-modules: ...
I also had to use executable War to avoid problems with loading static files.
Perhaps this approach will not allow you to access the tapestry beans from the spring context.
I need to specify multiple template loader paths for FreeMarker in a Spring Boot web application but the FreeMarkerAutoConfigurationClass only let me specify one path using the spring.freemarker.templateLoaderPath property, which uses the setTemplateLoaderPath method in the FreeMarkerConfigurationFactory. However, this class allows me to set multiple path using the setTemplateLoaderPaths method. Which is the best way to override this auto-configuration class and specify multiple loader paths? I don't really understand well the Spring Java config classes and I want an example for this before write the code I need. I'm using Spring Boot 1.1.2. Thanks in advance.
You'll need to provide your own bean of type org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer with your desired configuration. To do so, add something similar to the following to one of your application's Java configuration classes:
#Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPaths("one", "two", "three");
// Apply further configuration as needed
return configurer;
}
Update: the latest Spring Boot 1.2 snapshots now accept a comma-separated list for the spring.freemarker.templateLoaderPath property allowing you to specify multiple paths without declaring a custom FreeMarkerConfigurer bean.
I can't seem to get my servlet's fields to #AutoWire; they end up null. I have a pure annotation-configured webapp (no XML files). My servlet looks like this:
#WebServlet("/service")
public
class
SatDBHessianServlet
extends HttpServlet
{
#Autowired protected NewsItemDAO mNewsItemDAO;
}
Other #AutoWired things seem to work fine, both #Service objects and #Repository objects. But not this one, and I can't figure out why. I even tried adding its package to the ComponentScan(basePackages) list for my other classes.
Additional Info:
I added the following to my servlet’s init() method, and everything seemed to wire up properly, but I'm confused as to why Spring can't wire it up without that.
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, inConfig.getServletContext());
Servlet are web components that are not being created by Spring container, based on that lifecycle is not managed by the container and a lot of stuff that spring provides such as autowired or aspect can not run from them.
You need to indicate to the spring container that a component was created outside of IoC container and need to be part of it.
And as the API said SpringBeanAutowiringSupport is for:
Convenient base class for self-autowiring classes that gets
constructed within a Spring-based web application
This generic servlet base class has no dependency on the Spring ApplicationContext concept.
There is another way to indicate servlets being created by spring container using an interface
Spring MVC uses the DispatcherServlet for handling all requests in a Servlet environment.
The DispatcherServlet accordingly forwards the requests to the appropriate #Controller class (if any) based on the #RequestMapping on that class and/or it's methods.
What is happening in your Servlet is that it is not managed by Spring (but by the Servlet container) and there for no injection of dependencies is occurring.
Right now I'm exposing the service layer of my application using spring remoting's RMI/SOAP/JMS/Hessian/Burlap/HttpInvoker exporters. What I'd like is to allow the user to somehow define which of these remoting mechanisms they'd like enabled (rather than enabling all of them), then only create those exporter beans.
I was hoping that spring's application context xml's had support for putting in conditional blocks around portions of the xml. However, from what I've seen so far there's nothing in the standard spring distribution that allows you to do something like this.
Are there any other ways to achieve what I'm trying to do?
I am going to assume that you are looking to configure your application based on your environment, as in... for production I want to use this beans, in dev these other ...
As Ralph is saying, since Spring 3.1 you have profiles... But the key, is that you understand that you should put your environment based beans in different configuration files... so you could have something like dev-beans.xml, prod-beans.xml... Then in your main spring file, then you just invoke the appropriate one based on the environment that you are using... So profiles are only technique to do so... But you can also use other techniques, like have a system environmental variable, or pass a parameter in your build to decide which beans you want to use
You could realize this by using a Spring #Configuration bean, so you can construct your beans in java code. (see http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-java)
#Configuration
public class AppConfig {
#Bean
public MyService myService() {
if ( userSettingIshessian ) {
return new HessianExporter();
}else {
return new BurlapExporter();
}
}
}
Of course you need to get the user setting from somewhere, a system parameter would be easy, or config file, or something else.
Spring 3.1 has the concept of Profiles. My you can use them.