Spring employs four
key strategies:
- ¡
Lightweight
and minimally invasive development with plain old Java objects (POJOs)
- ¡
Loose
coupling through dependency injection and interface orientation
- ¡
Declarative
programming through aspects and common conventions
- ¡
Boilerplate
reduction through aspects and templates
The objects that form the backbone of
your application and that are managed by the Spring IoC container are
called beans. A bean is an object that is instantiated, assembled,
and otherwise managed by a Spring IoC container.
POJO
Injection of dependencies
The act of
creating associations between application components is the essence of
dependency injection (DI) and is commonly
referred to as wiring.
AOP:
Aspect-oriented
programming is often defined as a technique that promotes separation of
concerns within a software system.
System services
such as logging, transaction management, and security often find their way into
components whose core responsibility is something else. These system services
are commonly referred to as cross-cutting concerns because they
tend to cut across multiple components in a system.
In Spring, aspects are woven into
Spring-managed beans at runtime by wrapping them with a proxy class. The proxy
class poses as the target bean, intercepting advised method calls and forwarding
those calls to the target bean. Between the time when the proxy intercepts the
method call and the time when it invokes the target bean's method, the proxy
performs the aspect logic.
Container:
Spring comes with
several container implementations that can be categorized into two distinct
types. Bean factories (defined by the org.springframework.beans.factory.BeanFactory interface) are the
simplest of containers, providing basic support for DI. Application
contexts (defined by the org.springframework.context.ApplicationContext interface) build on
the notion of a bean factory by providing application framework services, such
as the ability to resolve textual messages from a properties file and the ability
to publish application events to interested event listeners.
The ApplicationContext container
includes all functionality of the BeanFactorycontainer, so it is
generally recommended over BeanFactory. BeanFactory can still be
used for lightweight applications like mobile devices or applet-based
applications where data volume and speed is significant.
Spring comes with
several flavors of application context. The three that you’ll most likely
encounter are
¡ ClassPathXmlApplicationContext—Loads a context
definition from an XML file located in the
classpath, treating context definition files as classpath resources.
¡ FileSystemXmlApplicationContext—Loads a context
definition from an XML file in the file
system.
¡ XmlWebApplicationContext—Loads context definitions from an XML file contained within a web application.
Annotations:
@SpringBootApplication is the combination of @Configuration, @EnableAutoConfiguration and @ComponentScan annotations.
@RestController annotation
in Spring MVC is nothing but a combination of @Controller and @ResponseBody annotation.
Read more: https://javarevisited.blogspot.com/2017/08/difference-between-restcontroller-and-controller-annotations-spring-mvc-rest.html#ixzz5hLnDcXlY
Read more: https://javarevisited.blogspot.com/2017/08/difference-between-restcontroller-and-controller-annotations-spring-mvc-rest.html#ixzz5hLnDcXlY
Common application
properties:
Spring Boot
Make Spring coding easier.
·
AutoConfiguration
·
Spring Boot Starters
How to create Spring Boot cloud bootstrapping:
Spring Boot, Nginx and Docker:
Spring cloud vs. Kubernetes:
Combine them:
Develop a Spring Boot application for Kubernetes:
Spring Boot for GAE Standard: see “Google Cloud Platform.pdf”
application.properties file:
Read properties from application.properties:
public class DemoApplication {
@Value("${spring.application.name}")
private String name;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@RequestMapping(value = "/")
public String name() {
return name;
}
}
Enable DEBUG in application.properties:
#show
sql statement
logging.level.org.hibernate.SQL=debug
#show sql values
logging.level.org.hibernate.type.descriptor.sql=trace
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=DEBUG
logging.level.org.hibernate.SQL=debug
#show sql values
logging.level.org.hibernate.type.descriptor.sql=trace
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=DEBUG
Important:
Always run ‘mvn clean’ if you
change the dependencies in pom.xml
AOP in Spring Boot:
Add following into pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
Add following annotation to
Spring application:
@SpringBootApplication
@EnableAspectJAutoProxy(proxyTargetClass=true)
public class SpringBootHelloWorldApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootHelloWorldApplication.class, args);
}
}
Add AccessAspect.java:
package com.example.demoGAESpringBoot2; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Aspect @Component public class AccessAspect { @Before(value = "execution(* com.example.demoGAESpringBoot2.DemoGaeSpringBoot2Application.addUser(..))") public void beforeAdvice(JoinPoint joinPoint) { System.out.println("Before method:" + joinPoint.getSignature()); } @After(value = "execution(* com.example.demoGAESpringBoot2.DemoGaeSpringBoot2Application.addUser(..))") public void afterAdvice(JoinPoint joinPoint) { System.out.println("After method:" + joinPoint.getSignature()); } @Around(value = "execution(* com.example.demoGAESpringBoot2.DemoGaeSpringBoot2Application.addUser(..))") public Object wrapResponse(ProceedingJoinPoint joinPoint) { StringBuilder str = new StringBuilder(); str.append("Do decorations from Aspect class " + this.getClass().getCanonicalName()); str.append("\n"); str.append("The result from " + joinPoint.getSignature() + " is: \n"); try { long start = System.currentTimeMillis(); Object returnValue = joinPoint.proceed(); if (!(returnValue instanceof String)) return returnValue; str.append(returnValue); str.append("\n"); str.append("Execution time is " + (System.currentTimeMillis() - start) + " ms."); } catch (Throwable e) { return e.toString(); } return str.toString(); } }
You define an expression that matches (like a
regular expression matches) points in the code. These points are called join points,
while the expressions that match them are called pointcuts. You can then opt to execute additional,
arbitrary code, called advice, when any pointcut or combination of
pointcuts are matched. An object that defines pointcuts and advice is called
an aspect.
Good website about
AOP:
The technologies to
implement AOP: AOP is proxy-based.
·
JDK Dynamic Proxy: for the classes with
interface
·
CGLib (and javassist): for the classes without
interface
Websocket support:
This is outdated:
This is explained here:
HTTP is used only for the initial
handshake, which relies on a mechanism built into HTTP to request a protocol
upgrade (or in this case a protocol switch) to which the server can respond
with HTTP status 101 (switching protocols) if it agrees. Assuming the handshake
succeeds the TCP socket underlying the HTTP upgrade request remains open and
both client and server can use it to send messages to each other.
The Spring Framework provides such
transparent fallback options based on the SockJS protocol.
SockJS consists of:
· The SockJS JavaScript client -
a client library for use in browsers.
· SockJS server implementations including one in the Spring
Framework
spring-websocket
module.
· As of 4.1
spring-websocket
also provides a SockJS Java client.
SockJS is designed for use in browsers. It goes to
great lengths to support a wide range of browser versions using a variety of
techniques. For the full list of SockJS transport types and browsers see
the SockJS client page. Transports fall in 3
general categories: WebSocket, HTTP Streaming, and HTTP Long Polling.
WebSocket RFC defines the use of sub-protocols. During the handshake, the client and server can use the
header
Sec-WebSocket-Protocol
to agree on a sub-protocol, i.e. a higher,
application-level protocol to use. The use of a sub-protocol is not required,
but even if not used, applications will still need to choose a message format
that both the client and server can understand. That format can be custom,
framework-specific, or a standard messaging protocol.
The Spring Framework provides support for
using STOMP — a simple, messaging protocol originally created for use in
scripting languages with frames inspired by HTTP.
Add following into pom.xml:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> <version>2.1.2.RELEASE</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>webjars-locator</artifactId> <version>0.30</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>webjars-locator-core</artifactId> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>sockjs-client</artifactId> <version>1.0.2</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>stomp-websocket</artifactId> <version>2.3.3</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>bootstrap</artifactId> <version>3.3.7</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.1.0</version> </dependency>
Also, need to add following repo so we can find javascript
dependencies:
<repository> <id>central</id> <name>Maven Repository Switchboard</name> <layout>default</layout> <url>http://repo1.maven.org/maven2</url> <snapshots> <enabled>false</enabled> </snapshots> </repository>
GAE flexible’s support to WebSocket is still beta. GAE standard’s support is 1 year later (as 2/28/2019):
Following website shows how load balance impacts WebSocket:
Examples of
WebSocket:
Java Servlet on server side:
org.eclipse.jetty.websocket.api.WebSocketAdapter
WebSocketAdapter.onWebSocketText(message); logger.fine("Received message: " + message);
// echo message back to client WebSocketAdapter.getRemote().sendString(message);
(not use Spring)
javascript in JSP:
var websocket = new WebSocket(webSocketUri);
(not use STOMP)
Works when “mvn appengine:deploy” for App Engine Flex
2 2. Stock info service: Spring on server side and
javascript (SockJS) on client side
Spring:
StompEndpoint at WebSocketMessageBrokerConfigurer
import org.springframework.messaging.core.MessageSendingOperations;
private final MessageSendingOperations<String> messagingTemplate;
this.messagingTemplate.convertAndSend("/topic/price.stock." + quote.getTicker(), quote);
SockJS over STOMP
stompClient = webstomp.over(new SockJS(url, null, {transports: sockJsProtocols}));
Works when “mvn jetty:run”
Does not work when “mvn appengine:deploy” for App Engine
Standard:
Works when “mvn appengine:deploy” for App Engine Flex with a
change to spring-websocket-portfolio-appflex/src/main/webapp/static/js/controllers.js:
The change is to modify line 65:
// tradeService.connect("/spring-websocket-portfolio/portfolio") tradeService.connect("/portfolio")
3 3. Sending date constantly to client: Spring boot on
server side and javascript (SockJS) on client side
Spring Boot:
StompEndpoint at AbstractWebSocketMessageBrokerConfigurer
import org.springframework.messaging.simp.SimpMessagingTemplate;
SimpMessagingTemplate.convertAndSend("/topic/message", "Date: " + new Date())
SockJS over STOMP
var
socket = new SockJS(‘/stomp’);
var stompClient
= Stomp.over(socket);
(gradle)
Unable to build from ‘mvn’ since there is no pom.xml file
4 4. Greeting service: Spring boot on server side and
javascript (SockJS) on client side
Spring Boot:
StompEndpoint at WebSocketMessageBrokerConfigurer
@MessageMapping("/hello") @SendTo("/topic/greetings") public Greeting greeting(HelloMessage message) throws Exception { Thread.sleep(1000); // simulated delay return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!"); }
SockJS over STOMP:
var
socket = new SockJS(‘/gs-guide-websocket’);
var
stompClient = Stomp.over(socket);
(mvn)
Works when running at local: mvn
spring-boot:run
Did not work when “mvn appengine:deploy” for App Engine Flex:
But after following changes, it works partially (server can
be started; but client got 404 error due to failure of loading javascript
library):
·
Add following to pom.xml:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency>
<repositories> <repository> <id>spring-snapshots</id> <url>http://repo.spring.io/snapshot</url> <snapshots><enabled>true</enabled></snapshots> <releases><enabled>false</enabled></releases> </repository> <repository> <id>spring-milestones</id> <url>http://repo.spring.io/milestone</url> <snapshots><enabled>false</enabled></snapshots> <releases><enabled>true</enabled></releases> </repository> <repository> <id>java-net</id> <url>https://maven.java.net/content/repositories/releases</url> </repository> </repositories>
<!-- for deployment of web application --> <plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>appengine-maven-plugin</artifactId> <!--<version>${appengine.maven.plugin}</version>--> <version>1.3.1</version> <configuration> </configuration> </plugin>
·
Copy app.js, index.html, and main.css from
‘resources/static’ to ‘webapp’ (need to create ‘webapp’ under ‘src/main’ first)
5 5. Spring boot
To turn a pom.xml project to appengine flexible instance,
you need to do:
1.
Add appengine plugin to pom.xml
<!-- for deployment of web application --> <plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>appengine-maven-plugin</artifactId> <version>1.3.1</version> <configuration> </configuration> </plugin>
2.
Add jetty plugin to pom.xml to support local running on
jetty:
<plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>9.4.7.v20170914</version> <configuration> <webApp> <contextPath>/${project.artifactId}</contextPath> </webApp> </configuration> </plugin>
3.
Since war is needed for google app engine, add
following line to pom.xml
<packaging>war</packaging>
4.
Create app.yaml file through IDEA’s “Add App Engine
Support”/”Google App Engine Flex” menu from “Tools” and put following lines
into it:
runtime: java env: flex handlers: - url: /.* script: this field is required, but ignored runtime_config: # Optional jdk: openjdk8 server: jetty9 # Use only a single instance, so that this local-memory-only chat app will work # consistently with multiple users. To work across multiple instances, an # extra-instance messaging system or data store would be needed. manual_scaling: instances: 1 network: session_affinity: true env_variables: JETTY_MODULES_ENABLE: websocket
5.
Run ‘mvn package’ and ‘mvn appengine:deploy’ to deploy
6.
Run ‘mvn jetty:run’ to test
Embedded Jetty or
Tomcat
Reactive Web
start.spring.io has Websocket as dependencies
@Async in Spring:
Simply put – annotating a method of a bean
with @Async will make it execute in a separate thread i.e.
the caller will not wait for the completion of the called method.
No comments:
Post a Comment