가비지 컬렉션 과정 - Generational Garbage Collection

GC에 대해서 알아보기 전에 알아야 할 용어가 있다. 바로 'stop-the-world'이다. stop-the-world란, GC을 실행하기 위해 JVM이 애플리케이션 실행을 멈추는 것이다. stop-the-world가 발생하면 GC를 실행하는 쓰레드를 제외한 나머지 쓰레드는 모두 작업을 멈춘다. GC 작업을 완료한 이후에야 중단했던 작업을 다시 시작한다. 어떤 GC 알고리즘을 사용하더라도 stop-the-world는 발생한다. 대개의 경우 GC 튜닝이란 이 stop-the-world 시간을 줄이는 것이다.

- Young 영역(Yong Generation 영역): 새롭게 생성한 객체의 대부분이 여기에 위치한다. 대부분의 객체가 금방 접근 불가능 상태가 되기 때문에 매우 많은 객체가 Young 영역에 생성되었다가 사라진다. 이 영역에서 객체가 사라질때 Minor GC가 발생한다고 말한다.

- Old 영역(Old Generation 영역): 접근 불가능 상태로 되지 않아 Young 영역에서 살아남은 객체가 여기로 복사된다. 대부분 Young 영역보다 크게 할당하며, 크기가 큰 만큼 Young 영역보다 GC는 적게 발생한다. 이 영역에서 객체가 사라질 때 Major GC(혹은 Full GC)가 발생한다고 말한다.

참고 : [D2 Java Garbage Collection](https://d2.naver.com/helloworld/1329)

GC의 튜닝의 목적 두가지

* Old 영역으로 넘어가는 객체의 수를 최소화 하는것

* FullGC의 실행 시간을 줄이는것

Old 영역으로 넘어가는 객체의수 최소화 하기

JDK 7부터 본격적으로 사용할 수 있는 G1 GC를 제외한, Oracle JVM에서 제공하는 모든 GC는 Generational GC이다. 즉, Eden 영역에서 객체가 처음 만들어지고, Survivor 영역을 오가다가, 끝까지 남아 있는 객체는 Old 영역으로 이동한다. 간혹 Eden 영역에서 만들어지다가 크기가 커져서 Old 영역으로 바로 넘어가는 객체도 있긴 하다. Old 영역의 GC는 New 영역의 GC에 비하여 상대적으로 시간이 오래 소요되기 때문에 Old 영역으로 이동하는 객체의 수를 줄이면 Full GC가 발생하는 빈도를 많이 줄일 수 있다. Old 영역으로 넘어가는 객체의 수를 줄인다는 말을 잘못 이해하면 객체를 마음대로 New 영역에만 남길 수 있다고 생각할 수 있지만, 그렇게는 할 수는 없다. 하지만 New 영역의 크기를 잘 조절함으로써 큰 효과를 볼 수는 있다.

Full GC 시간 줄이기

Full GC의 실행 시간은 상대적으로 Minor GC(yong GCs)에 비하여 길다. 그래서 Full GC 실행에 시간이 오래 소요되면(1초 이상) 연계된 여러 부분에서 타임아웃이 발생할 수 있다. 그렇다고 Full GC 실행 시간을 줄이기 위해서 Old 영역의 크기를 줄이면 자칫 OutOfMemoryError가 발생하거나 Full GC 횟수가 늘어난다. 반대로 Old 영역의 크기를 늘리면 Full GC 횟수는 줄어들지만 실행 시간이 늘어난다. Old 영역의 크기를 적절하게 '잘' 설정해야 한다.

이후 자세한 튜닝 방법은 안알아도됨

참고 : [Naver D2](https://d2.naver.com/helloworld/37111)

'ProgramLanguage > Java' 카테고리의 다른 글

JVM 메모리 구조 (1)  (0) 2020.03.22
Java8- Default 메서드(Abstract, Interface)  (0) 2020.03.18
Lambda_Expression(2)  (0) 2020.01.25
객체 지향 설계 5원칙 - SOLID  (0) 2019.12.26
Java 와 객체 지향  (0) 2019.12.03

HistoryServer 가 실행이 되지 않고, 아래와 같은 로그가 출력이 된다면

Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at org.apache.spark.deploy.history.HistoryServer$.main(HistoryServer.scala:296)
        at org.apache.spark.deploy.history.HistoryServer.main(HistoryServer.scala)
Caused by: java.io.FileNotFoundException: Log directory specified does not exist: file:/tmp/spark-events Did you configure the correct one through spark.history.fs.logDirectory?
        at org.apache.spark.deploy.history.FsHistoryProvider.org$apache$spark$deploy$history$FsHistoryProvider$$startPolling(FsHistoryProvider.scala:267)
        at org.apache.spark.deploy.history.FsHistoryProvider.initialize(FsHistoryProvider.scala:211)
        at org.apache.spark.deploy.history.FsHistoryProvider.<init>(FsHistoryProvider.scala:207)
        at org.apache.spark.deploy.history.FsHistoryProvider.<init>(FsHistoryProvider.scala:86)
        ... 6 more
Caused by: java.io.FileNotFoundException: File file:/tmp/spark-events does not exist
        at org.apache.hadoop.fs.RawLocalFileSystem.deprecatedGetFileStatus(RawLocalFileSystem.java:611)
        at org.apache.hadoop.fs.RawLocalFileSystem.getFileLinkStatusInternal(RawLocalFileSystem.java:824)
        at org.apache.hadoop.fs.RawLocalFileSystem.getFileStatus(RawLocalFileSystem.java:601)
        at org.apache.hadoop.fs.FilterFileSystem.getFileStatus(FilterFileSystem.java:421)
        at org.apache.spark.deploy.history.FsHistoryProvider.org$apache$spark$deploy$history$FsHistoryProvider$$startPolling(FsHistoryProvider.scala:257)
        ... 9 more

해결 spark-default.conf 에 아래와 같이spark.history.fs.logDirectory 설정을 추가 해준다

spark.eventLog.enabled          true
spark.eventLog.dir              file:/opt/spark-events
spark.history.fs.logDirectory   file:/opt/spark-events

https://stackoverflow.com/questions/44835026/how-to-enable-spark-history-server-for-standalone-cluster-non-hdfs-mode?rq=1

'BackEnd > Spark' 카테고리의 다른 글

스파크 SQL 사용하여 파일로 보내기  (0) 2020.03.02
java.io.InvalidClassException: org.apache.spark.rdd.RDD  (0) 2020.02.18
SparkSession  (0) 2020.02.06
RDD 영속화(캐싱)  (0) 2019.09.02
Spark BroadCast  (0) 2019.08.28

도커 컨테이너 종료 

$ docker stop 컨테이너id

 

도커 컨테이너 실행 

$docker exec 컨테이너id

 

실행중인 컨테이너 확인
$docker ps

 

전체 컨테이너 확인
$docker ps -a

 

컨테이너 삭제
$docker rm 컨테이너id

 

도커 이미지 확인
$docker images

 

도커 이미지 지우기
$docker rmi 이미지id

 

컨테이너 삭제, 이미지 삭제 동시
$docker rmi -f 이미지id

 

참고: https://brunch.co.kr/@hopeless/10

fastcampus Java SpringCore 강좌를들으면서 정리를 하였습니다.

ClassPath Scanning

특정 classpath 이하에 있는 관리할 컴포넌트(@Component)들을 등록을 하기 위해 스캔함

@Component : Annotation Type으로 런타임에 동작함. classpath scanning을 통해 자동적으로 검색됨.

@Repository, @Service, @Controller

@ComponentScan(basePackages = "kr.co.fastcampus.cli") 을 해주면 xml에 별도로 설정을 안해줘도 알아서 추가가 됨.

예시

@Configuration
@ComponentScan(basePackages = "kr.co.fastcampus.cli")
public class AppConfig {
    @Bean
    public A a1(){
        return new A();
    }
    @Bean
      @Scope("singleton")
    public B b1(){
        return new B();
    }
}

@Component
class A {}

@Component
class B{}

아래와 같이 AnnotationConfigApplicationContext()를 사용해서 사용이 가능하다.

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

AnnotationConfigApplicationContext API 를 살펴보면 아래와 같이 파라미터를 넣어주면 사용이 가능하다.

Constructor and Description
AnnotationConfigApplicationContext()Create a new AnnotationConfigApplicationContext that needs to be populated through register(java.lang.Class...) calls and then manually refreshed.
AnnotationConfigApplicationContext(Class... componentClasses)Create a new AnnotationConfigApplicationContext, deriving bean definitions from the given component classes and automatically refreshing the context.
AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory)Create a new AnnotationConfigApplicationContext with the given DefaultListableBeanFactory.
AnnotationConfigApplicationContext(String... basePackages)Create a new AnnotationConfigApplicationContext, scanning for components in the given packages, registering bean definitions for those components, and automatically refreshing the context.

Filter

ComponentScan에서 특정 클래스를 빼고 싶을 때, (pattern, class, 등 의 다양함 )

아래처럼 filter를 사용해서 execludeFilters를 사용하여 가능하다.

@Slf4j
@ComponentScan(basePackageClasses = Main.class , excludeFilters = @ComponentScan.Filter (type= FilterType.REGEX,pattern="kr.co.fastcampus.cli.B"))
public class Main {
    static Logger logger = LoggerFactory.getLogger(Main.class);

    public static void main(String []args) {

        //Java Anotation을 사용한 주입
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class);
        B b = context.getBean(B.class);
        log.info("b : "+b);
        context.close();
    }
}

ComponentScan 성능 향상

ComponentScan은 Java Generic을 사용하여 JVM에서 어노테이션이 붙어있는지 아닌지 결정하여 판단을 하게 되는데, 만약 어노테이션이 너무 많이 사용되게 되면 ComponentScan이 오래 걸릴 수 있다.

그래서 indexer를 만들어 놓음

pom.xml에 추가

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-indexer</artifactId>
        <version>5.2.3.RELEASE</version>
        <optional>true</optional>
    </dependency>
</dependencies>

빌드를 하게 되면 META-INF/spring.components 가 만들어짐.

'BackEnd > Spring' 카테고리의 다른 글

ClassPath Scanning and Managed Components  (0) 2020.02.22
Bean Scope  (0) 2020.02.11
Customizing the Nature of a Bean  (0) 2020.02.01
DI (Dependency Injection)  (0) 2020.02.01
Spring-Core  (0) 2020.01.19

SparkSession

모든 스파크 애플리케이션은 가장 먼저 SparkSession을 생성

기존 코드 : new SparkContext 패턴을 사용 (과거 SparkContext, SQLContext 를 직접 생성)

최신 코드 : SparkSession의 빌더 메서드를 사용해 생성할것을 추천

SparkSession 클래스는 스파크2.x 버전 에서 사용이 가능하다

new SparkContext 에서 보다 안전하게 생성할 수 있다. 다수의 라이브러리가 세션을 생성하려는 상황에서 컨텍스트 충돌을 방지 할 수 있다.

예제

val spark = SparkSession.builder
.appName("My Spark Application")  // optional and will be autogenerated if not specified
.master("local[*]")      // only for demo and testing purposes, use spark-submit instead
.enableHiveSupport()              // self-explanatory, isn't it?
.config("spark.sql.warehouse.dir", "target/spark-warehouse")
.config("spark.som.config.option","some-value")
.getOrCreate()



SparkSession, SQLContext, HiveContext

과거 버전의 스파크에서는 SQLContext와 HiveContext를 사용해 DataFrame과 스파크 SQL을 다룰수 있었음.
과거 SparkContext는 스파크의 핵심 추상화 개념을 다루는데 중점을 두고 , SQLContext는 스파크의 핵심 추상화 개념을 다루는데 중점을 둠 
Spark2.x 이후 부터는 두 콘텍스트를 SparkSession으로 단일화함
SparkContext, SQLContext는 존재하지만 SparkSession을 통하여 접근이 가능하다.

멀티 세션

newSession

SparkContext를 공유하고 session 만 달라지는 방법, 개별의 session 마다 동일한 이름의 테이블 생성 가능.

동일한 jvm에 여러개의 스파크 컨텍스트를 갖는것은 권장되지 않으며 더 불안하고 하나의 스파크 컨텍스트가 충돌하면 다른 스파크에 영향을 줄수 있다.

newSession으로 만들어진 세션중 하나라도 stop/close 를 하게 되면 동일한 SparkContext를 사용하기 때문에 종료가 된다.

sparkSession.newSession();

 

 

참고

Spark 완벽 가이드(도서)

Spark -newSession (https://medium.com/@achilleus/spark-session-10d0d66d1d24)

SparkSession - The Entry Point to Spark SQL (https://jaceklaskowski.gitbooks.io/mastering-spark-sql/spark-sql-SparkSession.html)

fastcampus java 온라인 강의를 들으면서 정리한 내용입니다.

Customizing the Nature of a Bean

  • Lifecycle Callbacks
  • ApplicationContextAware and BeanNameAware

LifeCycle

객체들을 관리 , 객체를 만들때(new), 객체를 없앨 때(destroy)

new라는 객체를 만들기 전

특정 빈에 대해서 자원 없앨때 close에 대한 함수

  • InitializingBean
  • DisposableBean
  • xml -init method / destroy

실행

ApplicationContext context = new ClassPathXmlApplicationContext("dao.xml");

ConnectionFactory connectionFactory = context.getBean("connectionFactory",ConnectionFactory.class);
log.info("result : "+connectionFactory.getConnection());
  1. Initializing Bean (Interface)

    bean이 생성 될때 미리 생성됨 : 컨테이너가 빈에 필요한 모든 속성을 설정 한 후 빈 초기화 작업을 수행

    InitializingBean 인터페이스는 afterPropertiesSet 하나의 메서드를 가진다.

    void afterPropertiesSet() throws Exception;

예제 dao.xml

<bean id="connectionFactory" class="kr.co.fastcampus.cli.ConnectionFactory" >
  <constructor-arg name="driverClass" value="org.h2.Driver"/>
  <constructor-arg name="url" value="jdbc:h2:mem:test"/>
  <constructor-arg name="user" value="sa"/>
  <constructor-arg name="password" value=""/>
</bean>

<bean id = "connection" class="java.sql.Connection"
      factory-bean = "connectionFactory"
      factory-method="createConnection"
      />

<bean id="dao" class="kr.co.fastcampus.cli.Dao">
  <constructor-arg ref="connection"></constructor-arg>
</bean>

ConnectionFactory.java

public class ConnectionFactory implements InitializingBean {
    private String driverClass;
    private String url;
    private String user;
    private String password;
    //bean을 만들지면서 Connection을 미리 생성 하기
    @Getter
    private Connection connection=null;

    public ConnectionFactory(String driverClass,String url, String user, String password) {
        this.driverClass = driverClass;
        this.url = url;
        this.user = user;
        this.password = password;
    }

    public Connection createConnection() throws SQLException {
        try {
            Class.forName("org.h2.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        String url = "jdbc:h2:mem:test;MODE=MySQL;";
        return DriverManager.getConnection(this.url,this.user,this.password);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        this.connection = createConnection();
    }
}
  1. Initializing Bean (xml)

    init-method 에 는 빈 팩토리를 불러올 때 실행될 메서드이름을 지정해서 사용할 수 있다.

    dao.xml

    <bean id="connectionFactory" class="kr.co.fastcampus.cli.ConnectionFactory" init-method="init" >

    ConnectionFactory.java

    public class ConnectionFactory {
        private String driverClass;
        private String url;
        private String user;
        private String password;
        //bean을 만들지면서 Connection을 미리 생성 하기
        @Getter
        private Connection connection=null;
    
        public ConnectionFactory( String driverClass,String url, String user, String password) {
            this.driverClass = driverClass;
            this.url = url;
            this.user = user;
            this.password = password;
        }
        //bean 메서드(xml)의 init의 메서드를 지정해주면 bean이 초기화될때 생성된다.
        public void init() throws Exception {
            this.connection = createConnection();
        }
    
        public Connection createConnection() throws SQLException {
            try {
                Class.forName("org.h2.Driver");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            String url = "jdbc:h2:mem:test;MODE=MySQL;";
            return DriverManager.getConnection(this.url,this.user,this.password);
        }
    }

###DisposableBean

Bean을 포함하는 컨테이너가 소멸 될 때 Bean이 콜백을 얻을 수 있습니다.

1.Disposable Bean (Interface)

DisposableBean 인터페이스는 destroy 메서드를 가진다.

void destroy() throws Exception;

ConnectionFactory.java

@Slf4j
public class ConnectionFactory implements DisposableBean {
    private String driverClass;
    private String url;
    private String user;
    private String password;
    //bean을 만들지면서 Connection을 미리 생성 하기
    @Getter
    private Connection connection=null;

    public ConnectionFactory( String driverClass,String url, String user, String password) {
        this.driverClass = driverClass;
        this.url = url;
        this.user = user;
        this.password = password;
    }
    //bean 메서드(xml)의 init의 메서드를 지정해주면 bean이 초기화될때 생성된다.
    public void init() throws Exception {
        this.connection = createConnection();
    }

    public Connection createConnection() throws SQLException {
        try {
            Class.forName("org.h2.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        String url = "jdbc:h2:mem:test;MODE=MySQL;";
        return DriverManager.getConnection(this.url,this.user,this.password);
    }

    @Override
    public void destroy() throws Exception {
        log.info("destory connection");
        if(this.connection!=null){
            this.connection.close();
        }
    }
}

이렇게 해주고 위에서 getbean을 사용해서 사용했지만, 여기서는 ApplicationContext 보다 ApplicationContext클래스를 상속받고 있는 ConfigurableApplicationContext 를 사용해서 테스트를 진행해야 한다.

ConfigurableApplicationContextApplicationContext, Lifecycle, Closeable 를 상속 받고 있다.

테스트를 위한 실행

ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("dao.xml");

ConnectionFactory connectionFactory = context.getBean("connectionFactory",ConnectionFactory.class);
log.info("result : "+connectionFactory.getConnection());
context.close();

결과

00:58:37.149 [main] INFO  kr.co.fastcampus.cli.Main - result : conn0: url=jdbc:h2:mem:test user=SA
00:58:37.151 [main] INFO  k.c.fastcampus.cli.ConnectionFactory - destory connection

2.DisposableBean Bean (xml)

위의 initializing Bean을 xml 로 설정한것과 같다.destroy-method 속성을 추가 해주면 된다.

<bean id="connectionFactory" class="kr.co.fastcampus.cli.ConnectionFactory" init-method="init" destroy-method="destroy">
@Slf4j
public class ConnectionFactory {
    private String driverClass;
    private String url;
    private String user;
    private String password;
    //bean을 만들지면서 Connection을 미리 생성 하기
    @Getter
    private Connection connection=null;

    public ConnectionFactory( String driverClass,String url, String user, String password) {
        this.driverClass = driverClass;
        this.url = url;
        this.user = user;
        this.password = password;
    }
    //bean 메서드(xml)의 init의 메서드를 지정해주면 bean이 초기화될때 생성된다.
    public void init() throws Exception {
        this.connection = createConnection();
    }

    public Connection createConnection() throws SQLException {
        try {
            Class.forName("org.h2.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        String url = "jdbc:h2:mem:test;MODE=MySQL;";
        return DriverManager.getConnection(this.url,this.user,this.password);
    }

    public void destroy() throws Exception {
        log.info("destory connection");
        if(this.connection!=null){
            this.connection.close();
        }
    }
}

결과는 똑같이 나온다.

01:08:23.145 [main] INFO  kr.co.fastcampus.cli.Main - result : conn0: url=jdbc:h2:mem:test user=SA
01:08:23.148 [main] INFO  k.c.fastcampus.cli.ConnectionFactory - destory connection

##Default init, destroy

default-init-method , default-destroy-method 를 beans에 추가 해주면 기본적으로 bean에서 특정 메서드로 사용이 가능하다.

<beans default-init-method="init"
       default-destroy-method="destroy"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

LifeCycle

Lifecycle 인터페이스

  • void start();

  • void stop();

  • boolean isRunning();

context가 실행 중인지 아닌지 lifeCycle의 상태를 조회 가능하다.

ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("dao.xml");
Lifecycle lifecycle = context.getBean(Lifecycle.class);
log.info("lifeCycle is Running ? "+lifecycle.isRunning());
context.close();
log.info("lifeCycle is Running ? "+lifecycle.isRunning());

결과

01:37:25.064 [main] INFO  kr.co.fastcampus.cli.Main - lifeCycle is Running ? true
01:37:25.069 [main] INFO  k.c.fastcampus.cli.ConnectionFactory - destory connection
01:37:25.070 [main] INFO  kr.co.fastcampus.cli.Main - lifeCycle is Running ? false

###ApplicationContextAware

특정 빈에서 application Context를 사용 하고 싶을때 사용

public interface ApplicationContextAware {
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-nature

'BackEnd > Spring' 카테고리의 다른 글

Bean Scope  (0) 2020.02.11
ClassPath Scanning and Managed Components  (0) 2020.02.08
DI (Dependency Injection)  (0) 2020.02.01
Spring-Core  (0) 2020.01.19
SpringCore - IoC Container(1)  (0) 2020.01.19

fastcampus java 강의를 보면서 정리를 한 것입니다.
Spring IoC의 핵심

의존성 하나 이상의 오브젝트로 실행 되는데, 오브젝트들 간에 함께 의존하고 있음

Di 예제

public Main(){
  public static void main(String []args){
    B b = new B(true);
    A a = new A(b);
    a.println();
  }
}

객체가 객체를 의존하고 있으면, 코드 유지보수가 어려워짐

디커플링 할수록 간결하게 변화함

코드에서 관계를 맺어주는것이 아니다.

의존성을 상위 코드에서 생성하여 객체를 주입하므로 a 에서는 B에 의존하는 값을 가지고 있지 않아도된다.

이것을 framework 화 한것이 IoC Container

  • 설정을 보고 관계를 눈으로 미리 볼수 있다.

  • 비지니스 로직만 집중할 수 있음 .

  • 테스트를 더 쉽게 가능하다.

  • 생성자 주입 / setter 주입

    생성자 주입

    객체가 생성될때 만들어짐

    public class A{
      private B b;
        public void setB(B b){
        this.b=b;
      }
      ...
    }
    <bean id="a" class="kr.co.fastcampus.cli.di.A">
      <constructor-arg ref="b"/>
    </bean>
    <bean id="b" class="kr.co.fastcampus.cli.di.B">
      <constructor-arg value="true"></constructor-arg>
    </bean>

    Setter 주입

    코드가 돌다가 객체가 언제든지 관계가 재설정이 되었을 때

    <bean id="a" class="kr.co.fastcampus.cli.di.A">
      <property name="b" ref="b"/>
    </bean>
    <bean id="b" class="kr.co.fastcampus.cli.di.B">
      <constructor-arg value="true"></constructor-arg>
    </bean>

circulate Dependency

상호 참조 dependecy 서로 참조를 하게 되면 stack overflow가 발생할수 있음.

https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-dependencies

'BackEnd > Spring' 카테고리의 다른 글

Bean Scope  (0) 2020.02.11
ClassPath Scanning and Managed Components  (0) 2020.02.08
Customizing the Nature of a Bean  (0) 2020.02.01
Spring-Core  (0) 2020.01.19
SpringCore - IoC Container(1)  (0) 2020.01.19

모던 자바( 자바8) 못다한 이야기를 보고 정리한 것입니다.

Functional Interface로 java.util.function 패키지 안에 포함되어있다.

람다식의 타입과 형변환

인터페이스인데 abstract 메소드가 하나만 존재하는 경우

Functional interface 4종류

  1. Function 타입
@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);

apply 메소드 하나만 가지고 있음

입력값과 리턴값이 있어야한다.

functional interface 는 anonymous 클래스 필요없이 사용이 가능하다.

function type : function패키지 안에 들어있다.

리턴타입 하나의 타입이 다른 타입으로 리턴 된것.

같은 타입을 리턴하는 것을 identity라고 한다.

같은 타입 T -> R은 일반적인 함수

T- >T 는 identity 함수가 된다 . 그 타입을 받아서 그타입으로 바로 넘기게 되는것

//Parameter : T , Return Type : R
//Function <R,T> 하나의 메소드를 호출
Function<String, Integer> toInt = new Function<String, Integer>() {
  @Override
  public Integer apply(String value) {
    return Integer.parseInt(value);
  }
};

//lambda로 표현하면 ?
Function<String, Integer> toIntLamda = (value)->Integer.parseInt(value);


Integer number = toInt.apply("200");
System.out.println(number);
  1. Consumer
@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

Accept 메소드 하나만 있음.

void 로 리턴값을 가지고 있음 값은 있고 리턴은 없다.

Ex) 리턴값이 없을경우, 출력

//Basic
//Consumer<T>
//Parameter  : T , Return : void
Consumer<String> consumer = new Consumer<String>() {
  @Override
  public void accept(String s) {
    System.out.println(s);
  }
};

//lambda
Consumer<String> consumer2 = (value)->System.out.println(value);

consumer.accept("20");
consumer2.accept("20");
  1. Predicate
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);

결과 값은 항상 boolean 값

function 인데 파라미터 값은 T이고 리턴 타입은항상 boolean 으로 출력

//Basic
Predicate<Integer> isPositive = new Predicate<Integer>() {
  @Override
  public boolean test(Integer integer) {
    return integer >0;
  }
};

System.out.println("is Positive ? "+isPositive.test(-1));
System.out.println("is Positive ? "+isPositive.test(2));

//응용
List<Integer> numbers = Arrays.asList(-5,-4,-3,-2,-1,0,1,2,3,4,5);

//조건
Predicate<Integer> isPositive2 = value -> value > 0;

List<Integer> positiveNumbers = new ArrayList<>();
for(Integer num : numbers){
  if(isPositive2.test(num)){
    positiveNumbers.add(num);
  }
}

아래와 같이 자주쓰이는 filter 메서드를 만들어서 condition만 변경 해주는 방식으로도 사용이 가능하다.

public static <T> List<T> filter(List<T> list, Predicate<T> condition){
  List<T> result = new ArrayList<>();
  for(T element: list){
    if(condition.test(element)){
      result.add(element);
    }
  }
  return result;
}
  1. Supplier

인자 값은 없고 return type만 존재한다.

일종의 lazy Evaliation 할 수 있다.

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

expensiveValue를 구하는 메서드를 일반 코드로 나타내면 아래와 같은 코드가 된다. 총 소요시간은 총 9초 이다.

 long start = System.currentTimeMillis();
        printIfValidIndex( 0, getVeryExpensiveValue());
        printIfValidIndex( -1, getVeryExpensiveValue());
        printIfValidIndex( -2, getVeryExpensiveValue());

        System.out.println("Take Time : "+((System.currentTimeMillis()-start)/1000));

메서드 :

    private static String getVeryExpensiveValue(){
        try{
            TimeUnit.SECONDS.sleep(3);
                        System.out.println("throw this area");
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        return "Morris";
    }

    private static void printIfValidIndex( int number, String valueSupplier){
        if(number >=0){
            System.out.println("The value is "+ valueSupplier + ".");
        }else {
            System.out.println("InValid");
        }
    }

결과 값

getVeryExpensiveValue 메서드가 항상 실행 된다.

그래서 비싼 비용의 메서드가 계속 실행된다는 단점이 있다.

실행 순서는 getVeryExpensiveValue () -> printIfValidIndex -> condition

throw this area
The value is Morris.
throw this area
InValid
throw this area
InValid
Take Time : 9

lazy 하게 실행 할수 있는 supplier로 수정을 해보자

long start = System.currentTimeMillis();
        printIfValidIndex( 0, () -> getVeryExpensiveValue());
        printIfValidIndex( -1, () -> getVeryExpensiveValue());
        printIfValidIndex( -2, () -> getVeryExpensiveValue());

        System.out.println("Take Time : "+((System.currentTimeMillis()-start)/1000));
    }

메서드

일반 코드에서 printIfValidIndex의 매개변수를 string에서 Supplier으로 변경을 하였다.

    private static String getVeryExpensiveValue(){
        try{
            TimeUnit.SECONDS.sleep(3);
              System.out.println("throw this area");
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        return "Morris";
    }

    private static void printIfValidIndex( int number, Supplier<String> valueSupplier){
        if(number >=0){
            System.out.println("The value is "+ valueSupplier.get() + ".");
        }else {
            System.out.println("InValid");
        }
    }

결과 값

throw this area
The value is Morris.
InValid
InValid
Take Time : 3

결과 값을 보면 3초 밖에 나오지 않는다 .

printIfValidIndex -> condition -> get을 하면 불러온다.

이렇게 알수 있는 것은 supplier를 사용하면 매개변수.get을 사용하는 시점에서 해당 메서드가 실행 되는 것을 알수 있다. 이렇게 하면 컴퓨팅 성능과 리소스를 줄일수 있을 것 같다.

'ProgramLanguage > Java' 카테고리의 다른 글

Java8- Default 메서드(Abstract, Interface)  (0) 2020.03.18
JVM 튜닝  (0) 2020.02.10
객체 지향 설계 5원칙 - SOLID  (0) 2019.12.26
Java 와 객체 지향  (0) 2019.12.03
Java jar파일 만들기  (0) 2019.08.04

Spring-Core

Spring FrameworkOverview

스프링은 Java EE(엔터프라이즈)를 쉽게 만들수 있다.

엔터프라이즈 어플리케이션 Java EE 는 커뮤니티 프로세스가 주도하는 소프트웨어 ,JS360,370...등등을 볼수 있다.

엔터프라이즈 소프트웨어 : 비지니스를 풀려고 할때 모든 셋에 대한 정의가 되어있다는 점

javax 패키지

Java Servlet도 Java EE에 대한 기능

역사

2003년부터 시작, J2EE가 너무 복잡함 , 복합함을 해결하기 위해서 POJO라는 개념이 나오기도함.

무조건 JavaEE Spec에 따라서 해야했는데,

IoC Container

core : ioc, eventresource, ibn validation, databinding, spel, aop..

Spring : Inversion of Control 을 구현한 프레임워크

왜 inversion of Controll이 좋은가?, Di 의 개념은?

ApplicationContext를 통해서 ioc를 진행하고있음

ApplicationContext는 aop, eventpublication, ....등 다양한 것들을 구현하고있다.

interface ApplicationContext 란 ?

여러 구현체들과 설명이 많이 있음 spring의 핵심

spring container를 통해서 pojo비지니스 오브젝트를 configuration 메타 데이터를 만들어놓으면 spring이 자동으로 만들어주고 활용할수 있게 해준다.

Instantiating a Container

구현체를 통해서 applicationContext를 사용할 수 있게 된다.

코드로 객체를 생성하는것이 아니라 xml을통해서 configuration Metadata를 만들고 비지니스 로직을 만들고 spring container를 통해서 동작(실행)이 하게된다.

applicationContext의 인터페이스를 구현한 것이 springcontainer임 !!

Spring Container설정은 아래와같다.

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

Dao dao = new Dao()

객체 생성 관련 설정

<beans....>
    <bean class="kr.morris.cli.dao"></bean>
</beans....>

객체의 타입에 맞게 context를 사용해서 객체를 가지고 옴 .

Dao dao = context.getBean(Dao.class);

Configuration Metadata

  • xml
    • 특정 namespace을 가지고 있다.
    • 라는 태그 안에 < bean /> 을 설정 할 수 있다.
  • annotation
  • java

Bean

Naming Bean

기존의 빈

<bean class="kr.morris.cli.Dao"/>
  • id 는 그대로 하나만 가지고 있어야한다.
    unique 하더라도 spring에서 다르게 관리하는 bean을 만들수도 있다.

    <bean id='dao'.../>
  • name으로도 추가가 가능하다

    <bean name='dao1, dao2'.../>
  • 같은 클래스를 가리키더라도 id,name이 다르면 새로운 객체를 만드는 것이기 때문에 둘의 객체의 hash값이 다르게 출력된다.

bean을 지정하면 기본 생성자에대해서 객체를 생성한다.

매개변수를 받는 생성자를 입력받게 된다면 ApplicationContext에서 bean을 불러 올때 에러가난다. (beanCreateionException)

static factory method를 사용해서 만들 수도 있다.

Dao 설정에 factory-method 속성에 createDao라는 매서드를 입력해주주면된다.

<bean id="dao" class="kr.morris.cli.Dao" factory-method="createDao"></bean>

public class Dao {
    public stataic Dao createDao(){
          return new Dao();
    }
}

instance Factory method

인스턴스 Method를 이용해 bean 객체를 생성이 가능하다

Factory bean 인터페이스를 구현한 팩토리 빈이 바로 팩토리 빈 오브젝트의 메소드를 이용해 bean 객체를 생성하는 대표적인 방법

두 개의 bean이 필요함.

  • 하나는 빈을 만들어줄 클래스가 정의된 빈 (Dao.class)

  • 우리가 사용할 빈 (DaoFactory)
    특정외부 자원들을 사용할때 팩토리 매서드를 사용해서 보는 경우가 있음

    public class DaoFactory{

    public Dao createDao(){
      return new Dao();
    }

    }

    public class Dao{

    }

동작을 해보면 팩토리메서드를 통해서 실제로 daofactory를 통해서 bean이 생성된 것을 알 수 있다.

참고 :

패스트 캠퍼스 Java Spring 강의중 Spring-Core

https://cornswrold.tistory.com/101

'BackEnd > Spring' 카테고리의 다른 글

Bean Scope  (0) 2020.02.11
ClassPath Scanning and Managed Components  (0) 2020.02.08
Customizing the Nature of a Bean  (0) 2020.02.01
DI (Dependency Injection)  (0) 2020.02.01
SpringCore - IoC Container(1)  (0) 2020.01.19

IoC Container

Spring IoC Container

ApplicationContext 인터페이스는 Spring IoC 컨테이너를 나타내며, 인스턴스 구성 및 bean 조립을 담당

아래는 Spring의 작동 방식을 개략적으로 보여줌

Springframework 용어 정리

Bean 빈 또는 빈 오브젝트는 스프링이 IOC 방식으로 관리하는 오브젝트를 말함 Spring Application에서 사용하는 모든 오브젝트가 빈이라고 불리는것이 아니라, 스프링이 직접 생성과 제어를 담당하는 오브젝트를 빈이라고 부른다.

빈 팩토리 스프링의 ioc 를 담당하는 컨테이너를 가리킴 빈을 등록하고, 생성하고 조회하고 부가적인 관리 기능을 담당 beanFactory를 바로 사용하지 않고, 확장한 application context를 이용한다.

애플리케이션 컨텍스트 빈 팩토리를 확장한 IOC 컨테이너, 빈을 등록하고 관리하는 기본적인 기능은 빈팩토리와 동일하다. 스프링에서 빈팩토리기능 말고도 부가적인 서비스를 추가로 제공함. 빈 팩토리라고 부를때는 주로 빈의 생성과 제어의 관점, 애플리케이션 컨텍스트라고 할 때는 스프링이 제공하는 애플리케이션 지원 기능을 모두 포함해서 이야기 하는 것이라고 보면된다.

applicationContext는 beanFactory를 상속한다.

설정정보/설정 메타 정보 스프링 애플리케이션 컨텍스트 또는 빈 팩토리가 ioc를 적용하기 위해 사용되는 메타정보 (xml이 될수도있고, java 어노테이션, java 코드 로 표기 될 수 있다.)

컨테이너 또는 ioc 컨테이너 IoC 방식으로 빈을 관리한다는 의미에서 애플리케이션 컨텍스트나 빈 팩토리를 컨테이너 또는 IoC container라고 한다.

스프링 프레임워크 스프링 프레임워크는 IoC 컨테이너, 애플리케이션 컨텍스트를 포함해서 스프링이 제공하는 모든 기능을 통틀어 말할 때 주로 사용

Spring Java API

API를 찾아서 들어가게 되면 아래와 같이 확인을 할 수 있다.

ApplicationContext API

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html

BeanFactory API

All Known Implementing Classes들은 아래와 같다. AbstractApplicationContext, AbstractAutowireCapableBeanFactory, AbstractBeanFactory, AbstractRefreshableApplicationContext, AbstractRefreshableConfigApplicationContext, AbstractRefreshableWebApplicationContext, AbstractXmlApplicationContext, AnnotationConfigApplicationContext, AnnotationConfigWebApplicationContext, ClassPathXmlApplicationContext, DefaultListableBeanFactory, FileSystemXmlApplicationContext, GenericApplicationContext, GenericGroovyApplicationContext, GenericWebApplicationContext, GenericXmlApplicationContext, GroovyWebApplicationContext, ResourceAdapterApplicationContext, SimpleJndiBeanFactory, StaticApplicationContext, StaticListableBeanFactory, StaticWebApplicationContext, XmlBeanFactory, XmlWebApplicationContext

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/BeanFactory.html

참고 :

토비의 스프링
[https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html]

'BackEnd > Spring' 카테고리의 다른 글

Bean Scope  (0) 2020.02.11
ClassPath Scanning and Managed Components  (0) 2020.02.08
Customizing the Nature of a Bean  (0) 2020.02.01
DI (Dependency Injection)  (0) 2020.02.01
Spring-Core  (0) 2020.01.19

+ Recent posts