Context:
I switched from XML based to Java based Spring configuration. My application has a JSP based web layer, Spring MVC, Spring Security and Hibernate as persistence provider.
I managed to separate the whole XML configuration in different config classes:WebConfig
- for the Spring MVC configurations;PersistenceConfig
- as the name states - for the JPA configuration;ServiceConfig
- only for the @Service and @Component annotated classes;SecurityConfig
- for the Spring Security Configuration.
For application initialization I have the SecurityInitializer
and WebAppInitializer
classes.
Here is some code:
WebConfig
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.demo.app.web"})
public class WebConfig extends WebMvcConfigurerAdapter { /* Bean initialization */ }
PersistenceConfig
@Configuration
@ComponentScan(basePackages = {"com.demo.app.dao"})
@EnableTransactionManagement(mode = AdviceMode.PROXY, proxyTargetClass = true)
public class PersistenceConfig { /* Bean initialization */ }
ServiceConfig
@Configuration
@ComponentScan(basePackages = {"com.demo.app.service", "com.demo.app.component"})
public class ServiceConfig { /* Bean initialization */ }
SecurityConfig
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter { /* Bean initialization */ }
SecurityInitializer
@Order(1)
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
WebAppInitializer
@Order(2)
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] {SecurityConfig.class, PersistenceConfig.class,
ServiceConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] {WebConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
}
And having to test the whole thing I have:
TestContext
- abstract class that I think it sets up the basic context;TestWebContext
- extends TestContext
and adds the WebCOnfig
context. It's extended by all Controller tests;DaoTest
- extends TestContext
and adds transaction management. It's extended by all DAO tests;
TestContext
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {PersistenceConfig.class, ServiceConfig.class, SecurityConfig.class})
public abstract class TestContext {
}
TestWebContext
@ContextConfiguration(classes = {WebConfig.class})
@WebAppConfiguration
public abstract class TestWebContext extends TestContext {
}
DaoTest
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional
public abstract class DaoTest extends TestContext {
}
Questions:
WebConfig.class
in the getServletConfigClasses()
or in the getRootConfigClasses()
or both? What is the difference?getRootConfigClasses()
and getServletConfigClasses()
methods? I've seen somewhere that order matters for the initializers and people put @Order
at them but what about the Config
classes? TestWebContext
class I know that just adding @ContextConfiguration(classes = {WebConfig.class})
overrides the @ContextConfiguration
from the base class but how can I achieve the context extension? CoreConfig
(I had one). Then load spring application context from XML in it and add it to the classes in getRootConfigClasses()
:CoreConfig
@Configuration
@EnableScheduling
@ImportResource("classpath:applicationContext.xml")
public class CoreConfig { // No duplicate Beans load }
Which beans are loaded at first? The ones in applicationContext.xml or the ones from the Config classes?
Any other tips from practice that worked for you about the Java configuration are also highly appreciated!
Regarding the usage of the config files I actually use a similar approach with yours. A change that you may find useful could be to only have a RootConfig.class loaded from the getRootConfigClasses() , and that RootConfig may import the SecurityConfig.class, PersistenceConfig.class and ServiceConfig.class along with any other functionality it may have. For example in my case it also loads an application.properties file using @PropertySource("classpath:application.properties") annotation and containing a PropertySourcesPlaceholderConfigurer bean
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With