Introduction to Spring (part 2) Matt Wheeler
Notes This is a training NOT a presentation Please ask questions Prerequisites – Introduction to Java Stack – Basic Java and XML skills – Introduction to Spring (part 1) – Installed LdsTech IDE (or other equivalent)
Review Last time we went over – Bean definitions – Dependency Injection (DI) and Inversion of Control (IoC) – Application context – Bean scopes
Review ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); SomeBean someBean = context.getBean(SomeBean.class); someBean.callMethod(); Bean definition (beans.xml) Application Context
Overview Bean lifecycle XML Schema-based configuration (namespace handlers) Lifecycle hooks Bean Initialization (JSR …) Bean post processors Component scanning Spring Component Annotations DI Annotations
Spring Bean Lifecycle 1. Bean definitions created/registered (from xml or annotations, or, …) 2. Beans instantiated using the definitions 3. Dependencies set (values and bean references) on the newly instantiated beans 4. Bean initialization 5. Beans delivered to requester for use 6. Destruction callback method called at container shutdown
XML Schema-based configuration Also called namespace handlers Shorten bean definition configuration Provide easily reusable definitions Self documenting More readable NOTE: Takes place in the first phase of the bean lifecycle (i.e. while xml files are being parsed)
XML Schema-based configuration Example namespace handler Basically equivalent configuration
Wait that’s not all And this
Another Example Utilizing a namespace handler <beans xmlns=" xmlns:xsi=" xmlns:util=" xsi:schemaLocation=" abc def ghi jkl abc def ghi jkl
Demo DEMO
Spring XML Schema-based configurations SchemaDescription / Documentation utilCreate non-anonymous collection types that can be referenced by id reference/html/xsd-config.html#xsd-config-body-schemas-util jeeElements such as jndi support / ejb shortcuts reference/html/xsd-config.html#xsd-config-body-schemas-jee langExpose beans written in another language like JRuby or Groovy reference/html/xsd-config.html#xsd-config-body-schemas-lang jmsDeal with configuring JMS-related beans reference/html/xsd-config.html# xsd-config-body-schemas-jms txTransaction support reference/html/xsd-config.html# xsd-config-body-schemas-tx
XML Schema-based configuration (cont.) SchemaDescription / Documentation aopHelpers for Spring’s aspect oriented programming mechanisms reference/html/xsd-config.html# xsd-config-body-schemas-aop contextConfiguration related to the application context plumbing reference/html/xsd-config.html# xsd-config-body-schemas-context toolsConfiguration for adding tooling specific meta-data reference/html/xsd-config.html# xsd-config-body-schemas-tool securityProvides elements for web security configuration config.html mvcProvides interceptors, view-controller, ….. reference/html/mvc.html#mvc-config
XML Schema-based configuration arch. Parts of XML Schema-based configuration – Xml schema that describes allowable elements – Namespace handler (Java code) – BeanDefinitionParser (Java code) Parses the defined xml and adds any necessary beans into the configuration Bottom line – Namespace handlers are backed by code The code supplements bean configuration and is often a lot more than meets the eye
Bean Definition Parsers Let’s look at an example public class SomeBeanDefinitionParser implements BeanDefinitionParser { public AbstractBeanDefinition parse(Element element, ParserContext parserContext) { CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element)); parserContext.pushContainingComponent(compositeDef); BeanDefinitionBuilder someBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(SomeBean.class); if (Boolean.parseBoolean(element.getAttribute("some-attribute"))) { SomeBeanDefinition.addPropertyValue("someProperty", "abc"); } …
Lab 1: XML Schema-based configuration ontinued#Lab_1_Xml_Schema- based_configuration
Bean Initialization (JSR 250)
Spring Bean Lifecycle 1. Bean definitions created/registered (from xml or annotations, or, …) 2. Beans instantiated using the definitions 3. Dependencies set (values and bean references) on the newly instantiated beans 4. Bean initialization 5. Beans delivered to requester for use 6. Destruction callback method called at container shutdown
Hooking into the Lifecycle Assume the following class Define init-method to be called The init method is called after the bean has been initialized and all properties set public class SomeBean { public void init() { //some initialization code }
Jar Dependency JSR 250 Annotation Dependency (only required in Java 1.5) javax.annotation jsr250-api 1.0
JSR 250 Common Annotations The goal of JSR 250 was to come up with a standard set of annotations to accomplish common use cases in Java The annotations are outlined here: We will only be focusing on a tiny subset of these annotations in order to replace our init-method functionality
Annotate the Class JSR 250 annotations annotation for bean initialization There is likewise counterpart – Called just before the bean is destroyed – Allows for cleanup of resources public class SomeBean public void init() { // do some initialization work }
Configure Annotation Handling Specify annotation handlers (bean post processors) <beans xmlns=" xmlns:xsi=" xsi:schemaLocation=" <beans xmlns=" xmlns:xsi= xmlns:context= xsi:schemaLocation="
Lab 2: JSR 250 Annotations ontinued#Lab_2_JSR_250_Annotations
Spring Component Annotations We have seen how to use annotations to call an init method during initialization Wouldn’t it be nice if didn’t need to define even the beans themselves in xml at all? – We will need something to scan the classes for annotations and register bean definitions
Welcome component-scan component-scan element in context schema – Scans classpath searching for matching beans Registers bean definitions for matching classes – Can specify an include filter and/or exclude filter You can also assign a filter type for a targeted search – framework-reference/html/beans.html#beans-scanning-filters – annotation – assignable – regex – custom
Bean Lifecycle and Component Scan 1. Create bean definitions (from xml or annotations, or, …) 2. Instantiate beans using the definitions 3. Set bean dependencies (values and bean references) on the newly instantiated beans 4. Initialization 5. Deliver bean to requester for use 6. On container shutdown call destruction callback method
For Example This configuration will (for the given packages): – Register bean definitions for all classes with “abc” in their names – Not register beans for any classes that extend / implement Animal <beans xmlns=" xmlns:xsi=" xmlns:context=" xsi:schemaLocation="
Naming What id will be given for beans that are registered By default it is the class name with the first letter lower cased – For example, the following will result in a bean definition with public class Rabbit { }
Naming What id will be given for beans that are registered? By default it is the class name with the first letter lower cased – For example, a class named Rabbit would result in a bean definition with id=“rabbit” – Package is dropped from the name
Annotation Scanning What do we do if: – The default naming is not acceptable – Difficult to come up with a pattern that matches only the beans that we want registered with Spring – What if we don’t want scope of singleton We can employ annotations and only register definitions for classes that are appropriately annotated
Spring Component Annotations Spring provides stereotype annotations to identify a bean’s role in the app. architecture – denotes application services – denotes view layer components – the most general stereotype annotation – denotes any class to be managed by Spring – most often used to demarcate DAOs – You can also create your own custom stereotype annotations
For Example In a given application context you may want to have the scanner selectively register definitions – Register beans annotated with your custom annotation – Once include is specified defaults are disabled <beans xmlns=" xmlns:xsi=" xmlns:context=" xsi:schemaLocation="
Naming So how does annotation scanning help naming? – The following will still register a bean with id=“rabbit” – But, this will register a bean with id=“crazyRabbit” – I.e. the annotations allow you to provide a specific name for the given bean to the bean definition public class Rabbit { public class Rabbit { }
The Main Point All this to tell you that now you can create a bean automatically without defining it in xml That is to say, the following are basically equivalent in public class SomeBean { }
Scope But what about scope – What is the equivalent annotation for specifying a scope of prototype
@Scope Be sure to use org.springframework.context.annotation.Scope – Not javax.inject.Scope Possible values:
Putting it all together Xml definition Equivalent public class Turkey { }
Lab 3: Spring Component Annotations ontinued#Lab_3_Spring_Component_Annotation s
JSR 330 Annotations (DI) Now that we can create bean definitions how do we specify injection
Dependency JSR 330 annotations require you to include the following dependency: – Don’t be alarmed by the unorthodox version value It is correct as of this writing javax.inject 1
Dependency Injection Annotations To inject beans we have the following new annotations – inject bean references by type – modify injection by providing a name
can be used almost anywhere //on a member private Rabbit rabbit; //on a public Farm(Rabbit prizeRabbit) {…} //on a setter public void setPrizeRabbit(Rabbit rabbit) { this.rabbit = rabbit; } //if you can’t inject all of them by type you could to narrow to a single public void anyMethod(Chicken Rabbit rabbit, Duck duck) { … } //on collections (will inject all beans in the application context of the specified private Rabbit[] private List rabbits; //will contain all beans with the given type and the bean name as the private Map rabbits;
@Inject (cont) By default injection injects by type – Finds any registered instances of the type for the annotated type What if you have two targets of the same type? – You can specify by name – Downside is that this is no longer type safe Only referenced by a String Could employ a Qualifier to remain type safe private Rabbit prizeRabbit;
Putting it all together Xml definition Somewhat equivalent annotation public class Turkey { … billysFarm ") public class Farm { private Turkey public Farm(Turkey turkey) { this.turkey = turkey; }
DEMO ??? Assume the following configuration Now say I wanted to get rid of the chicken declaration Remove the chicken xml declaration Remove the farm xml declaration Assume the following configuration Of course our farm would look something like this: public class Farm { private Chicken chicken; public void setChicken(Chicken chicken) { this.chicken = chicken; } … }
Lab 4: JSR 330 (DI) Annotations ontinued#Lab_4_JSR_330_Annotations
Credit where credit is due Spring Recipies 2 nd Edition (Gary Mak, Josh Long and Daniel Rubio)