SPRING REVISITED: Application CONTEXT
Purposes?
Sometimes we read Spring Core documentation forgetfully
OR
We forgot some Spring Core concepts
OR
We don't want to know how this works under hood
SO
WE NEED TO REVISIT IT!
What's covered?
- Spring Lifecycle
-
Spring ApplicationContext and all that it involves
-
Different context type: How does it work?
-
Benchmarks
WHAT ARE WE TALKING ABOUT?
Common things & KeyWords:
ApplicaitonContext
Bean
BeanDefenition
BeanDefenitionReader
BeanPostProcessor
BeanFactory
BeanFactoryPostProcessor
WTF?
XmlBeanFactory factory = new XmlBeanFactory(
new FileSystemResource("spring.xml"));
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("dev.properties"));
cfg.postProcessBeanFactory(factory);
BEAN Lifecycle
Main bean lifecycle "players":
- InitializingBean and DisposableBean callback interfaces;
- Other Aware interfaces for specific behavior;
- Custom init() and destroy() methods in bean configuration file;
- @PostConstruct and @PreDestroy annotations;
- ContextListeners
BEAN LIFECYCLE
Context LifeCycle
CONTEXT LIFECYCLE
BeanFactoryPostProcessor
Purpose: You can customize your BeanDefenitions before Bean creation phase
Make some code:
public class DemoBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("PostBeanFactory");
}
}
CONTEXT LIFECYCLE
BeanFactoryPostProcessor
Context lifecycle
BeanPostProcessor
Purpose: To configure beans before they will go into the containter
public class DemoBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("PostBeforeInit: " + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("PostAfterInit: " + beanName);
return bean;
}
}
CONTEXT LIFECYCLE
BeanPostProcessor
@Component
<context:component-scan base-package="edu"/>
or
new AnnotationConfigApplicationContext("com");
@Component
ClassPathBeanDefenitionScanner
This class is not a subclass of BeanPostProcessor or BeanPostProcessorFactory
This class is ResourceLoaderAware
It creates BeanDefenition of all classes that have @Component annotation or sub-annotation by parsing .class files
Java Config
@Configuration
@ComponentScan("edu")
public class JavaConfig {
@Bean
public AnnotatedMessage annotatedMessage(){
AnnotatedMessage result = new AnnotatedMessage();
result.setText("Demo");
return result;
}
@Bean(initMethod = "method")
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public Message message(){
Message result = new Message();
result.setText("Demo1");
result.setAnnotatedMessage(annotatedMessage());
return result;
}
}
Java Config
new AnnotationConfigApplicationContext(AppConfig.class)
Do we have some ClasBeanReader?
Yes! - AnnotedBeanDefenitionReader
But this class only registres JavaConfig classes.
Java config
How is JavaConfig processed?
ConfigurationClassPostProcessor is used
This class monitors classpath and finds classes with @Bean
And define strategy for @Import, @ImportResource and @ComponentScan
Groovy Config
Spring 4.0 gives us new configuration fomat:
Groovy Context
import my.company.MyBeanImpl
beans = {
myBean(MyBeanImpl) {
someProperty = 42
otherProperty = "blue"
}
}
new GenericGroovyApplicationContext("context.groovy");
Uses GroovyBeanDefenitionReader
And What about Scopes?
Our favorite picture
AND WHAT ABOUT SCOPES?
AND WHAT ABOUT SCOPES?
public interface Scope {
Object get(String name, ObjectFactory objectFactory);
Object remove(String name);
/** Register a callback to be executed on destruction of the specified
* object in the scope (or at destruction of the entire scope, if the
* scope does not destroy individual objects but rather only terminates
* in its entirety).**/
void registerDestructionCallback(String name, Runnable callback);
Object resolveContextualObject(String key);
String getConversationId();
}
And what about scopes?
public class SimpleThreadScope implements Scope {
private final ThreadLocal<Map<String, Object>> threadScope = new NamedThreadLocal<Map<String, Object>>("SimpleThreadScope");
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
Map<String, Object> scope = this.threadScope.get();
Object object = scope.get(name);
if (object == null) {
object = objectFactory.getObject();
scope.put(name, object);
}
return object;
}
@Override
public Object remove(String name) {
Map<String, Object> scope = this.threadScope.get();
return scope.remove(name);
}
}
microbenchmarks
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/application-context.xml");
Message message = null;
long before = System.nanoTime();
for(int i = 0; i < 100*100*100; i++){
message= (Message)applicationContext.getBean("message");
System.out.println( message);
}
long after = System.nanoTime();
System.out.println((after-before)/1000000);
10^6 Singletons: 0,1 second
10^6 Prototypes: 5,4 seconds
MicroBenchmarks
Conclusion
-
Read frameworks documentation
-
Debug frameworks
-
Try to go under hood of framework
spring-revisited
By Yegor Bondar
spring-revisited
These slides describe main concepts of bean creation in Spring Framework
- 1,279