26 Şubat 2020 Çarşamba

spring-boot-starter-parent - Eğer Kendi Parent pom Dosyamız Varsa

Giriş
Eğer kendi parent pom dosyamız varsa parent olarak spring-boot-starter-parent'ı kullanamayız. Çünkü bir pom dosyasında sadece bir tane parent olabilir. Bu durumda hem kendi parent dosyamızı hem de springboot'u kullanmak için şöyle yaparız

Örnek
1. parent dosyamıza şu satırı ekleriz. Açıklaması şöyle
If we don't make use of the parent POM, we can still benefit from dependency management by adding the spring-boot-dependencies artifact with scope=import
Şöyle yaparız.
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-dependencies</artifactId>
      <version>1.5.6.RELEASE</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
2. Eğer spring-boot maven plugin'i kullanacaksak kendi pom dosyamıza şu satırı ekleriz. Açıklaması şöyle
On the other hand, without the parent POM, we no longer benefit from plugin management. This means we need to add the spring-boot-maven-plugin explicitly:
Şöyle yaparız.
<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
  </plugins>
</build>
Örnek
Şöyle yaparız
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-dependencies</artifactId>
      <version>2.5.2</version>
      <type>pom</type>
      <scope>import</scope>
      </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
  </dependency>

  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
  </dependency>
</dependencies>


spring-boot-maven-plugin

Giriş
Açıklaması şöyle
Spring Boot Maven Plugin is a Maven plugin that allows you to package executable jar or war archives and run an application in place. It provides a number of features that are useful when developing Spring Boot applications, such as the ability to package executable jar or war files, run an application in place, and use hot swapping with background compilation to make development faster.

Sunulan goal şunlar
1. repackage
2. run
3. start ve stop
4. build-info
5. build-image

repackage goal  - Fat Jar Oluşturur
Spring boot uygulamasını paketlemek için gerekir.  Açıklaması şöyle.
Unfortunately, if we are working with a jar package, the basic Maven package goal doesn't include any of the external dependencies.

This means that we can use it only as a library in a bigger project.

To circumvent this limitation, we need to leverage the Maven Spring Boot plugin repackage goal to run our jar/war as a stand-alone application.
Maven 3.2 gerektirir. Açıklaması şöyle.
The Spring Boot Maven Plugin provides Spring Boot support in Maven, allowing you to package executable jar or war archives and run an application “in-place”. To use it you must be using Maven 3.2 (or better).
Çalıştırmak için şöyle yaparız
maven package spring-boot:repackage
run Goal 
Debug içindir. Açıklaması şöyle.
By default the application is executed directly from the Maven JVM. If you need to run in a forked process you can use the 'fork' option. Forking will also occur if the 'jvmArguments', 'systemPropertyVariables', 'environmentVariables' or 'agent' options are specified, or if devtools is present.

If you need to specify some JVM arguments (i.e. for debugging purposes), you can use the jvmArguments parameter,...
Normalde spring uygulamasını çalıştırmak için şöyle yaparız. Ancak bu kullanımda pom içinde tanımladığımız jvm parametreleri kullanılmaz.
$ ./myapp-1.1.0.jar --spring.config.name=application-prod
Bu parametreleri de kullanmak için şöyle yaparız.
maven spring-boot:run
Profile seçmek için şöyle yaparız.
mvn spring-boot:run -Drun.jvmArguments="-Dspring.profiles.active=production"
pom Örnekleri

Örnek - executable jar
Şöyle yaparız
<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <configuration>
        <executable>true</executable>
      </configuration>
    </plugin>
  </plugins>
  <finalName>sba-as-windows-service</finalName>
</build>
Örnek - jvmArguments
Şöyle yaparız.
<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <configuration>
    <executable>true</executable>
    <jvmArguments>-Xmx256m</jvmArguments>
  </configuration>
</plugin>
Örnek - jvmArguments
Şöyle yaparız.
<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <configuration>
      <mainClass>tech.flexpoint.demo.DemoApplication</mainClass>
      <jvmArguments>--show-module-resolution --add-opens=java.base/java.lang=spring.core
        --add-opens=java.base/java.io=tomcat.embed.core
        --add-opens=java.base/java.lang=ALL-UNNAMED 
        --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED</jvmArguments>
      <workingDirectory>${project.basedir}</workingDirectory>
  </configuration>
</plugin>

25 Şubat 2020 Salı

SpringContext @Scope Anotasyonu - Bean İçin Scope Tanımlar

Giriş
Açıklaması şöyle.
We use the @Scope annotation to define the scope of a  @Component class or the @Bean definition. It can be either singleton, prototype, request, session, globalSession, or some custom scope.
proxyMode Alanı
DEFAULT
INTERFACES - JDK kullanır
NO
TARGET_CLASS - CGLIB kullanır
değerlerini alabilir

proxyMode Alanı ne zaman kullanılır sorusunun açıklaması şöyle.
... Spring will not directly inject the bean itself, but a proxy that intercepts all invocations to this bean. This is required for scenarios where a bean with a short-lived scope is injected into another bean with a more long-lived scope. For instance, when injecting a request-scoped bean into an application-scoped bean, the proxy takes care of correctly retrieving the bean for the current request. Without this proxy, the application-scoped bean would be directly populated with a request-scoped bean during the first invocation. All subsequent invocations would (wrongly) still use exactly this “stale” request-scoped bean, even if in the context of a subsequent HTTP request. When using a singleton-scoped bean instead of an application-scoped bean in this proxy-less setup, Spring will even report an error during application startup: Singleton beans are constructed eagerly, but there is no active request context during the application’s initialization phase.

JDK Dynamic Proxy ve CGLIB Farkı Nedir?
Eğer bean bir arayüzden kalıtıyorsa, Spring JDK Dynamic Proxy yöntemini kullanır. Açıklaması şöyle
JDK Reflection API facilitates proxy pattern creation. If the target object to be proxied implements at least one interface, spring uses JDK dynamic proxies to create the proxy for a given target object.
1. INTERFACES  Yani JDK Proxy
JDK proxy nesnesinin class ismine bakarsak şuna benzer bir görürüz.
com.sun.proxy.$Proxy35
JDKDynamicAopProxy Sınıfı
Açıklaması şöyle
JdkDynamicAopProxy is an AopProxy implementation for the Spring AOP framework, based on JDK java.lang.reflect.Proxy dynamic proxies.

Creates a dynamic proxy, implementing the interfaces exposed by the AopProxy that can be used to proxy methods defined in interfaces, rather than classes. Objects of this type should be obtained through proxy factories, * configured by an AdvisedSupport class.
Akış şöyle
 - Your custom component is proxied by a JDK dynamic proxy
- A method call comes into the proxy
- Spring gets the list of MethodInterceptors that define custom proxy logic
- After that, we call the actual target object method
- Then return the value to the proxy than to the original caller
2. TARGET_CLASS - Yani CGLIB Proxy
Eğer bean bir arayüzden kalıtmıyorsa, Spring CGLIB kütüphanesini kullanır. CGLIB proxy için sınıfımızdan kalıtır.  Açıklaması şöyle
Code Generation Library (CGLIB) is a byte code generation instrumentation library. Byte code instrumentation allows us to manipulate or to create classes after the compilation phase of a Java application.

Classes in Java are loaded dynamically at runtime. CGLIB is using this feature of Java language to make it possible to add new classes to an already running Java program.

CGLIB creates a proxy by subclassing. 
CGLIB nesnesinin class ismine bakarsak şuna benzer bir görürüz.
com.foo.Bar$$EnhancerBySpringCGLIB$$38e0aaec
Örnek
Şöyle yaparız.
@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Session getSession() throws Exception {
    return super.getSession();
}
scopeName Alanı
Açıklaması şöyle.
singleton (Default) Scopes a single bean definition to a single object instance per Spring IoC container.
prototype Scopes a single bean definition to any number of object instances.
request Scopes a single bean definition to the lifecycle of a single HTTP request; that is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.
session Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
globalSession Scopes a single bean definition to the lifecycle of a global HTTP Session. Typically only valid when used in a Portlet context. Only valid in the context of a web-aware Spring ApplicationContext.
application Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
websocket Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.
scopeName = singleton Değeri
Singleton Scope yazısına taşıdım.

scopeName = prototype Değeri
Prototype Scope yazısına taşıdım.

scopeName = request Değeri
Bu scope türündeki bean içinde HttpServletRequest kullanılabilir. Şöyle yaparız.
private @Autowired HttpServletRequest request;
scopeName = session Değeri
@SessionScope Anotasyonu yazısına bakabilirsiniz.

scopeName = application Değeri
@ApplicationScope Anotasyonu yazısına bakabilirsiniz.

value Alanı
scopeName ile aynıdır.