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;
    }
}  
Init(), afterPropertySet(), @PostConstruct are called in between

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();
} 

Example: org.springframework.context.support.SimpleThreadScope

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 
Made with Slides.com