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:
- When should I put the
WebConfig.class
in thegetServletConfigClasses()
or in thegetRootConfigClasses()
or both? What is the difference? - Does it matter what is the order of the classes that are present in the
getRootConfigClasses()
andgetServletConfigClasses()
methods? I've seen somewhere that order matters for the initializers and people put@Order
at them but what about theConfig
classes? - For the
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? - If I add another configuration class say
CoreConfig
(I had one). Then load spring application context from XML in it and add it to the classes ingetRootConfigClasses()
:
Note: no duplicate beans with Config classes are present in the applicationContext.xml.
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!