430 likes | 525 Views
Intermediate Spring. Matt Wheeler. Notes. This is a training NOT a presentation Please ask questions Prerequisites Introduction to Java Stack Basic Java and XML skills Installed LdsTech IDE (or other equivalent – good luck there ;). Overview. Bean lifecycle
E N D
Intermediate Spring Matt Wheeler
Notes • This is a training NOT a presentation • Please ask questions • Prerequisites • Introduction to Java Stack • Basic Java and XML skills • Installed LdsTech IDE (or other equivalent – good luck there ;)
Overview • Bean lifecycle • Xml Configuration Extensions (namespace handlers) • Lifecycle hooks • JSR 250 • Bean post processors • Spring Annotations • JSR 330 Annotations (@Inject, @Named)
Review • Last time we went over • Bean definitions • Dependency Injection (DI) and Inversion of Control (IoC) • Application context • Bean scopes
Review • Bean definition (beans.xml) <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean class="org.lds.training.SomeBean" /> </beans> • Application Context ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); SomeBeansomeBean = context.getBean(SomeBean.class); someBean.callMethod();
Spring Bean Lifecycle 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
Xml Configuration Extension • Also called namespace handlers • Shorten bean definition configuration • Provide easily reusable definitions • Self documenting • More readable
Example • You have options • Or <mvc:annotation-driven validator="validator" /> <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"> <property name="order" value="0"/> <property name="useDefaultSuffixPattern" value="false"></property> </bean> <bean class="org.springframework.web.servlet.handler.MappedInterceptor"> <constructor-arg value="null"></constructor-arg> <constructor-arg> <bean class="org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor"> <constructor-arg> <bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean"></bean> </constructor-arg> </bean> </constructor-arg> </bean>
Wait that’s not all And this <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="webBindingInitializer"> <bean id="webBindingInitializer" class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer"> <property name="validator" ref="validator" /> <property name="conversionService"> <bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean" /> </property> </bean> </property> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"></bean> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="writeAcceptCharset" value="false" /> </bean> <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"></bean> <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"></bean> <bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"></bean> <bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"></bean> <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean> </list> </property> </bean>
Another Example • Let us utilize a namespace handler <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"> <!-- definitions here --> </beans> <!-- creates a java.util.List instance with the supplied values --> <util:list id="alphaGroups"> <value>abc</value> <value>def</value> <value>ghi</value> <value>jkl</value> </util:list> <bean id="alphaGroups" class="org.springframework.beans.factory.config.ListFactoryBean"> <property name="sourceList"> <list> <value>abc</value> <value>def</value> <value>ghi</value> <value>jkl</value> </list> </property> </bean>
Xml Configuration Extension architecture • Pieces of namespace handlers • Create an xml schema that describes allowable elements • Write a namespace handler • Code a BeanDefinitionParser • Parses the defined xml and adds any necessary beans into the configuration
For Example Add a parser example here • Bottom line • Namespace handlers are backed by code • The code supplements bean configuration and is a lot more than meets the eye
Lab 1: Xml Configuration Extensions https://tech.lds.org/wiki/Intermediate_Spring#Lab_1_Xml_Configuration_Extensions
JSR 250 (Common) Annotations • JSR 250 provides many annotations for common use cases in Java
Hooking into the Lifecycle • Define init-method in bean definition • The associated bean • The init method is called after the bean had been initialized an all properties set <bean id="whatever"init-method="init"class="org.lds.training.SomeBean"/> public class SomeBean{ public void init() { //some initialization code } }
Spring Bean Lifecycle Review 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
Annotate the Class • JSR 250 annotations provides @PostConstruct annotation for bean initialization • There is likewise an @PreDestroy counterpart • Called just before the bean is destroyed • Allows for cleanup of resources public class SomeBean { @PostConstruct public void init() { // do some initialization work } }
Configure Annotation Handling • Specify annotation handlers (bean post processors) <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" /> </beans> <!– or --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xmlns:context=http://www.springframework.org/schema/context xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:annotation-config/> </beans>
Lab 2: JSR 250 Annotations https://tech.lds.org/wiki/Intermediate_Spring#Lab_2_JSR_250_Annotations
Spring 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 matching classes • Can specify an include filter and/or exclude filter • You can also assign a filter type for a targeted search • http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-scanning-filters • annotation • assignable • aspectj • regex • cutsom
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="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="org.lds.training,org.lds.another"> <context:include-filter expression="org\.lds\.training\..*abc.*" type="regex"/> <context:exclude-filter expression=“org.lds.training.Animal" type="assignable"/> </context:component-scan> </beans>
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”
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 • Annotation scanning
Spring Annotations • Spring provides stereotype annotations to help identify a bean’s role the application architecture • @Service – denotes application services • @Controller – denotes a view layer components • @Component – the most general stereotype annotation – denotes any class to be managed by Spring • @Repositoy – 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 • Register beans annotated with your custom annotation • But not register definitions for beans annotated with @Service <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="org.lds.training"> <context:include-filter expression="org.lds.training.Custom" type="annotation"/> <context:exclude-filter expression="org.springframework.stereotype.Service" type="annotation"/> </context:component-scan> </beans>
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” @Component public class Rabbit { } @Component("crazyRabbit") 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 function <bean id="something" class="org.lds.training.SomeBean" /> @Component("something") public class SomeBean { }
Scope • But what about scope • i.e. what is the equivalent annotation for specifying a scope of prototype • @Scope("prototype") <bean id="something" class="org.lds.training.SomeBean" scope="prototype"/>
@Scope • Be sure to use org.springframework.context.annotation.Scope • Not javax.inject.Scope • Possible values: • @Scope or @Scope("singleton") • @Scope("prototype") • @Scope("request") • @Scope("session") • @Scope("globalSession")
Putting it all together • Xml definition • Equivalent annotation definition <bean id="turkey" class="org.lds.training.Turkey" scope="prototype"> @Component @Scope("prototype") public class Turkey { }
Lab 3: Spring Annotations https://tech.lds.org/wiki/Intermediate_Spring#Lab_3_Spring_Annotations
JSR 330 Annotations (DI) • Now that we can create bean definitions from annotations we probably would like to be able to inject one bean into another
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 <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency>
Dependency Injection Annotations • To inject beans we have the following new annotations • @Inject – inject bean references by type • @Named – modify injection by providing a name • @Inject is similar to specifying the following in a bean definition file <constructor-argref="rabbit"/> <!– or --> <property name="prizeRabbit" ref="rabbit"/>
@Inject • @Inject can be used almost anywhere //on a member variable @Inject private Rabbit rabbit; //on a constructor @Inject public Farm(Rabbit prizeRabbit) {…} //on a setter method @Inject public void setPrizeRabbit(Rabbit rabbit) { this.rabbit= rabbit; } //if you can’t inject all of them by type you could use @Named to narrow to a single match @Inject public void anyMethod(Chicken chicken, @Named("prototypeRabbit") Rabbit rabbit, Duck duck) { … } //on collections (will inject all beans in the application context of the specified type) @Inject private Rabbit[] rabbits; @Inject private List<Rabbit> rabbits; //will contain all beans with the given type and the bean name as the key @Inject private Map<String, Rabbit> rabbits;
@Inject (cont) • By default injection injects by type • Finds any declared instances of the type for the annotated entity • 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 • http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-autowired-annotation-qualifiers @Inject @Named("prototypeRabbit") private Rabbit prizeRabbit;
Putting it all together • Xml definition • Equivalent annotation definition <bean id="billysFarm" class="org.lds.training.Farm"> <constructor-argname="turkey" ref="turkey"/> </bean> @Component public class Turkey { … } @Component(" billysFarm ") public class Farm { private Turkey turkey; @Inject public Farm(Turkey turkey) { this.turkey= turkey; } }
Credit where credit is due • http://springsource.org • Spring Recipies 2nd Edition (Gary Mak, Josh Long and Daniel Rubio)