Annotations vs @Java config
Java config (@Bean, @Configuration)
- @Bean is used when auto-detection is not possible, like to integrate existing libraries while @Component are automatically detected by Spring.
- @Bean are configured in a @Configuration class at method level, it decouples instantiation from definition.
Annotations:
- @Component work at class level and can be only if the class is editable.
Configuration
@Import
Configuration metadata, contains bean definitions, can use Import to import other configurations.
@Import({Configuration.class,OtherConfiguration.class})
@PropertySource
Adds additional properties, prefixes (“classpath”,”file” and “http”).
@PropertySource(“classpath:/com/example/example.properties”)
@PropertySource(“file:config/example.properties”)
Java configuration
@Configuration
@Configuration
@PropertySource("classpath:example.properties")
public class ApplicationConfiguration {
@Bean
public MessageBean getMessageBean() {
return new HelloWorldBean();
}
@Bean(name = "message")
public String getMessage( @Value("${bean.message}") String message) {
return message;
}
}
Usage
public class SpringApplicationMain {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
MessageBean messageBean = applicationContext.getBean(MessageBean.class);
System.out.println("->" + messageBean.getMessage());
}
}
Tests
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = ApplicationConfiguration.class)
public class ApplicationConfigurationTest {
public static final String MESSAGE = "this is a bean";
/**
* Complex example with the use of annotations and autowire
*/
@Autowired
ApplicationContext applicationContext;
@Autowired
MessageBean messageBean;
@Test
public void testApplicationContext() {
Assertions.assertNotNull(applicationContext);
MessageBean messageBean = applicationContext.getBean(MessageBean.class);
Assertions.assertEquals(MESSAGE, messageBean.getMessage());
}
}
Tests
To configure Spring context in Spring a combination of annotations can be used.
Configures Junit to use Spring Context, can use @ContextConfiguration to set configuration class. @ContextConfiguration(classes = ApplicationConfiguration.class)
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = ApplicationConfiguration.class)
public class AutoWiringTypesTest {
@Autowired
@Qualifier("fruitSaladConstructor")
FruitSaladConstructor fruitSaladConstructor;
....
}
Annotations @ExtendWith and @ContextConfiguration can be replaced with @SpringJUnitConfig or @SpringJUnitWebConfig.
@SpringJUnitConfig(SpringJUnitConfigIntegrationTest.Config.class)
public class SpringJUnitConfigIntegrationTest {
@Configuration
static class Config {}
}
Annotation configuration
Using @ComponentScan and stereotypes.
@Configuration
@PropertySource("classpath:example.properties")
@ComponentScan
public class ApplicationConfiguration {
...
...
...
@Service
public class SomeService {
@Value("${service.message}")
private String message = "";
public String getMessage() {
return message;
}
}
public MyService getMyService(){
..
}
}
Manual Bean registration
Manual bean configuration could be used for different reasons:
- Dynamic Configuration: Sometimes, you don’t know how many instances of a certain class you need until runtime. For example, if you’re reading configuration from a file or database, you might need to create a variable number of beans based on that configuration. Programmatic registration allows you to dynamically create and register these beans at runtime .
- Conditional Bean Creation: You might want to create beans based on certain conditions, such as the presence of a specific property or the active profile. Programmatic registration gives you the flexibility to check these conditions and decide whether to create and register the beans .
- Custom Logic: You might need to apply custom logic to the creation of your beans, such as setting specific properties or constructor arguments. Programmatic registration allows you to implement this custom logic directly in your code .
- Integration with Non-Spring Components: If you’re working with components or libraries that are not managed by Spring, you can register these components as beans programmatically to integrate them into your Spring application context .
Register Bean
public class App {
public static void main(String[] args) {
// no configurations class passed 👇🏻
var ctx = new AnnotationConfigApplicationContext();
// register bean is used to make spring context aware of it .
ctx.register(Person.class);
// refreshing the context by creating instances from all beans that we registered .
ctx.refresh();
Person p = ctx.getBean(Person.class);
}
}
Register Bean Definition
public class GenericBeanDefinitionExample {
public static void main (String[] args) {
DefaultListableBeanFactory context =
new DefaultListableBeanFactory();
GenericBeanDefinition gbd = new GenericBeanDefinition();
gbd.setBeanClass(MyBean.class);
MutablePropertyValues mpv = new MutablePropertyValues();
mpv.add("date", new Date());
//alternatively we can use:
// gbd.getPropertyValues().addPropertyValue("date", new Date());
gbd.setPropertyValues(mpv);
context.registerBeanDefinition("myBeanName", gbd);
MyBean bean = context.getBean(MyBean.class);
bean.doSomething();
}
}