반응형

 Datasource의 pool 관련 기본적인 아래의 설정들을 하게 된 후 실제 서비스에 적용하게 되면 몰려드는 요청 및 처리 시간 때문에 예상치 못한 문제들을 확인하게 됩니다.

<기본설정 예제>

datasource.driverClassName=com.mysql.jdbc.Driver

datasource.url=

datasource.username=

datasource.password=


 보통 요청에 대한 pool 을 관리하기 위해 개수를 조정하게 됩니다.

datasource.initialSize=4    # 커넥션 초기값

datasource.minIdle=4       # 유휴상태로 있을 수 있는 커넥션 최소값

datasource.maxActive=16 # 커넥션 최대값

datasource.maxIdle=16


 이러고 나면, DB 와의 연결 관련 문제들이 발생하게 된다. Validation-Query 설정이나 autoReconnect=true (url의 param 값으로들 많이 붙임) 설정을 하게 된다. 하지만 실제 지속적으로 트래픽이 있는 실환경과 사용과 연결이 거의 없는 테스트 환경은 각기 다르니 유의하기를 바라고 autoReconnect 옵션은 false 해 두기를 바랍니다.(라고 어디서 봄) 

datasource.validation-query=select 1 # DB마다 다름.

datasource.test-on-borrow=true        # 커넥션 사용 시 validation 쿼리를 호출하여 커넥션을 확인하는 기능을 사용할지 말지 여부

datasource.test-while-idle=true


 위와같이 했는데도 'Communications link failure' 같은 메시지를 확인하게 된다면, 사용하는 DB 의 timout 들을 확인하기 바란다.(주로 wait_timeout)

확인을 하고 evictor thread 설정을 해야 에러 메시지를 그만 보게 될 것입니다. DB  wait_timeout 보다 당연히 짧아야 할 것 입니다.

datasource.timeBetweenEvictionrunsMillis=60000 # 1000이 1초, thread 실행주기

datasource.minEvictableIdleTimeMillis=60000

datasouce.numTestsPerEvictionRun=4                      # thread 실행 시 처리될 커넥션 개수


※ Tip 자신의 서비스의 master / slave 마다 설정이 다를 수 있고 권한 때문에 DBA만 조회 가능한 환경이 있을 수 있으니 유의 바랍니다.

-- mysql 의 wait_timeout 확인 방법

SHOW GLOBAL VARIABLES LIKE '%timeout%';


-- mysql 에서 host 에서 접속한 연결 개수 확인 방법

SELECT *

  FROM INFOMATION_SCHEMA.PROCESSLIST

WHERE host = '' #

     AND db = ''

;


그 외에 일반적으로 같이 추가하는 설정들 입니다.

datasource.maxWait=5000 # 애플리케이션 레벨에서 DBCP pool의 커넥션을 획득하기 위해 기다리는 시간이니 주의하기 바람.


대략 이렇게 설정하고 서버의 하드웨어 및 서비스에 따라 적절히 값을 조정하면 될 것 같습니다.


※ 사용하는 dbcp1 / dbcp2 / tomcat-dbcp 에 따라 상이할 수 있으니 유의바랍니다.

반응형
반응형

 스프링에서는 포괄적인 캐시 추상 인터페이스를 이용하여, ehcache를 구현할 수 있습니다. (3.1부터? 2.5부터?)

그래서 메소드에 어노테이션으로 @Cacheable 이나 @CacheEvict 와 같이 코드에 추가하여 개발자로 하여금 쉽게 사용할 수 있게 하고 있습니다.


하지만 당연하게도 어노테이션만으로 구현되지는 않으나 기본적인 추가내용이 어렵지는 않습니다.

아래의 단계를 거치면 기본적인 cache 구현을 사용할 수 있습니다.



1. dependency 추가

A. gradle 

compile('net.sf.ehcache:ehcache')


B. maven

<dependency>

<groupId>net.sf.ehcache</groupId>

<artifactId> ehcache </artifactId>

<version>2.10.4</version>

</dependency>


2. ehcache.xml 생성

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:noNamespaceSchemaLocatioin="ehcache.xsd"

updateCheck="true"

dynamicConfig="true"

maxBytesLocalHeap="4M">


<cache name="testName"

     maxBytesLocalHeap="2M"

     memoryStoreEvictionPolicy="LRU" // LFU, FIFO 

     timeToLiveSeconds="3600">

</cache>

</ehcache>


3. CacheManager config 생성

@EnableCaching

@Configuration

public class MyCacheConfig {

@Bean

public CacheManager cacheManager() {

return new EhCacheCacheManager(ehCacheManager().getObject());

}


@Bean

public EhCacheManagerFactoryBean ehCacheManager() {

EhCacheManagerFactoryBean bean = new EhCacheManagerFactoryBean();

bean.setConfigLocation(new ClassPathResource("ehcache.xml"));

bean.setShared(true);

}

}


4. 메소드에 @Cacheable 어노테이션으로 사용

/**

 * 기본적으로 key-value 형태이며, 캐시이름으로 값이 없으면 만들고 조건을 줄 수 있다.

 */

@Cacheable("testName") 

@Cacheable(cacheNames = "testName", key="#{keyId}") 

@Cacheable(value = "testName", key="#{keyId}")


@CachePut(cacheNames = "testName") // 캐시를 갱신한다.


@CacheEvict(cacheNames = "testName", allEntries = true) // 캐시를 삭제한다.

※ 주의사항으로 같은 클래스 내의 호출(self-invocation)은 안 되니 유의해야한다.


5. 간단한 CacheManager TEST-CASE.

@RunWith(SpringRunner.class)

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)

@Import(MyCacheConfig.class)

public class MyCacheConfigTest {

@Autowired CacheManager cacheManager;


@Test public void testSample() {

Cache cache = cacheManager.getCache("testName");

cache.put("testKey", "testValue");


System.out.println("- cache=" + cache.get("testKey").get());

}

}



ref) http://www.ehcache.org/

ref) https://spring.io/guides/gs/caching/

ref) https://memorynotfound.com/spring-boot-ehcache-2-caching-example-configuration/


반응형
반응형

Spring-boot-cli 설치 및 Repository 적용


Spring-CLI 로 프로젝트를 생성하여 Git Repository를 처음에 올리는 방법을 기술하도록 하겠습니다.


A. 먼저 spring init 명령어를 통해서 spring-cli 를 수행하려면 설치를 해야하는데요. 아래의 방법들이 있습니다.

1. spring-boot-cli 라이브러리를 직접 설치 및 환경설정을 한다.

2. SDKMAN(http://sdkman.io) 를 설치하여 spring-boot-cli 를 설치한다.(bashrc 가 수정되는 바람에 나중에 삭제할 때 헤맬 수 있다.)

3. Homebrew 로 설치한다.(https://brew.sh)

4. 맥포트로 설치한다.(https://www.macports.org/install.php)


B. 저는 spring-boot-cli 라이브러리를 직접 설치 및 환경설정을 하려고 합니다.

1. 적당한 위치에 파일을 받고 푼다.

2. .bash_profile 에 SPRIING_HOME, PATH, CLASSPATH 를 설정하고 적용한다. (source .bash_profile)

3. 커멘드 창에 spring --version 또는 spring --help 를 타이핑하여 잘 적용되었는지 확인한다.


C. Spring-Initializer(start.spring.io)를 통해서 새로운 프로젝트를 생성합니다.

1. 아주 간단한 예

  spring init

2. -d 옵션을 사용하여 원하는 모듈을 추가한다.--build 옵션을 사용해 gradle 또는 maven 을 지정할 수 있다.

- spring init -dweb -g=groupId -a=artifactId -n="name" --package-name=pa --description=de --build maven myproject

- spring init -dweb --groudId=g --artifactId=a --name=n --package-name=p --description=d --build maven myproject

3. 존재하는 파일이나 디렉토리에 덮어쓰려면 -f, --force 를 사용하면 됩니다.


D. 옵션 목록 상세 입니다. spring help init을 통해 볼 수 있고, spring init --list 명령어를 수행하면 자세한? 정보들도 볼 수 있어요.

1. -a / --artifactId

2. -b / --boot-version

3. --build

4. -d / dependencies

5. --description

6. -f / force

7. --format

8. -g / --groupId

9. -j / --java-version

10. -l / --language

11. -n / --name

12. -p / --packaging

13. --package-name

14. -t / --type

15. -- target

16. -v / --version

17. x / --extract


E. 설치된 프로젝트를 실행해 본다.

1. 같이 설치된 mvnw 로 실행해 본다.

- ./mvnw spring-boot:run

2. 이미 설치된 maven 으로 실행해 본다.

- mvn spring-boot:run


1.  같이 설치된 gradlew 로 실행해 본다.

- ./gradlew bootRun

2. 이미 설치된 gradle 로 실행해 본다.

- gradle bootRun


F. Git 정보 조회 및 Repository 반영.

1. 프로젝트의 git 정보를 조회한다.

> git config --list

2. 수정할 정보들을 처리한다.

> git config user.name "jooChangYoo"

> git config remote.origin.url " https://github...."

3. 설치된 소스들을 올린다.

> git add -A

> git commit -m ""

> git push origin master (또는 git remote add origin https://github... 후 처리함.)


관련글) http://joochang.tistory.com/84

반응형
반응형

JAVA 기반의 웹서비스 개발을 하는 사람이라면 Spring을 떼어낼 수 없습니다. 그리고 누구나 @Autowired를 최소한 한 번쯤은 사용하고 있습니다. 하지만 보통 크게 관심을 갖지 않으면 “IoC 개념을 구현한 Spring-Container의 Dependency-Injection을 사용했다.” 라는 정도만 숙지하고 사용하게 됩니다. 바로 아래의 가장 초보적인 예제로 말이죠.


ex) 가장 초보적인 @Autowired 사용예제.

public class MyTest {

@Autowired MyService1 myService1;

}


조금 익숙해 지게 되면 다음과 같이 constructor 또는 setter 를 사용하여 확장하게 됩니다. @Autowired 는 기본적으로 byType으로 bean을 찾고 못 찾으면 byName으로 찾습니다.  그리고 필수적인 속성들은 생성자로 그렇지않은 것은 메서드로 생성하기도 합니다.


ex) constructor 또는 setter 를 사용한 @Autowired 사용예제.

public class MyTest {

MyService2 myService2;

MyService3 myService3;


@Autowired

public MyTest(MyService2 myService2) {

this.myService2 = myService2;

}


@Autowired(required=false)

public void setMyService3(MyService3 myService3) {

this.myService3 = myService3;

}

}


우리가 이와 같이 사용하는 Spring의 @Autowired 와 관련있는 DI 의 히스토리와 개념에 대해 짚고 넘어 가도록 하겠습니다. IoC(Inversion of Control)의 한 형태인  DI(Dependency-Injection)는 2004년부터 자바개발의 중요한 프로그래밍 패러다임이 되었습니다. Spring 뿐만 아니라 Guice 프레임워크 등에서 DI를 구현해 왔는데요. 다양한 프레임워크에서 각자의 방향으로 발전하다가  SpringSource의 Rod-Johnson 과 Guice 를 발표한 Bob-Lee가 2009년5월 함께 표준-DI 인터페이스 JSR-330을 작업하기로 발표한 후 몇 달만에 final을 내놓게 되었습니다..(링크)


 Martin-Fowler 의 말을 빌리면 IoC 는 Concept 이고 DI는 Pattern 이라는 설명을 하기도 했고, IoC 를 실제 구현한 것들이 DI를 포함하여 많은 분들께 익숙한 Factory-Pattern과 Service-Locator-Pattern 등이 있습니다.


... ING~~


PrototypeBean의 Dependency-Lookup 의 전략들..

1. ObjectFactory

2. ServiceLocatorFactoryBean

3. Provider<T>

4. @Lookup




reference) https://martinfowler.com/articles/injection.html  

반응형
반응형

Spring boot Tips


  • spring-boot 에서 spring-boot-starter-data-* 관련 dependency 들을 추가하면 'mysql-connector-java' 같은 connector를 추가해야 합니다.
  • no profiles are currently active 가 뜨면 spring.profiles.active=@activeProfile@ 설정을 해야 합니다.
  • gradle 로 구동 시 -Dspring.profiles.active= 를 하더라도 되지 않는 경우가 있는데 아래와 같이 설정해 주어야 합니다.
bootRun {
systemProperties System.properties
}


테스트 케이스에서 ConfigurationProperties나 lombok으로 인해 gradle build 실패

  • spring boot configuration annotation processor not found in classpath 
    • Spring-Boot2에서 ConfigurationProperties 관련 에러가 발생
    • Spring-Doc 문서 참고 - spring-boot-configuration-processor 관련 설정 추가
    • Gradle 버전마다 다를 수 있으니 유의

annotationPorcessor('org.springframework.boot:spring-boot-configuration-processor')
compile('org.springframework.boot:spring-boot-configuration-processor')

annotationPorcessor('org.projectlombok:lombok')
compile('org.projectlombok:lombok)




반응형
반응형

Let's take a lookt at spring-boot!


한 줄로만 요약할 수는 없겠지만 굳이 이야기 한다면 '좀 더 쉽게 스프링을 관리하여 스프링을 빠르게 개발하는데 도움을 주는 도구' 이지 않을까 합니다.


A. spring-boot 를 사용하는데 있어서 핵심요소들이 있습니다. 

1. @SpringBootApplication 을 통한 기본적인 Auto-Configuration 을 활성화 할 수 있습니다. 

2. spring-boot 의 starter 들을 통해 이전에 비해 spring 의 설정들을 간소화 및 관련된 의존성들을 쉽게 관리할 수 있게 됬습니다.

3. spring-boot CLI(Commnand Line Interface) 를 통해서 간결한 스프링 개발 방식을 제공합니다.

4. Actuator 를 통해서 애플리케이션의 내부 작동을 살펴볼 수 있습니다.


B. 다음으로 spring-boot 애플리케이션 프로젝트를 생성하는 방법들을 확인해 보겠습니다.

1. Maven 으로 프로젝트를 생성할 수 있습니다.

mvn archetype:generate -B\

  -DarchetypeGroupId=am.ik.archetype\

  -DarchetypeArtifactId=spring-boot-blank-archetype\

  -DarchetypeVersion=1.0.6\

  -DgroupId=com.example\

  -DartifactId=hajiboot\

  -Dversion=1.0.0-SNAPSHOT

2. Sping Initializer의 웹 인터페이스를 사용합니다.

- http://start.spring.io

3. 개발도구들을 활용해서 프로젝트를 생성합니다.

- IntelliJ, SpringToolSuite

4. Spring Boot CLI 에서 Initializer 를 사용 합니다.

- spring init

- spring init -dweb,jpa,security --build gradle -p jar -x (현재디렉토리에 풀기를 원하면 --extract 나 -x 사용)

spring init -d=web,thymeleaf,data-jpa,h2 --groupId=com.example  --artifactId=mylotto --name="My Lotto Service" --package-name=mylotto --description="My Lotto Service" --build maven mylotto


참고) spring-boot 의 실행.

1. mvn spring-boot:run

2. mvn package 실행 후 java -jar *.jar


참고) spring-boot-cli 설치.

1. spring-boot-cli 라이브러리를 직접 설치 및 환경설정을 한다.

2. SDKMAN(http://sdkman.io) 를 설치하여 spring-boot-cli 를 설치한다.(bashrc 가 수정되는 바람에 나중에 삭제할 때 헤맬 수 있다.)

3. Homebrew 로 설치한다.(https://brew.sh)

4. 맥포트로 설치한다.(https://www.macports.org/install.php)


C. DB

1. JDBC 연결.

a) pom.xml 에 spring-boot-starter-data-jdbc 또는 spring-boot-starter-data-jpa(jdbc를 포함) 그리고 mysql-connector 를 추가한다.

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-jdbc</artifactId>

</dependency>

<!-- jpa 안에 jdbc 포함 -->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-jpa</artifactId>

</dependency>

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

</dependency>


b) application.properties 에 설정값들을 추가한다.

spring.datasource.dirver-class-name=com.mysql.jdbc.Driver

spring.datasource.url=jdbc:mysql://*******:3306/my_lotto

spring.datasource.connectionProperties=useSSL=false;characterEncoding=UTF-8;zeroDateTimeBehavior=convertToNull;useAffectedRows=true

spring.datasource.username=

spring.datasource.password=

spring.datasource.initSQL=SELECT 1

spring.datasource.tomcat.max-wait=3000

spring.datasource.tomcat.mac-active=2

spring.datasource.tomcat.test-on-borrow=true


c) JdbcTemplate 으로 CRUD 를 한다.

@Autowired JdbcTemplate jdbcTemplate;


public List<MyLotto> selectList() {

String query = "SELECT * FROM mylotto ORDER BY seq desc LIMIT 10";

return jdbcTemplate.query(query, new BeanPropertyRowMapper<MyLottoVO>(MyLottoVO.class));

}


2. MyBatis 연동.

a) mybatis-spring-boot-starter 를 추가한다.(1.2.0 이 있지만... parent version 1.5.2에선 안 되는 듯)

<dependency>

<groupId>org.mybatis.spring.boot</groupId>

<artifactId>mybatis-spring-boot-starter</artifactId>

<version>1.1.1</version>

</dependency>


b) using simple mapper 

- dependency 를 추가하고, datasource에 대한 application.properties 설정이 되어 있단면 아래의 interface Mapper 만 있으면 동작한다.

@Mapper

public interface MyLottotMapper {

@Select("SELECT * FROM mylotto WHERE key = #{key}")

MyLotto selectOne(@Param("key") Integer key);


@Select("SELECT NOW() FROM DUAL")

String selectCurrentDateTime();

}


c) using SqlSession

- Dao, Repository 역할을 가지는 클래스를 만든다.

@Repository

public class MyLottoRepository {

private final SqlSession sqlsession;


public MyLottoRepository(SqlSession sqlsession) {

this. sqlsession = sqlsession;

}


public MyLotto selectOne() {

return (MyLotto) this.sqlSession.selectOne("com.joochang.lotto.selectOne"); 

}

}

- mapper.xml 을 만든다.

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.joochang.lotto">

<resultMap id="myLotto" type="com.joochang.lotto.MyLotto">

...

</resultMap>

<select id="selectOne" resultMap="myLotto">

<![CDATA[

SELECT * FROM mylotto LIMIT 1

]]>

</select>

</mapper>


3. JPA 연동.

a) JPA 를 MySql과 함께 사용하려면 먼저 아래와 같이 pom.xml 에 dependency 를 추가해 줍니다.

<!-- jpa 안에 jdbc 포함 -->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-jpa</artifactId>

</dependency>

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

</dependency>

b) application.properties 에 JPA와 관련된 설정을 추가합니다.

spring.jpa.databas=MYSQL

spring.jpa.show-sql=true

# 테스트할 때 유용할 것 같은 기능. #실환경에서 돌린다면 지옥을 경험한다..

# spring.jpa.hibernate.ddl-auto=create # create or create-drop

c) Entity 클래스를 생성합니다.

@Entity

public class MyLotto {

@Id

@GeneratedValue(strategy = GenerationType.AUTO)

private int id;

private String name;


(생략)...

}

d) Dao, Repository 역할을 가지는 interface 를 만들어야 합니다.

public interface MyLottoJPA extends CrudRepository<MyLotto, Integer> {

MyLotto findById(Integer id);

}

또는

public interface MyLottoJPA extends JpaRepository<MyLotto, Integer> {

MyLotto findById(Integer id);

}


D. Logger

spring-boot는 모든 내부 로깅에 대해서 Commons-Loggins-API 를 사용합니다. 기본 구성은 Java-Util-Logging, Log4j2logback 입니다. 기본적으로 spring-boot 'Starters' 를 사용하면 logback 이 사용될 것인데, Java-Util-Logging, Commons-Logging, Log4j 또는 SLF4J 를 사용하는 의존적인 라이브러리들이 모두 올바르게 동작하도록 적절한 logback 라우팅이 포함됩니다.


a) spring-boot는 콘솔에 INFO 레벨 로그를 표시하려고 로그백(http://logback.qos.ch)으로 로깅을 설정합니다. 로깅 구성을 완전히 제어하려면 클래스패스 루트(src/main/resources)에 logback.xml 파일을 생성해야 합니다. logback.xml 이 존재하면 우선적으로 파일의 내용이 적용됩니다. 다르게 하려면 logback.xml 의 이름을 변경하고 (logback-spring.xml) application.properties 에 로그설정들을 추가하면 됩니다.

참고) applcation.properties

logging.config=classpath:logback-spring.xml

logging.exception-conversion-word=

logging.file=

logging.level=

logging.path=

logging.pattern.console=


b) 만약 logback 대신 log4j2 를 사용하고 싶다면 다음과 같이 해야 합니다.

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter</artifactId>

<exclusions>

<exclusion>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-logging</artifactId>

</exclusion>

</exclusions>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-log4j2</artifactId>

</dependency>


references of loggers)

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-logging.html

https://docs.spring.io/spring-boot/docs/current/reference/html/howto-logging.html


E. Profile

 스프링 프레임워크는 스프링 3.1부터 Profile-Based Configuration을 지원했습니다. 이것은 애플리케이션의 환경설정을 분리하는 방법이면서 특정한 환경을 구성하기도 합니다. @Component나 @Configuration 은 @Profile 과 함께 쓰여 애플리케이션의 로딩을 제한할 수 있습니다.

 spring-boot를 빌드 및 실행 시 "no profiles are currently active" 라는 메시지를 마주칠 수 있는데요. 에러는 spring.profiles.active 값을 설정하면 해결할 수 있습니다. pom.xml 과 src/main/resrouce 의 application.properties 에 대한 설정을 다음과 같이 합니다.


참고) pom.xml

<properties>

<activeProfile>local</activeProfile>

</properties>

<profiles>

<profile>

<id>local</id>

<activation>

<activationByDefault>true</activationByDefault>

</activation>

<properties>

<activeProfile>local</activeProfile>

</properties>

</profile>

<profile>

<id>release</id>

<properties>

<activeProfile>release</activeProfile>

</properties>

</profile>

</profiles>


참고) application.properties

spring.profiles.active=@activeProfiles@

위와 같이 설정 후 application-{profile}.properties 형태의 입맛에 맞는 파일들을 생성하여 사용할 수 있으며, 실행은 아래와 같이 합니다.

java -jar -Dspring.profiles.active=local target/lotto-0.0.1-SNAPSHOT.jar

또는 각 서버에서 환경변수 설정을 통해 사용할 수 있습니다.

export SPRING_PROFILES_ACTIVE=release


references of profiles)

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html

- https://docs.spring.io/spring-boot/docs/current/reference/html/howto-properties-and-configuration.html

https://groups.google.com/forum/#!topic/ksug/BBaO3y8hSaU



Spring-boot-profiles

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html


Common-Application-Properties

http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html


Etc...

http://www.mybatis.org/spring-boot-starter/

https://github.com/spring-projects/spring-boot

https://www.slideshare.net/madvirus/spring-boot-42817314

https://www.slideshare.net/whiteship/ss-47273947



반응형
반응형

Gradle 간단히 사용하기.


Maven 은 사용한지 오래되기도 했고 익숙하지만 Gradle 아직 회사에서 사용을 안 하여;; ㅠㅠ ;;잘 잊어버리곤해서 간단한 Gradle 설치와 실행을 확인해 보고자 한다.


1. Gradle 설치 및 간단한 실행.

  • 먼저 Gradle 사이트에 접속한다.(https://gradle.org/gradle-download/)
  • sdkman 을 사용하던지, 개별적으로 download 하여 $PATH 와 $CLASSPATH 를 설정한다.(나는 후자)
  • 간단한 java project 를 생성 및 Helloworld.java 를 만들고, 프로젝트 폴더 안에 build.gradle 파일을 생성한다.
  • 생성한 build.gradle 에 apply plugin: 'java' 를 한 줄 넣는다.
  • gradle tasks 명령어를 실행해서 콘솔에 뜨는 목록들을 확인해 본다.
  •  gradle build 명령어를 사용하면 test, compile 후 jar 파일이 만들어 지는 것을 볼 수 있다.

실행한 java 파일은 다음과 같습니다.

package main.java.hello;


import org.joda.time.LocalTime;


public class HelloWorld {

public static void main(String[] args) {

LocalTime currentTime = new LocalTime();

System.out.println("The current local time is: " + currentTime);

Greeter greeter = new Greeter();

System.out.println(greeter.sayHello());

}

}


class Greeter {

public String sayHello() {

return "Hello world!";

}

}



2. Gradle 의존 파일들 추가하기.

 

Maven Central 을 추가했듯이 다음과 같이 build.gradle 파일에 추가한다.

repositories {

    mavenCentral()

}


필요한 dependencis 도 추가한다.

sourceCompatibility = 1.8

targetCompatibility = 1.8


dependencies {

    compile "joda-time:joda-time:2.2"

    testCompile "junit:junit:4.12"

}


그리고 JAR Artifact 의 이름도 정의한다.

jar {

    baseName = 'java-test'

    version = '0.1.0'

}


다시 gradle build 를 수행하면 정상적으로 수행된다. (dependency 된 import 는 주석처리)



3. 빌드를 쉽게 도와주는 Gradle Wrapper.


다음의 스크립트를 사용하면 시스템에 Gradle을 설치하지 않고도 Gradle 빌드를 수행할 수 있습니다.

$ gradle wrapper --gradle-version 3.3


생성된 명령어로 빌드를 할 수 있습니다.

./gradlew build


생성된 jar 를 실행해 봅니다. 

$ jar tvf build/libs/java-test-0.1.0.jar

0 Thu Jan 05 01:42:22 KST 2017 META-INF/

25 Thu Jan 05 01:01:30 KST 2017 META-INF/MANIFEST.MF

0 Thu Jan 05 01:01:30 KST 2017 main/

0 Thu Jan 05 01:01:30 KST 2017 main/java/

0 Thu Jan 05 01:42:22 KST 2017 main/java/hello

389 Thu Jan 05 01:42:22 KST 2017 main/java/hello/Greeter.class

1028 Thu Jan 05 01:42:22 KST 2017 main/java/hello/HelloWorld.class


작업한 코드를 실행할 수 있게 하려면 gradle 의 applicaiton 플러그인을 추가해야 합니다. 

build.gradle 파일에 다음과 같이 추가하세요.

apply plugin: 'application'

mainClassName = 'hello.HelloWorld'


자 이제 다시 실행해 봅시다.

$ ./gradlew run


지금은 jar 로 실행했는데요. 

war 로 실행되기를 원하면, 플러그인을 추가하면 됩니다. (https://docs.gradle.org/current/userguide/war_plugin.html)


다 만들어진 build.gradle 파일은 아래처럼 될 것 같습니당.


apply plugin: 'java'

apply plugin: 'application'

mainClassName = 'main.java.hello.HelloWorld'


// For starters, you need to add a source for 3rd party libraries.

// tag::repositories[]

repositories {

    mavenCentral()

}

// end::repositories[]


// tag::jar[]

jar {

    baseName = 'java-test'

    version =  '0.1.0'

}

// end::jar[]


// tag::dependencies[]

sourceCompatibility = 1.8

targetCompatibility = 1.8


dependencies {

    compile "joda-time:joda-time:2.2"

    testCompile "junit:junit:4.12"

}

// end::dependencies[]





반응형
반응형

Spring4 + myBatis 환경에서 트랜잭션 설정하기.

트랜잭션 위주로 정리해 봅니다. mybatis 는 뭐 정보가 많으니 패스하겠습니다.


1. 기본 설정.

transaction 범위와 관련하여, dispatch-servlet 에서와  applicaitonContext.xml 에서의  component-scan 설정을 수정해 줘야 합니다.

mvc-config.xml

<context:component-scan base-package="com.slowstarter" use-default-filters="false">

<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />

</context:component-scan>


applicationContext.xml

<context:component-scan base-package="com. slowstarter">

<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />

</context:component-scan>


poll(dbcp2, c3po), mybatis 등 필요한 dependency 설정들 추가하기. 

<dependency>

<groupId>org.mybatis</groupId>

<artifactId>mybatis</artifactId>

<version>3.4.0</version>

</dependency>


<dependency>

<groupId>org.aspectj</groupId>

<artifactId>aspectjweaver</artifactId>

<version>1.8.1</version>

</dependency>


2. aop 를 통한 설정.


<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="pushDataSource" />

</bean>


<tx:annotation-driven transaction-manager="transactionManager" mode="proxy"/>


<tx:advice id="txAdvice"  transaction-manager="transactionManager">

<tx:attributes>

<tx:method name="createTest"

    isolation="REPEATABLE_READ"

    propagation="REQUIRED"

    rollback-for"RuntimeException" />

</tx:attributes>

</tx:advice>


<aop:config>

<aop:pointcut id="servicePublicMethod"

                expression="execution(* com.joochang.service.*Service.*(..))" />

<aop:adviser id="transactionAdvisor"

               pointcut-ref="servicePubicMethod" advice-ref="txAdvice" />

</aop:config>


- 스프링AOP 대신 AspectJ-AOP를 사용하는 방법도 있다. AspectJ는 프록시 대신 클래스 바이트코드를 직접 변경해서 부가기능을 추가하기 때문에 타깃 오브젝트의 자기 호출 중에도 트랜잭션 부가기능이 잘 적용된다. 굳이 자신의 메소드를 호출하는 경우에도 트랜잭션 속성이 정확히 적용되기를 원한다면 AspectJ를 사용하는편이 좋다. <tx:annotation-driven mode="aspectj" /> 처럼 설정하면 된다. (Spring AOP 는 기본적으로 JDK프록시이고, AspectJ는 클래스기반 프록시)


3. annotation 을 통한 설정. 

 MySql 은 기본 isolation 이 repeatable_read  인데, spring  의 default 가 알아서 맞춰주는지 알아볼 필요도 있고 명확하게 해당 타입을 지정해 주는게 더 와 닿는 것 같습니다.


@Transactional(propagation = Propagarion.REQUIRED,

                  isolation = Isolation.REPEATABLE_READ,

                  rollbackFor = RuntimeException.class)

public MyTestResult createTest() throws RuntimeException {

...

}


 선언적 트랜잭션에서는 런타입 예외가 발생하면 롤백합니다. 반면에 예외가 전혀 발생하지 않거나 checked-exception이 발생하면 commit 합니다.  스프링에서 data-access-exception은 Runtime-Exception으로 전환돼서 던져지므로 Runtime-Exception만 롤백대상이 됩니다. 하지만 롤백대상으로 삼아야 한다면 rollbackFor 를 사용해서 등록합니다. 반대로 기본적인 롤백대상인 Runtime-Exception을 트랜잭션 커밋 대상으로 해 주려면 noRollbackFor 를 사용하면 됩니다.


 그리고 rollback 시 createTest() 에서 만약 try catch 쓸 경우 statement 안에서 예외를 잡더라도 throw new RuntimeException  하지 않으면 롤백되지 않습니다. 또한 finally 로 뭔가 동작을 하길 바래서 사용한다면 ㅠㅠ rollback 이 되지 않습니다.


4. 기타 사항. 

 스프링의 Proxy 는 2가지 타입이 있습니다.  JDK Reflection API 를 사용한 JDK다이내믹프록시 와 CBLIB(Code Generator Library) 인데요. JDK프록시는 인터페이스를 구현한 클래스에 적용이되고, CBLIB은 spring 3.2부터 기본적용이 되어있어서 인터페이스를 사용하지 않은 클래스에 대해 적용이 됩니다.

 스프링AOP는 기본적으로 JDK Reflection API를 사용하여 Spring에 의해 생성 된 다이내믹 프록시 기법을 이용해 동작합니다. 다이내믹 프록시를 적용하려면 인터페이스가 있어야 하지만 스프링 내부의 ProxyFactoryBean 클래스나 CGLIB 라이브러리가 제공해주는 클래스 레벨의 프록시도 사용할 수 있습니다. AspectJ를 사용해 트랜잭션을 적용할 때는 앞에서 설명한 것처럼 @Transactional을 클래스레벨과 클래스 메소드 레벨에 부여해야 한다는 점을 주의해야합니다. AspectJ 모드를 사용하면서 인터페이스에만 @Transactional을 부여하면 트랜잭션이 적용되지 않습니다. 그래서 클래스프록시 모드에서는 Service 코드에 인터페이스를 Implements 해야한다는니 이런 거 필요없습니다.


명확하게 CGLIB을 사용하려면 proxy-target-class=true 옵션을 아래의 설정에 추가 해야만 합니다.

<tx:annotation-driven proxy-target-class="true">

또는 <aop:config proxy-targer-class="true"> </aop:config>

또는 <aop:aspectj-autoproxy proxy-target-class="true"> //  aspectj는 기본이 클래스모드

또는 @EnableAspectJAutoProxy(proxyTargetClass=true)

또는 spring.aop.proxy-target-class=true // application.properties 




반응형

+ Recent posts