Skip to content

Instantly share code, notes, and snippets.

@farukh-dm
Created June 18, 2020 16:13
Show Gist options
  • Select an option

  • Save farukh-dm/4417e8efc9ccff441977b090eb3d522b to your computer and use it in GitHub Desktop.

Select an option

Save farukh-dm/4417e8efc9ccff441977b090eb3d522b to your computer and use it in GitHub Desktop.
Spring is like a container of beans or factory of beans.
And you ask the container to give you what you need. Container reads from some configuration setup avaialable for it & returns thw required object.
BeanFactory will help create new objects by reading some configuration.
We can use BeanFactory object to create target objects. And as the object is created in Bean Factory, Spring handles the life cycle of the object.
spring DI
BeanFactory f = new XmlBF(new FileSystemResouce(spring.xml))
f.getBean(..)
----------------------------------
BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("C:/workspace/project/spring-demo-1/src/main/resources/spring/spring-config.xml"));
Burger burger = (Burger) beanFactory.getBean("cheeseBurger");
burger.prepare();
------------------------------------
ApplicationContext is like a big brother of beanFactory. Event notify, AOP, etc.
ApplicationContext ac = new ClasspathXmlAppContext(spring.xml)
ac.getBean()
<beans>
<bean id="abd" class="a.b.d" />
<bean id="xyz" class="a.b.c">
// /member variable / Property Injection / setter injection using set<PropertyName>() method.
<property name="variable1" value="abc"/>
// Constructor injection
<constructor-args value="test"/>
<constructor-args value="1"/>
<constructor-args index="0" value="test"/>
<constructor-args index="1" value="1"/>
<constructor-args type="java.lang.string" value="test"/>
<constructor-args type="int" value="1"/>
// object injection
<property name="variable2" ref="abd"/>
//inner bean
<property name="innerBean1"/>
<bean id="inner_abc" class="a.b.z">
<property name="variable1" value="1"/>
<property name="variable2" value="2"/>
</bean>
</property>
//idref
<property name="variable3">
<idref="someid"> // only takes id & not alias
</property>
//list
<property name="listVariable">
<list>
<ref bean="" />
<ref bean="" />...
</list>
</property>
<property name="listVariable">
<list>
<value />
<value />...
</list>
</property>
</bean>
// alias
<alias name="abc" alias-name="abc-alias" />
ac.getBean(abc-alias)
--------------
class B1
<bean name="b1" class="B">
<bean name="b2" class="B">
class A
private B b1
private B b2
<bean name="AA" class="A" autowire=byName>
</bean>
member variables with same name as beans defined above, this injected.
autowire=byType works if their is only one bean define of type.
autowire=constructor, one bean per type
default = autowire is off
------------------------
scope:
singlton(initialized by spring when spring container gets initialized)
prototype: created when requested(.getBean)
Web aware context:
Request: per request
session: user session
global: portlets
<bean name="b1" class="B" scope=prototype">
---------------------------
ApplicationContextAware:
BeanNameAware - To know name of the bean set in the config.
class A implements ApplicationContextAware, BeanNameAware
private ApplicationContext appContext;
// will be called by spring
public void setApplicationContext(ApplicationContext context) {
this.appContext = context
}
public void setBeanName(String beanName) {
print(beanName);
}
------------------------
Bean Definition inheritance:
<bean name="b1" class="B">
<property name="b_1" value="1">
</bean>
<bean name="b2" class="B" parent="b1">
<property name="b_2" value="2"> <!-- Additional Property -->
</bean>
<bean name="b3" class="B" parent="b2">
<property name="b_3" value="3">
</bean>
<bean name="b1" class="B" abstract="true">...</bean>
<bean name="b2" class="B" parent="b1" >...</bean>
overrides common properties
abstract="true" => initialization will not happen, its just like a template
-------------------------------------------------
callbacks:
For spring web applicaion, it know when to end the spring container. NO explicit registerShutDownHook is required.
Butin case of desktop app, it is required.
AbstractApplicationContext ac = new ClasspathXmlAppContext(spring.xml)
ac.registerShutDownHook(); //for spring to shupdown itself when program ends.
class A implements initializingBean, DisposableBean {
public void afterPropertiesSet() {}
public void destroy() {}
}
<bean name="a" class="A" init-method="init" destroy-method="destroy" />
class A {
public void init() {}
public void destroy() {}
}
DEFAULT INIT METHOD:-
<beans default-init-method="init" default-destroy-method="destroy">
<bean>..
...
</beans>
ignores if bean does not define it.
-----------------------------------------------------
BeanPostProcessor: classes that informs spring needs to use after initializing bean. Called for all beans.
class ABC implements BeanPostProcessor {
public object postProcessAfterInitilization(object bean, string name) {
return object;
}
public object postProcessBeforeInitilization(object bean, string name) {
return object;
}
<bean class=ABC />
}
------------------------------------------------
BeanFactoryPostProcessor: Some code you want to run when Spring's bean factory itself gets initialized.
class ABS implements BeanFactoryPostProcessor {
public void postProcessorBeanFactory( ) {
return object;
}
<bean class=ABC />
===========================
PropertyPlaceHolderConfigurer -> is an example of BeanFactoryPostProcessor
PropertyPlaceHolderConfigurer: bean factory post processor provided by spring.
demo.properties
a.val=1
b.val=2
<bean class="org.spring...PropertPlaceHolderConfigurer" >
<property name="location" value="classpath:demo.properties" />
</bean>
<bean ...>
<property name=a value="${a.val}" />
<property name=b value="${b.val}" />
}
--------------------------------------------
@Required annotation: It's like a bean post processor that run after beans are initialized to check if required annotations are also initialized.
class A {
private B b;
@Required
public void setB() {
}
...
}
In order to make @required to work, we need to add a PostProcessor bean.
<bean class="org.springframework.bean.factory.annotation.RequiredAnnotationBeanPostProcessor" /> - This checks for annotations
If bean is not available, error will be caught up during bean initialization/creation phase itself.
------------------------------------------------
@Autowire annotation: Default is by type, then name
class A {
private B b;
@Autowire
public void setB() {
}
...
}
<bean class="A" id=".." />
<bean class="org.springframework.bean.factory.annotation.AutowiredAnnotationBeanPostProcessor" /> - This checks for annotations
=================================
@Autowire
@Qualifier("bb")
public void setB() {..}
<bean class="B" id="...">
<qualifier value="bb" />
</bean>
<bean class="org.springframework.bean.factory.annotation.AutowiredAnnotationBeanPostProcessor" /> - This checks for annotations
Instead of adding individual annotations bean we can use: for defining all bean post processor tags
<context: annotation-config />
------------------------------------------------------------------------
JSR annotation: standard java specification request that defines standard annotation that applies across different frameworks.
Spring supports some of JSR annotations.
@Resource(name="bb") // javax.annotation. Looks for a bean named bb and inject that.
public void setB() {..} // default search by name of the member variable if "name" is not provided.
@PostConstruct // => initializingBean
public void initBean() {..}
@PreDestroy(name="bb") // => DisposableBean
public void destroyBean() {..}
-----------------------------------------------------------------------------
@Component => <bean id=".." class=".." />
@Component tells spring that a particular class to used as a bean.
Also, tell spring that there are beans inside code & tell it to look for them using below scan line:
<context:component-scan base-package="" />
Stereotypes annotation = @controller, @Service, @Repository
------------------------------------------
MessageSource:
mymessagefile.properties
home=Hello
paramMsg=Test {0} & (1)
<bean id="messageSource" class="ResourceBundleMessageSource" >
<property name="basenames
<list>
<value>mymessagefile</value>
</list>
</property
</bean>
context.getMessage("home", null, null, null);
OR
@Autowired
private MessageSource messageSource;
private setMessageSource() {...}
this.messageSource.getMessage("home", null, null, null);
this.messageSource.getMessage("home", new Obhect[] {1, 2}, null, null);
mymessagefile_EN.properties
this.messageSource.getMessage("home", null, null, "EN");
-----------------------------------------------------------
Events:
@Component
class MyEventListener implements ApplicationEventListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
sysout(event.toString());
}
}
custom event:
class FoodPreparedEvent extends ApplicationEvent {
public FoodPreparedEvent(Object source) {
super(source);
// TODO Auto-generated constructor stub
}
public void toString() {
sysout("Food Prepared")
}
}
class M implements ApplicationEventPublisherAware {
private ApplicationEventPublisher publisher;
somemethod() {
FoodPreparedEvent event = new FoodPreparedEvent();
publisher.publishEvent(event)
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
}
----------------
In Java: run program to with:
System.setProperty("javax.net.debug", "ssl");
If you are trying to create an SSL connection to a server that doesn't have an official ssl certificate.
You can work around this by importing the servers certificate into the java cert store.
ssh://git@cedt-bitbucketcli.nam.nsroot.net:7999/maphub/main.git
git clone --depth 1 ssh://git@cedt-bitbucketcli.nam.nsroot.net:7999/maphub/main.git
----------------------------
Spring MVC:
-----------
in servlet (controller) -> jsp (view) define url mapping in web.xml
Similarly, instead of multiple servlets we define one front controller called dispatcher servlet(spring) that will take all requests.
then in spring we make controller using annotation @Controller.
controller will return data back to dispatcher & dispatcher will provide data to view & return the response.
Client request -> Front Controller/Dispatcher Servlet ---> handler mapping: to find controller for URL ---> Controller -> back to Dispatcher Servlet -->
--> View Resolver to find view -> View -> Form response & send back to dispatcher -> return to client
How to create web mvc:
1. add dispatcher in web.xml
2. create <servlet name>-servlet.xml . dispatcher looks for config file using this naming convention.
3. Eg: demo-servlet.xml
<context:property-placeholder location="classpath:applicationContext.properties" /> if any
<mvc:annotation-driven enable-matrix-variables="true">
<mvc:message-converters>
jackson..
</..>
</annotation>
<context:component-scan base-package="com.group.project">
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass">
<value>
org.springframework.web.servlet.view.tiles3.TilesView
</value>
</property>
</bean>
<mvc:interceptors>
<bean
class="com.group.project.vicdw.common.controller.SessionValidatorInterceptor">
</bean>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />
-----------------
mvc app using config file:
MyDemoAppConfig.java
@Configuration
@ComponentScan({ "com.demo.app"})
class MyDemoAppConfig {
@Bean
public InternalViewResolver viewResolver()
//InternalViewResolver vr = new InternalViewResolver();
InternalResourceViewResolver view = new InternalResourceViewResolver();
vr.setPrefix("/WEB_INF");
vr.setSuffix("/.jsp");
}
}
we can also replace web.xml with class
MyWebDotXmlInitializer.java
class MyWebDotXmlInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
getRootConfigClasses() {}
getServletConfigClasses() {
return new Class[] { MyDemoAppConfig.class };
}
getServletMappings() {
return new String[] { "/" };
}
}
---------------------
Spring webmvc config java class
@Configuration
@EnableMvc
@ComponentScan({ "com.demo.app"})
class MyMvcDemoApp extends WebMvcConfigurerAdapter{
}
class MyWebDotXmlInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
getRootConfigClasses() {
return new Class[] { MyMvcDemoApp.class };
}
getServletConfigClasses() { }
getServletMappings() {
return new String[] { "/" };
}
}
---------------------------------------
@ModelAttribute on a method
@Controller
class DemoController {
// This will be available in all methods of this controller + its JSP.
@ModelAttribute
public void addCommonAttributesToModel(Model model1) {
model1.addAttribute("headerName", "DEMP APP");
}
}
-----------------------------------
Data mapping with @ModelAttribute
<form>
input name="address.line1"
input name="address.line2"
</form>
class user {
private Address address
}
class Address {
private String line1;
private String line2;
}
-------------------------------
BindingResult:
class user {
private Integer age; // "ABC" => Data Binding Error
}
public ModelAndView add(@ModelAttribute("userForm") User user, BindingResult result) {
if(result.hasError()) {
return new ModelAndView("add.jsp");
}
}
add.jsp:
use below from taglib
<form:errors path="userForm.*"
-------------------------------------------------
initBinder:
@controller
class C
@InitiBinder
p v anyName(WebDataBinder binder) {
// stop default binding
binder.setDisallowedFields(new String[] { "someFieldName"});
// Custom date field binding.
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd h:m a");
binder.registerCustomEditor(Date.class, "someDateField", new CustomDateEditor(dateFormat, false));
}
}
Writing your own editor by extending built-in property editor for different data types
class MyFieldEditor extends PropertyEditorSupport {
@Override
public String getAsText() {
// do your update
return super.getAsText();
}
// when we submit data, sprign will call setAsText
@Override
public void setAsText(String text) throws IllegalArgumentException {
// do your update
setValue(text);
}
}
and then in the initbinder method:
binder.registerCustomEditor(Date.class, "someField", new MyFieldEditor());
------------------------
Form validation using JSR:
include 3rd part jsr library: hibernate validator
Class User {
@Size(min=2, max=10)
private Integer phone
}
public ModelAndView add(@valid @ModelAttribute("userForm") User user, BindingResult result) {
if(result.hasError()) {
return new ModelAndView("add.jsp");
}
}
Class User {
@Size(min=2, max=10, message="Plz enter between 2-10")
private Integer phone
}
Class User {
@Size(min=2, max=10, message="Plz enter between {min}-{max}")
private Integer phone
@Pattern(regexp="..")
private String name
@Past
private Date dateOfBirth
}
Customize error message using MessageSource:
========================
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="WEB-INF/messages/projectMessages" />
<property name="basenames">
<list>
<value>classpath:messages/AppMessages</value>
<value>classpath:messages/AppErrorMessages</value>
</list>
</property>
<property name="defaultEncoding" value="UTF-8" />
</bean>
AppErrorMessages.properties:
Size.phone = Plz enter between {1}-{2}
Spring will search for Size.attributeName in message source.
Custom validation annotation: TODO
=====================
--------------------------------------
INTERCEPTOR
Create a class that extends HandlerInterceptorAdapter & override preHandle() & add entry in xml config file.
<mvc:interceptors>
<bean class="com.group.project.vicdw.common.controller.SessionValidatorInterceptor" />
</mvc:interceptors>
public class SessionValidatorInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
UserAccessBean user = (UserAccessBean) session.getAttribute(USER_BEAN_IN_SESSION);
response.getWriter().write("error message") // or any other form of response
OR
response.sendRedirect(URL);
OR
resp.setHeader("redirectToLogin", "true");
response.sendError(901);
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// called after controller method
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// called after view data got created.
}
}
----------------------------------------------------------
INTERNATIONALIZATION
(1)
mymessagefile_EN.properties
field1.label=Name
field2.label=Age
JSP:
<form>
<label><spring:message code="field1.label" />
(2)
url?siteName=FR
Interceptor: LocaleChangeInterceptor
<mvc:interceptors>
<property name="paramName" value="siteName" />
</mvc:interceptors>
<bean id="localResolver" class="...CookieLocaleResolver" />
-----------------------------------------
EXCEPTIONS
in controller class add a method with annotation @ExceptionHandler(<Exception>.class)
class AController {
@ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(RuntimeException.class)
public String ExceptionHandlerMethod(RuntimeException runEx) {
...
return RuntimeException; // => RuntimeException.jsp is rendered.
}
}
-------------------------------------------------------------
JSON RESPONSE:
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties({"createdAt"})
@JsonPropertyOrder({"student_name", "age", "address"}) //order of json attributes
class User {
@JsonProperty("student_name") // will be sent as key in JSON response.
private String name;
private address;
private Integer age;
private String createdAt;
}
-----------------------------
PATH VARIABLE
@RequestMapping(value = "/action/{do_action}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ResponseDTO<Void>> do_action(
@RequestBody RequestDTO<MyDto, Void> request,
@PathVariable("do_action") String do_action,
HttpSession session) throws IOException, ApplicationException {
return ....;
}
----------------------------------
RESPONSE TYPE:
is based on header "ACCEPT".
Value can be "application/json", "application/xml"
& jackson library will accordingly send response
@RequestMapping -> "Produces" forces a response to be of specific type.
REQUEST TYPE:
Header "content-Type": application/json => information in the body is of type json {....}
@RequestMapping -> "Consumes" forces a request of specific type to be processed.
CUSTOM HEADERS:
org.springframework.http.HttpHeaders h = new org.springframework.http.HttpHeaders();
h.add(headerName, headerValue);
add as an argument to new ResponseEntity instance
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment