회사에서 업무 중 미완성된 알림 서비스(스케쥴러) 소스 코드 중에 정말 잘 만든 소스 코드를 보게되었습니다.

관련 코드에 문제가 있어서 코드 수정하는겸 , 코드에 대해서 공부할겸 관련해서 코드 모사를 가볍게 해봤습니다.

Method getterMethod=property.getClass().getMethod("getWorkflowEntity");
                   Object targetEntity = getterMethod.invoke(property);
@CallerSensitive
    public Method getMethod(String name, Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException {
        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
        Method method = getMethod0(name, parameterTypes, true);
        if (method == null) {
            throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
        }
        return method;
    }

 

workflow id 를 통해서 => 부모 workflow의 데이터를 가지고 오려고 하는 의도인듯 했습니다.

 

entity 클래스

@Setter
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "table")
@EntityListeners(AuditingEntityListener.class)
public class PropertyEntity extends BaseEntity {

	@GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
	long seq_id;

	String workflowid;

	String workid;

	@OneToOne(cascade = CascadeType.ALL)
	@JoinColumn(name = "workflow_seq", referencedColumnName = "seq")
	WorkflowEntity workflowEntity;

	public static PropertyEntity of(String workflowid) {
		return PropertyEntity.builder()
				.workflow_definition_key(workflowid)
			.build();
	}

	public static PropertyEntity of(String workflowid, String workid) {
	   return PropertyEntity.builder()
			 .workflow_definition_key(workflowid)
			   .taskId(workid)
		   .build();
	}

	public static PropertyEntity ofProperty(String workid, String workflowid) throws JsonProcessingException {
		return PropertyEntity.builder()
				.taskId(workid)
				.workflow_definition_key(workflowid)
				.build();
	}
}

 

관련 propertyEntity table이고 WorkFlowEntity db Join을 하여 seq를 통해서 one to one 관계를 가집니다. 

이후 데이터를 invoke를 통해서 workflowEntity 테이블의 모든 데이터를 가져올수 있습니다.

 

개인적으로 봐도 정말 잘 만든 코드여서 비슷하게 다시 구현해서 만들어 봤습니다.

 

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

Spring Data JPA - 구성  (0) 2024.02.25
Spring Data JPA- repository 인터페이스의 정의  (0) 2024.02.18
Spring Data JPA - 핵심 개념  (0) 2024.02.03
Spring Data JPA에 대해서  (0) 2024.02.03
톰캣의 war 실행되는 원리?  (0) 2024.01.14

2024.02.18 - [웹/Spring] - Spring jpa - repository 인터페이스의 정의

 

Spring jpa - repository 인터페이스의 정의

2024.02.03 - [웹/Spring] - Spring Data JPA - 핵심 개념 Spring Data JPA - 핵심 개념 2024.02.03 - [끄적이기] - JPA에 대해서 JPA에 대해서 JPA? 자바 퍼시스턴스(Java Persistence, 이전 이름: 자바 퍼시스턴스 API/Java Persist

kwaksh2319.tistory.com

Spring Data JPA 리포지토리 지원은 다음 예시와 같이 JavaConfig와 사용자 지정 XML 네임스페이스를 통해 활성화될 수 있습니다.

@Configuration
@EnableJpaRepositories
@EnableTransactionManagement
class ApplicationConfig {

  @Bean
  public DataSource dataSource() {

    EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
    return builder.setType(EmbeddedDatabaseType.HSQL).build();
  }

  @Bean
  public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    vendorAdapter.setGenerateDdl(true);

    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setJpaVendorAdapter(vendorAdapter);
    factory.setPackagesToScan("com.acme.domain");
    factory.setDataSource(dataSource());
    return factory;
  }

  @Bean
  public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {

    JpaTransactionManager txManager = new JpaTransactionManager();
    txManager.setEntityManagerFactory(entityManagerFactory);
    return txManager;
  }
}

 

앞서 언급된 구성 클래스는 spring-jdbc의 EmbeddedDatabaseBuilder API를 사용하여 내장 HSQL 데이터베이스를 설정합니다. 그런 다음 Spring Data는 EntityManagerFactory를 설정하고 샘플 영속성 제공자로 Hibernate를 사용합니다. 여기에 선언된 마지막 인프라 구성 요소는 JpaTransactionManager입니다. 마지막으로, 예제는 @EnableJpaRepositories 주석을 사용하여 Spring Data JPA 리포지토리를 활성화하는데, 이는 본질적으로 XML 네임스페이스와 같은 속성을 가집니다. 기본 패키지가 구성되지 않은 경우, 구성 클래스가 위치한 패키지를 사용합니다.

 

*  EmbeddedDatabaseBuilder API?

EmbeddedDatabaseBuilder API는 Spring Framework의 일부로, 개발자가 손쉽게 내장형 데이터베이스를 구성하고 사용할 수 있게 해주는 도구입니다. 이 API는 spring-jdbc 모듈에 포함되어 있으며, 주로 테스트나 프로토타이핑 목적으로 사용됩니다. EmbeddedDatabaseBuilder를 사용하면 HSQL, H2, Derby와 같은 인메모리 데이터베이스를 코드 몇 줄로 설정할 수 있습니다. 이 API를 통해 데이터베이스 인스턴스를 생성하고, SQL 스크립트를 실행하여 스키마를 초기화하거나 테스트 데이터를 로드할 수 있습니다.

EmbeddedDatabaseBuilder는 매우 유연하며, 데이터베이스 타입, 초기화 스크립트, 종료 옵션 등을 설정할 수 있는 다양한 메서드를 제공합니다. 이를 통해 애플리케이션이나 테스트 실행 시 필요한 데이터베이스 환경을 쉽게 준비하고 관리할 수 있습니다.

 

* 내장 HSQL 데이터베이스?

HSQLDB(HyperSQL DataBase)는 자바로 작성된 관계형 데이터베이스 관리 시스템(RDBMS)입니다. 이 데이터베이스는 주로 내장 데이터베이스로 사용되며, 애플리케이션에 직접 포함될 수 있습니다. HSQLDB는 작고 빠르며, SQL-92 표준의 상당 부분을 지원합니다. 인메모리 운영 모드를 지원하기 때문에, 애플리케이션 테스트나 개발 과정에서 빠르게 데이터베이스 환경을 구축하고 사용할 수 있습니다.

내장 HSQL 데이터베이스의 주요 장점은 별도의 서버 설치나 관리 없이 애플리케이션 내부에서 직접 데이터베이스를 실행할 수 있다는 것입니다. 이는 개발 및 테스트 과정을 간소화하고, 애플리케이션의 배포와 이식성을 향상시킵니다. HSQLDB는 자바 기반 애플리케이션과의 통합이 용이하며, JUnit 테스트 등에서 데이터베이스 환경을 요구하는 경우 유용하게 사용될 수 있습니다.

 

*Spring 네임스페이스

Spring Data의 JPA 모듈에는 리포지토리 빈을 정의할 수 있는 사용자 지정 네임스페이스가 포함되어 있습니다. 또한 JPA에 특화된 특정 기능과 요소 속성을 포함하고 있습니다. 일반적으로, JPA 리포지토리는 다음 예시와 같이 repositories 요소를 사용하여 설정할 수 있습니다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:jpa="http://www.springframework.org/schema/data/jpa"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/data/jpa
    https://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

  <jpa:repositories base-package="com.acme.repositories" />

</beans>

 

repositories 요소를 사용하면 @Repository로 주석이 달린 모든 빈에 대해 영속성 예외 변환을 활성화하여, JPA 영속성 제공자에 의해 발생된 예외들이 Spring의 DataAccessException 계층 구조로 변환되게 합니다.

 

*  JPA 영속성이란?

자바 애플리케이션에서 객체와 데이터베이스 테이블 사이의 매핑을 관리하는 방법입니다. 이는 자바 표준으로, 개발자가 데이터베이스 작업을 보다 쉽게 할 수 있도록 도와주며, 객체 지향 프로그래밍과 관계형 데이터베이스 사이의 간극을 줄여줍니다.

JPA를 사용하면 개발자는 복잡한 SQL 쿼리를 작성하는 대신, 객체의 상태 변화를 데이터베이스에 자동으로 반영할 수 있습니다. 이를 통해 객체를 생성, 조회, 업데이트 및 삭제하는 작업을 객체 지향적인 방식으로 처리할 수 있습니다. JPA는 이러한 작업을 위한 API와 런타임 환경을 제공합니다.

영속성 컨텍스트라고 불리는 JPA의 핵심 개념은 엔티티의 생명 주기를 관리합니다. 영속성 컨텍스트는 엔티티를 관리하며, 엔티티의 상태 변화를 추적하여 데이터베이스에 반영합니다. 엔티티가 영속성 컨텍스트에 의해 관리될 때, 그 엔티티는 '영속 상태'에 있으며, 이 상태에서는 JPA가 자동으로 데이터베이스와의 동기화를 처리합니다.

이러한 방식으로 JPA 영속성은 개발자가 데이터베이스와의 상호작용을 추상화하고, 데이터베이스 작업을 보다 직관적이고 객체 지향적인 방식으로 수행할 수 있도록 도와줍니다.

 

*사용자 지정 네임스페이스 속성

repositories 요소의 기본 속성을 넘어서, JPA 네임스페이스는 리포지토리 설정에 대한 보다 상세한 제어를 할 수 있도록 추가 속성을 제공합니다.

    표1.  repositories 요소의 사용자 지정 JPA 특정 속성

entity-manager-factory-ref repositories 요소에 의해 감지된 리포지토리와 함께 사용될 EntityManagerFactory를 명시적으로 연결합니다. 보통 애플리케이션 내에서 여러 EntityManagerFactory 빈들이 사용될 경우에 사용됩니다. 구성되지 않은 경우, Spring Data는 ApplicationContext 내에서 entityManagerFactory라는 이름의 EntityManagerFactory 빈을 자동으로 찾습니다.
transaction-manager-ref repositories 요소에 의해 감지된 리포지토리와 함께 사용될 PlatformTransactionManager를 명시적으로 연결합니다. 보통 여러 트랜잭션 매니저 또는 EntityManagerFactory 빈들이 구성된 경우에만 필요합니다. 현재 ApplicationContext 내에서 단일로 정의된 PlatformTransactionManager를 기본값으로 합니다.

주의)

  명시적인 transaction-manager-ref가 정의되어 있지 않은 경우, Spring Data JPA는 transactionManager라는 이름의 PlatformTransactionManager 빈이 존재해야 합니다.

 

*bootstrap mode

기본적으로, Spring Data JPA 리포지토리는 기본적으로 Spring 빈입니다. 이들은 싱글톤 범위를 가지며 즉시 초기화됩니다. 시작하는 동안, 그들은 검증 및 메타데이터 분석 목적으로 JPA EntityManager와 이미 상호작용합니다. Spring Framework는 JPA EntityManagerFactory의 초기화를 백그라운드 스레드에서 지원합니다. 왜냐하면 그 과정은 보통 Spring 애플리케이션의 시작 시간에서 상당한 양을 차지하기 때문입니다. 그 백그라운드 초기화를 효과적으로 사용하기 위해, JPA 리포지토리가 가능한 한 늦게 초기화되도록 해야 합니다.

 

Spring Data JPA 2.1부터, 이제 @EnableJpaRepositories 주석 또는 XML 네임스페이스를 통해 다음 값을 가지는 BootstrapMode를 구성할 수 있습니다:

DEFAULT (기본값) — 리포지토리는 명시적으로 @Lazy로 주석이 달리지 않는 한 즉시 인스턴스화됩니다. 
                    이 지연화는 리포지토리의 인스턴스가 필요하지 않는 클라이언트 빈이 없을 때만
                    효과가 있습니다. 왜냐하면 그것은 리포지토리 빈의 초기화를 요구하기 때문입니다.

LAZY — 모든 리포지토리 빈을 암시적으로 지연된 것으로 선언하고 클라이언트 빈에 주입될 지연 초기화
       프록시를 생성합니다. 
       즉, 클라이언트 빈이 단순히 인스턴스를 필드에 저장하고 초기화하는 동안 리포지토리를 
       사용하지 않는 경우 리포지토리가 인스턴스화되지 않습니다. 리포지토리 인스턴스는 
       리포지토리와의 첫 번째 상호작용 시 초기화되고 검증됩니다.

DEFERRED — 기본적으로 LAZY와 동일한 운영 모드이지만, 
            애플리케이션이 완전히 시작되기 전에 리포지토리가 검증되도록 하여
            ContextRefreshedEvent에 대한 반응으로 리포지토리 초기화를 트리거합니다.

 

*추천 사항

비동기적인 JPA 부트스트랩을 사용하지 않는 경우, 기본 bootstrap mode 를 사용하세요.

JPA를 비동기적으로 bootStrap 하는 경우, DEFERRED는 합리적인 기본값입니다. 이는 EntityManagerFactory 설정이 애플리케이션의 다른 모든 구성 요소를 초기화하는 것보다 더 오래 걸릴 경우에만 Spring Data JPA 부트스트랩이 대기하도록 합니다. 그럼에도 불구하고, 애플리케이션이 준비되었다고 신호하기 전에 리포지토리가 제대로 초기화되고 검증되도록 합니다.

LAZY는 테스트 시나리오와 로컬 개발에 적합한 선택입니다. 리포지토리가 제대로 부트스트랩될 수 있다는 것을 확신하거나, 애플리케이션의 다른 부분을 테스트하는 경우에, 모든 리포지토리에 대한 검증을 실행하는 것은 시작 시간을 불필요하게 증가시킬 수 있습니다. 로컬 개발에서도, 단일 리포지토리만 초기화해야 하는 애플리케이션의 일부분에만 접근할 경우 같은 원칙이 적용됩니다.

 

참조: 

https://docs.spring.io/spring-data/jpa/reference/repositories/create-instances.html

 

Configuration :: Spring Data JPA

By default, Spring Data JPA repositories are default Spring beans. They are singleton scoped and eagerly initialized. During startup, they already interact with the JPA EntityManager for verification and metadata analysis purposes. Spring Framework support

docs.spring.io

 

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

Reflection api GetMethod  (0) 2024.04.20
Spring Data JPA- repository 인터페이스의 정의  (0) 2024.02.18
Spring Data JPA - 핵심 개념  (0) 2024.02.03
Spring Data JPA에 대해서  (0) 2024.02.03
톰캣의 war 실행되는 원리?  (0) 2024.01.14

2024.02.03 - [웹/Spring] - Spring Data JPA - 핵심 개념

 

Spring Data JPA - 핵심 개념

2024.02.03 - [끄적이기] - JPA에 대해서 JPA에 대해서 JPA? 자바 퍼시스턴스(Java Persistence, 이전 이름: 자바 퍼시스턴스 API/Java Persistence API) 또는 자바 지속성 API(Java Persistence API, JPA)는 자바 플랫폼 SE와

kwaksh2319.tistory.com

 

저장소 인터페이스를 정의하려면 먼저 도메인 클래스별 저장소 인터페이스를 정의해야 합니다. 인터페이스는 Repository를 확장하고 도메인 클래스 및 ID 유형에 타입이 지정되어야 합니다. 해당 도메인 유형에 대한 CRUD 메소드를 노출하려면 Repository 대신 CrudRepository 또는 그 변형 중 하나를 확장할 수 있습니다.

 

저장소 인터페이스 정의를 세밀하게 조정하는 방법에는 몇 가지 변형이 있습니다.

전형적인 접근 방식은 CrudRepository를 확장하는 것이며, 이는 CRUD 기능을 위한 메소드를 제공합니다. CRUD는 생성(Create), 읽기(Read), 업데이트(Update), 삭제(Delete)를 의미합니다. 버전 3.0에서는 ListCrudRepository도 도입했는데, 이는 CrudRepository와 매우 유사하지만 다수의 엔티티를 반환하는 메소드의 경우 Iterable 대신 List를 반환하여 사용하기 더 쉬울 수 있습니다.

반응형 저장소를 사용하는 경우 사용하는 반응형 프레임워크에 따라 ReactiveCrudRepository 또는 RxJava3CrudRepository를 선택할 수 있습니다.

 

Kotlin을 사용하는 경우 코틀린의 코루틴을 활용하는 CoroutineCrudRepository를 선택할 수 있습니다.

추가로, Sort 추상화를 지정할 수 있는 메소드가 필요한 경우 PagingAndSortingRepository, ReactiveSortingRepository, RxJava3SortingRepository 또는 CoroutineSortingRepository를 확장할 수 있습니다. 첫 번째 경우 Pageable 추상화를 지정할 수 있습니다. 다양한 정렬 저장소는 Spring Data 버전 3.0 이전처럼 각각의 CRUD 저장소를 확장하지 않습니다. 따라서 두 기능 모두를 원하는 경우 두 인터페이스를 모두 확장해야 합니다.

 

Spring Data 인터페이스를 확장하고 싶지 않은 경우, @RepositoryDefinition으로 저장소 인터페이스를 주석 처리할 수도 있습니다. CRUD 저장소 인터페이스 중 하나를 확장하면 엔티티를 조작하는 메소드의 완전한 세트가 노출됩니다. 노출되는 메소드를 선택적으로 결정하고 싶다면, 원하는 메소드를 CRUD 저장소에서 도메인 저장소로 복사하세요. 이렇게 할 때 메소드의 반환 유형을 변경할 수 있습니다. 가능한 경우 Spring Data는 반환 유형을 존중합니다. 예를 들어, 다수의 엔티티를 반환하는 메소드의 경우 Iterable<T>, List<T>, Collection<T> 또는 VAVR 리스트를 선택할 수 있습니다.

 

애플리케이션의 많은 저장소가 같은 메소드 세트를 가져야 한다면, 상속받을 자체 기본 인터페이스를 정의할 수 있습니다. 이러한 인터페이스는 @NoRepositoryBean으로 주석 처리되어야 합니다. 이는 Spring Data가 직접 인스턴스를 생성하려고 시도하고 실패하는 것을 방지하기 위함입니다. 왜냐하면 여전히 일반 유형 변수를 포함하고 있어 해당 저장소의 엔티티를 결정할 수 없기 때문입니다.

 

다음 예시는 CRUD 메소드(이 경우 findById와 save)를 선택적으로 보여줍니다.

 

@NoRepositoryBean
interface MyBaseRepository<T, ID> extends Repository<T, ID> {

  Optional<T> findById(ID id);

  <S extends T> S save(S entity);
}

interface UserRepository extends MyBaseRepository<User, Long> {
  User findByEmailAddress(EmailAddress emailAddress);
}

 

이전 예시에서, 모든 도메인 저장소에 대한 공통 기본 인터페이스를 정의하고 findById(...)와 save(...) 메소드를 노출시켰습니다. 이 메소드들은 CrudRepository에 있는 메소드 시그니처와 일치하기 때문에, 선택한 저장소의 Spring Data 제공 기본 저장소 구현체(예를 들어, JPA를 사용하는 경우 SimpleJpaRepository 구현체)로 라우팅됩니다. 따라서 UserRepository는 이제 사용자를 저장하고, ID로 개별 사용자를 찾고, 이메일 주소로 사용자를 찾기 위한 쿼리를 트리거할 수 있습니다.

 

애플리케이션에서 단일 Spring Data 모듈을 사용하는 것은 모든 저장소 인터페이스가 정의된 범위 내에서 해당 Spring Data 모듈에 바인딩되기 때문에 일이 간단해집니다. 그러나 때로는 둘 이상의 Spring Data 모듈을 사용해야 하는 상황이 발생합니다. 이런 경우에는 저장소 정의가 영속성 기술 사이를 구별해야 합니다. 클래스 경로상에 여러 저장소 팩토리가 감지되면, Spring Data는 엄격한 저장소 구성 모드로 전환됩니다. 엄격한 구성은 저장소 또는 도메인 클래스에 대한 세부 정보를 사용하여 저장소 정의에 대한 Spring Data 모듈 바인딩을 결정합니다:

  • 저장소 정의가 모듈 특정 저장소를 확장하는 경우, 해당 Spring Data 모듈에 대한 유효한 후보가 됩니다.
  • 도메인 클래스가 모듈 특정 유형 주석으로 주석이 달린 경우, 해당 Spring Data 모듈에 대한 유효한 후보가 됩니다. Spring Data 모듈은 JPA의 @Entity와 같은 타사 주석이나 Spring Data MongoDB 및 Spring Data Elasticsearch의 @Document와 같은 자체 주석을 허용합니다.

다음 예시는 모듈 특정 인터페이스(JPA인 경우)를 사용하는 저장소를 보여줍니다:

interface MyRepository extends JpaRepository<User, Long> { }

@NoRepositoryBean
interface MyBaseRepository<T, ID> extends JpaRepository<T, ID> { … }

interface UserRepository extends MyBaseRepository<User, Long> { … }
interface AmbiguousRepository extends Repository<User, Long> { … }

@NoRepositoryBean
interface MyBaseRepository<T, ID> extends CrudRepository<T, ID> { … }

interface AmbiguousUserRepository extends MyBaseRepository<User, Long> { … }
interface PersonRepository extends Repository<Person, Long> { … }

@Entity
class Person { … }

interface UserRepository extends Repository<User, Long> { … }

@Document
class User { … }
interface JpaPersonRepository extends Repository<Person, Long> { … }

interface MongoDBPersonRepository extends Repository<Person, Long> { … }

@Entity
@Document
class Person { … }

엄격한 저장소 구성을 위해 저장소 유형 세부 정보와 도메인 클래스 주석을 구별하는 것은 특정 Spring Data 모듈에 대한 저장소 후보를 식별하는 데 사용됩니다. 동일한 도메인 유형에 여러 영속성 기술 특정 주석을 사용하는 것이 가능하며, 이는 여러 영속성 기술에 걸쳐 도메인 유형의 재사용을 가능하게 합니다. 그러나 이 경우 Spring Data는 더 이상 저장소와 바인딩할 유일한 모듈을 결정할 수 없습니다.

저장소를 구별하는 마지막 방법은 저장소 기본 패키지의 범위를 지정하는 것입니다. 기본 패키지는 저장소 인터페이스 정의를 스캔하기 위한 시작점을 정의하며, 이는 적절한 패키지에 저장소 정의가 위치해야 함을 의미합니다. 기본적으로, 주석 기반 구성은 구성 클래스의 패키지를 사용합니다. XML 기반 구성에서는 기본 패키지가 필수입니다.

 

@EnableJpaRepositories(basePackages = "com.acme.repositories.jpa")
@EnableMongoRepositories(basePackages = "com.acme.repositories.mongo")
class Configuration { … }

https://docs.spring.io/spring-data/jpa/reference/repositories/definition.html

 

Defining Repository Interfaces :: Spring Data JPA

To define a repository interface, you first need to define a domain class-specific repository interface. The interface must extend Repository and be typed to the domain class and an ID type. If you want to expose CRUD methods for that domain type, you may

docs.spring.io

 

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

Reflection api GetMethod  (0) 2024.04.20
Spring Data JPA - 구성  (0) 2024.02.25
Spring Data JPA - 핵심 개념  (0) 2024.02.03
Spring Data JPA에 대해서  (0) 2024.02.03
톰캣의 war 실행되는 원리?  (0) 2024.01.14

2024.02.03 - [끄적이기] - JPA에 대해서

 

JPA에 대해서

JPA? 자바 퍼시스턴스(Java Persistence, 이전 이름: 자바 퍼시스턴스 API/Java Persistence API) 또는 자바 지속성 API(Java Persistence API, JPA)는 자바 플랫폼 SE와 자바 플랫폼 EE를 사용하는 응용프로그램에서 관

kwaksh2319.tistory.com

Spring Data 저장소 추상화의 중앙 인터페이스는 Repository입니다. 관리할 도메인 클래스와 도메인 클래스의 식별자 유형을 유형 인수로 사용합니다. 이 인터페이스는 주로 작업할 유형을 캡처하고 이 인터페이스를 확장하는 인터페이스를 검색하는 데 도움이 되는 마커 인터페이스 역할을 합니다. CrudRepository 및 ListCrudRepository 인터페이스는 관리되는 엔터티 클래스에 대한 정교한 CRUD 기능을 제공합니다.

 

public interface CrudRepository<T, ID> extends Repository<T, ID> {

  <S extends T> S save(S entity);   //1

  Optional<T> findById(ID primaryKey); ///2

  Iterable<T> findAll(); //3

  long count(); //4

  void delete(T entity); //5

  boolean existsById(ID primaryKey); //6

  // … more functionality omitted.
}

 

  1. entity를 저장합니다.
  2. entity에서 id 식별자를 통해서 return 합니다.
  3. 모든 entity를 return 합니다.
  4. entities들의 숫자를 return합니다.
  5. entity를 삭제합니다.
  6. id 식별자를 entity에서  존재 여부를 확인합니다. 

이 메서드들은 CRUD 메서드들를 참조하여 일반적으로 인터페이스에 명시된 메서들입니다.

ListCrudRepository는  동등한 메서들을 제공합니다. 그러나 CrudRepository는 Iterable리턴하지만 

ListCrudRepository는 list를 return 합니다.

 

CrudRepository 외에도 엔터티에 대한 페이지 매김 액세스를 쉽게 하기 위해 추가 메서드를 추가하는 PagingAndSortingRepository 및 ListPagingAndSortingRepository가 있습니다.

public interface PagingAndSortingRepository<T, ID>  {

  Iterable<T> findAll(Sort sort);

  Page<T> findAll(Pageable pageable);
}

 

페이지 크기 20으로 User의 두 번째 페이지에 액세스하려면 다음과 같이 할 수 있습니다.

PagingAndSortingRepository<User, Long> repository = // … get access to a bean
Page<User> users = repository.findAll(PageRequest.of(1, 20));

 

ListPagingAndSortingRepository는 동등한 메서드를 제공하지만 PagingAndSortingRepository 메서드가 Iterable을 반환하는 List를 반환합니다

 

쿼리 방식 외에도 개수 쿼리와 삭제 쿼리 모두에 대한 쿼리 파생이 가능합니다. 다음 목록은 파생된 카운트 쿼리에 대한 인터페이스 정의를 보여줍니다.

interface UserRepository extends CrudRepository<User, Long> {

  long countByLastname(String lastname);
}

다음 목록은 파생된 삭제 쿼리에 대한 인터페이스 정의를 보여줍니다.

interface UserRepository extends CrudRepository<User, Long> {

  long deleteByLastname(String lastname);

  List<User> removeByLastname(String lastname);
}

https://docs.spring.io/spring-data/jpa/reference/repositories/core-concepts.html

 

Core concepts :: Spring Data JPA

The methods declared in this interface are commonly referred to as CRUD methods. ListCrudRepository offers equivalent methods, but they return List where the CrudRepository methods return an Iterable.

docs.spring.io

 

JPA?

자바 퍼시스턴스(Java Persistence, 이전 이름: 자바 퍼시스턴스 API/Java Persistence API) 또는 자바 지속성 API(Java Persistence API, JPA)는 자바 플랫폼 SE 자바 플랫폼 EE를 사용하는 응용프로그램에서 관계형 데이터베이스의 관리를 표현하는 자바 API이다. -위키글-

 

https://ko.wikipedia.org/wiki/%EC%9E%90%EB%B0%94_%ED%8D%BC%EC%8B%9C%EC%8A%A4%ED%84%B4%EC%8A%A4

 

자바 퍼시스턴스 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 자바 퍼시스턴스(Java Persistence, 이전 이름: 자바 퍼시스턴스 API/Java Persistence API) 또는 자바 지속성 API(Java Persistence API, JPA)는 자바 플랫폼 SE와 자바 플랫폼 EE를

ko.wikipedia.org

 

간단하게 jpa에 위키글을 요약하자면 데이터베이스를 관리하는 api라고 생각하면 됩니다.

그렇다면 jpa에 사용법과 구조에 대해서 정확하게 알아 보도록 하겠습니다.

 

간단한 entity와 해당 repository부터 보겠습니다.

@Entity
class Person {

  @Id @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  private String name;

  // getters and setters ommited for brevity
}

interface PersonRepository extends Repository<Person, Long> {

  Person save(Person person);

  Optional<Person> findById(long id);
}

 

메인에서 예제를 확인해보겠습니다.

@SpringBootApplication
public class DemoApplication {

  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }

  @Bean
  CommandLineRunner runner(PersonRepository repository) {
    return args -> {

      Person person = new Person();
      person.setName("John");

      repository.save(person);
      Person saved = repository.findById(person.getId()).orElseThrow(NoSuchElementException::new);
    };
  }
}

 

Repsoitory 인스턴스들은 자동적으로 실행됩니다. 

메소드의 @Bean의 파라미터들을 사용할때, annotation이 추가적으로 필요 없이 autowired 하게 됩니다.

기본적으로 repsoitory 는 repsoitory 확장합니다(?)

일반적으로 우리는 api surface  사용자의 application에 노출을 원하는 만큼 고려하여 제안하다(?)

(아마 제가 볼때 Repository 상속받아서 사용하는 그런부분인것 같습니다... 확실히 모르겠네요

(아래 내용은 api surface(api 표면) 즉 api 상호 작용할수 있는 코드부분을 뜻한다고 하네요.

즉 가용할수 있는 api surface부분을 고려하면서 repsoitory를 확장해서 사용하라는 뜻 같네요

틀리면 지적 부탁드립니다.)

 마지막으로 

더욱 복잡한 인터페이스들인 ListCrudRepository, JpaRepository들이 존재합니다.

https://docs.spring.io/spring-data/jpa/reference/jpa/getting-started.html

 

Getting Started :: Spring Data JPA

Let’s start with a simple entity and its corresponding repository: @Entity class Person { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; // getters and setters ommited for brevity } interface PersonRepository ex

docs.spring.io

 

공부하게 된 계기는 팀장님의 피드백으로 인해서 많은 생각을 하게 되었습니다.

그리고 코드를 분석하는 방법에 대해서도 결과부터가 아니라 순차적으로 분석해야 한다는 느낌을 많이 받았습니다.

 

기존에 개발하면서 결과적인 시각으로 많이 바라본게 아닌가 라는 생각을 많이 하게되었습니다. 아직 조금 그러한 습관이 남아 있어서 천천히 없애도록 노력해야겠다는 생각이 들었습니다. (한번에 없어지는게 이상한거겠지만 ㅎㅎ 일단은 조금씩 바꾸면 언젠간 바뀐다고 믿는 성격이어서 열심히 해볼생각입니다. 생각해보면 블로그 작성이나 공부하는 습관들도 처음부터 생겼던건 아니었으니까요. ㅎㅎ) 

 

과연 war 실행의 구동원리를 정확하게 이해하고 있는가? 에 대해서 다시 한번 돌아보게 되었습니다.

조금 더 섬세하게 체크 해야겟다는 생각이 많이 들었습니다.

 

톰캣 이용되는곳?

 

정확하게 웹이 실행될때 일반적으로 톰캣을 이용하여 사용하는경우가 많다.

물론  iis 서버 같은걸로 할수 있지만 일단 저희 회사에선 톰캣을 이용하기도 하고 많은 회사들이 톰캣을 이용하기 때문에 

톰캣동작에 대해서 먼저 정리해보도록 하겠습니다.

 

톰캣(tomcat) 설치 링크:

https://tomcat.apache.org/

 

Apache Tomcat® - Welcome!

The Apache Tomcat® software is an open source implementation of the Jakarta Servlet, Jakarta Server Pages, Jakarta Expression Language, Jakarta WebSocket, Jakarta Annotations and Jakarta Authentication specifications. These specifications are part of the

tomcat.apache.org

기본적인 형태는 이렇습니다.

/bin            -   시작, 종료 및 기타 스크리트 파일

/conf          -  구성 파일 및 관련 DTD, 여기서 중요한 파일은 sever.xml입니다. 컨테이너 기본 구성 파일입니다.

/logs          -  로그 파일은 기본적으로 여기있습니다.

/webapps  - 웹앱은 여기에 있습니다.

 

Catalina_Home 및 Catalina_Base?

  • catalina_home: 톰캣 설치 루트를 나타냅니다. ( 예: /home/tomcat/apache-tomcat-9.0x, C:\program Files\ apache-tomcat-9.0x )
  • catalina_base:특정 Tomact 인스턴스의 런타임 구성 루트를 나타냅니다. 한 시스템에 여러 Tomcat 인스턴스를 갖고 싶다면 이 Catlian_base 속성을 사용하면 됩니다.
  • 속성을 다른 위치로 설정하면 catilina_home 위치에 .jar 파일이나 바이너리 파일과 정적 소스가 포함됩니다. catalina_base위치에는 구성 파일, 로그 파일, 배포된 애플리케이션 및 기타 런타임 요구 사항이 포함됩니다.

Catalina_base를 사용하는 이유?

기본적으로 Catalina_home과 Catlina_base는 동일한 디렉토리를 가리킵니다. 하나의 시스템에서 여러 톰캣 인스턴스를 실행해야하는 경우 Catalina_base를 수동으로 설정하십시오.

  • 최신버전의 톰캣으로 업그레이드 관리가 더 쉬워졌습니다. 단일 Catalina_home위치를 가진 모든 인스턴스는 하나의 파일 및 바이너리 파일 세트를 공유하므로, .jar파일을 최신 버전으로 쉽게 업그레이드하고 동일한 Catalina_home 디렉터리를 사용하는 모든 톰캣 인스턴스에 변경사항을 전파할수 있습니다.
  • 동일한 정적 .jar 파일의 중복을 방지합니다.
  • sentenv운영 체제에 따라 쉘 또는 bat 스크립트 파일과 같은 특정 설정을 공유할수 있습니다.

코드에 대해서 한번 분석 해보겠습니다.

우선 startup.bat을 실행하면 

보시면 rem 은 주석이므로 쓸데 없는 앞부분은 지웟습니다.

@echo off

rem ---------------------------------------------------------------------------
rem Start script for the CATALINA Server
rem ---------------------------------------------------------------------------

setlocal

set "CURRENT_DIR=%cd%"

if not "%CATALINA_HOME%" == "" goto gotHome
set "CATALINA_HOME=%CURRENT_DIR%"
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome

cd ..
set "CATALINA_HOME=%cd%"

cd "%CURRENT_DIR%"
:gotHome
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
echo The CATALINA_HOME environment variable is not defined correctly
echo This environment variable is needed to run this program
goto end
:okHome

set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat"

rem Check that target executable exists

if exist "%EXECUTABLE%" goto okExec
echo Cannot find "%EXECUTABLE%"
echo This file is needed to run this program
goto end
:okExec

rem Get remaining unshifted command line arguments and save them in the

set CMD_LINE_ARGS=
:setArgs
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
shift
goto setArgs
:doneSetArgs

call "%EXECUTABLE%" start %CMD_LINE_ARGS%

:end

 

코드를 보시면 

startup.bat->catalina.bat을 호출하죠. 

catalina.bat을 한번 보겠습니다. 마찬가지로 앞부분 rem은 조금 삭제하겠습니다.

 

@echo off

setlocal

rem Suppress Terminate batch job on CTRL+C
if not ""%1"" == ""run"" goto mainEntry
if "%TEMP%" == "" goto mainEntry
if exist "%TEMP%\%~nx0.run" goto mainEntry
echo Y>"%TEMP%\%~nx0.run"
if not exist "%TEMP%\%~nx0.run" goto mainEntry
echo Y>"%TEMP%\%~nx0.Y"
call "%~f0" %* <"%TEMP%\%~nx0.Y"
rem Use provided errorlevel
set RETVAL=%ERRORLEVEL%
del /Q "%TEMP%\%~nx0.Y" >NUL 2>&1
exit /B %RETVAL%
:mainEntry
del /Q "%TEMP%\%~nx0.run" >NUL 2>&1

rem Guess CATALINA_HOME if not defined
set "CURRENT_DIR=%cd%"
if not "%CATALINA_HOME%" == "" goto gotHome
set "CATALINA_HOME=%CURRENT_DIR%"
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
cd ..
set "CATALINA_HOME=%cd%"
cd "%CURRENT_DIR%"
:gotHome

if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
echo The CATALINA_HOME environment variable is not defined correctly
echo This environment variable is needed to run this program
goto end
:okHome

rem Copy CATALINA_BASE from CATALINA_HOME if not defined
if not "%CATALINA_BASE%" == "" goto gotBase
set "CATALINA_BASE=%CATALINA_HOME%"
:gotBase

rem Ensure that neither CATALINA_HOME nor CATALINA_BASE contains a semi-colon
rem as this is used as the separator in the classpath and Java provides no
rem mechanism for escaping if the same character appears in the path. Check this
rem by replacing all occurrences of ';' with '' and checking that neither
rem CATALINA_HOME nor CATALINA_BASE have changed
if "%CATALINA_HOME%" == "%CATALINA_HOME:;=%" goto homeNoSemicolon
echo Using CATALINA_HOME:   "%CATALINA_HOME%"
echo Unable to start as CATALINA_HOME contains a semicolon (;) character
goto end
:homeNoSemicolon

if "%CATALINA_BASE%" == "%CATALINA_BASE:;=%" goto baseNoSemicolon
echo Using CATALINA_BASE:   "%CATALINA_BASE%"
echo Unable to start as CATALINA_BASE contains a semicolon (;) character
goto end
:baseNoSemicolon

rem Ensure that any user defined CLASSPATH variables are not used on startup,
rem but allow them to be specified in setenv.bat, in rare case when it is needed.
set CLASSPATH=

rem Get standard environment variables
if not exist "%CATALINA_BASE%\bin\setenv.bat" goto checkSetenvHome
call "%CATALINA_BASE%\bin\setenv.bat"
goto setenvDone
:checkSetenvHome
if exist "%CATALINA_HOME%\bin\setenv.bat" call "%CATALINA_HOME%\bin\setenv.bat"
:setenvDone

rem Get standard Java environment variables
if exist "%CATALINA_HOME%\bin\setclasspath.bat" goto okSetclasspath
echo Cannot find "%CATALINA_HOME%\bin\setclasspath.bat"
echo This file is needed to run this program
goto end
:okSetclasspath
call "%CATALINA_HOME%\bin\setclasspath.bat" %1
if errorlevel 1 goto end

rem Add on extra jar file to CLASSPATH
rem Note that there are no quotes as we do not want to introduce random
rem quotes into the CLASSPATH
if "%CLASSPATH%" == "" goto emptyClasspath
set "CLASSPATH=%CLASSPATH%;"
:emptyClasspath
set "CLASSPATH=%CLASSPATH%%CATALINA_HOME%\bin\bootstrap.jar"

if not "%CATALINA_TMPDIR%" == "" goto gotTmpdir
set "CATALINA_TMPDIR=%CATALINA_BASE%\temp"
:gotTmpdir

rem Add tomcat-juli.jar to classpath
rem tomcat-juli.jar can be over-ridden per instance
if not exist "%CATALINA_BASE%\bin\tomcat-juli.jar" goto juliClasspathHome
set "CLASSPATH=%CLASSPATH%;%CATALINA_BASE%\bin\tomcat-juli.jar"
goto juliClasspathDone
:juliClasspathHome
set "CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\bin\tomcat-juli.jar"
:juliClasspathDone

if not "%JSSE_OPTS%" == "" goto gotJsseOpts
set JSSE_OPTS="-Djdk.tls.ephemeralDHKeySize=2048"
:gotJsseOpts
set "JAVA_OPTS=%JAVA_OPTS% %JSSE_OPTS%"

rem Register custom URL handlers
rem Do this here so custom URL handles (specifically 'war:...') can be used in the security policy
set "JAVA_OPTS=%JAVA_OPTS% -Djava.protocol.handler.pkgs=org.apache.catalina.webresources"

if not "%LOGGING_CONFIG%" == "" goto noJuliConfig
set LOGGING_CONFIG=-Dnop
if not exist "%CATALINA_BASE%\conf\logging.properties" goto noJuliConfig
set LOGGING_CONFIG=-Djava.util.logging.config.file="%CATALINA_BASE%\conf\logging.properties"
:noJuliConfig

if not "%LOGGING_MANAGER%" == "" goto noJuliManager
set LOGGING_MANAGER=-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
:noJuliManager

rem Configure JAVA 9 specific start-up parameters
set "JDK_JAVA_OPTIONS=%JDK_JAVA_OPTIONS% --add-opens=java.base/java.lang=ALL-UNNAMED"
set "JDK_JAVA_OPTIONS=%JDK_JAVA_OPTIONS% --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED"

rem ----- Execute The Requested Command ---------------------------------------

echo Using CATALINA_BASE:   "%CATALINA_BASE%"
echo Using CATALINA_HOME:   "%CATALINA_HOME%"
echo Using CATALINA_TMPDIR: "%CATALINA_TMPDIR%"
if ""%1"" == ""debug"" goto use_jdk
echo Using JRE_HOME:        "%JRE_HOME%"
goto java_dir_displayed
:use_jdk
echo Using JAVA_HOME:       "%JAVA_HOME%"
:java_dir_displayed
echo Using CLASSPATH:       "%CLASSPATH%"

set _EXECJAVA=%_RUNJAVA%
set MAINCLASS=org.apache.catalina.startup.Bootstrap
set ACTION=start
set SECURITY_POLICY_FILE=
set DEBUG_OPTS=
set JPDA=

if not ""%1"" == ""jpda"" goto noJpda
set JPDA=jpda
if not "%JPDA_TRANSPORT%" == "" goto gotJpdaTransport
set JPDA_TRANSPORT=dt_socket
:gotJpdaTransport
if not "%JPDA_ADDRESS%" == "" goto gotJpdaAddress
set JPDA_ADDRESS=localhost:8000
:gotJpdaAddress
if not "%JPDA_SUSPEND%" == "" goto gotJpdaSuspend
set JPDA_SUSPEND=n
:gotJpdaSuspend
if not "%JPDA_OPTS%" == "" goto gotJpdaOpts
set JPDA_OPTS=-agentlib:jdwp=transport=%JPDA_TRANSPORT%,address=%JPDA_ADDRESS%,server=y,suspend=%JPDA_SUSPEND%
:gotJpdaOpts
shift
:noJpda

if ""%1"" == ""debug"" goto doDebug
if ""%1"" == ""run"" goto doRun
if ""%1"" == ""start"" goto doStart
if ""%1"" == ""stop"" goto doStop
if ""%1"" == ""configtest"" goto doConfigTest
if ""%1"" == ""version"" goto doVersion

echo Usage:  catalina ( commands ... )
echo commands:
echo   debug             Start Catalina in a debugger
echo   debug -security   Debug Catalina with a security manager
echo   jpda start        Start Catalina under JPDA debugger
echo   run               Start Catalina in the current window
echo   run -security     Start in the current window with security manager
echo   start             Start Catalina in a separate window
echo   start -security   Start in a separate window with security manager
echo   stop              Stop Catalina
echo   configtest        Run a basic syntax check on server.xml
echo   version           What version of tomcat are you running?
goto end

:doDebug
shift
set _EXECJAVA=%_RUNJDB%
set DEBUG_OPTS=-sourcepath "%CATALINA_HOME%\..\..\java"
if not ""%1"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy"
goto execCmd

:doRun
shift
if not ""%1"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy"
goto execCmd

:doStart
shift
if "%TITLE%" == "" set TITLE=Tomcat
set _EXECJAVA=start "%TITLE%" %_RUNJAVA%
if not ""%1"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy"
goto execCmd

:doStop
shift
set ACTION=stop
set CATALINA_OPTS=
goto execCmd

:doConfigTest
shift
set ACTION=configtest
set CATALINA_OPTS=
goto execCmd

:doVersion
%_EXECJAVA% -classpath "%CATALINA_HOME%\lib\catalina.jar" org.apache.catalina.util.ServerInfo
goto end


:execCmd
rem Get remaining unshifted command line arguments and save them in the
set CMD_LINE_ARGS=
:setArgs
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
shift
goto setArgs
:doneSetArgs

rem Execute Java with the applicable properties
if not "%JPDA%" == "" goto doJpda
if not "%SECURITY_POLICY_FILE%" == "" goto doSecurity
%_EXECJAVA% %LOGGING_CONFIG% %LOGGING_MANAGER% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end
:doSecurity
%_EXECJAVA% %LOGGING_CONFIG% %LOGGING_MANAGER% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end
:doJpda
if not "%SECURITY_POLICY_FILE%" == "" goto doSecurityJpda
%_EXECJAVA% %LOGGING_CONFIG% %LOGGING_MANAGER% %JAVA_OPTS% %JPDA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end
:doSecurityJpda
%_EXECJAVA% %LOGGING_CONFIG% %LOGGING_MANAGER% %JAVA_OPTS% %JPDA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end

:end

 

엄청많죠 여기서 조금 핵심적으로 봐야하는게 

setenv.bat -> setclasspath.bat -> bootstrap.jar -> tomcat-juli.jar 입니다.

 

setenv.bat 는 JAVA_OPTS, CATALINA_OPTS등의 환경변수 설정을 하는데 이용됩니다.

이 동작이 jvm의 동작에도 영향을 줍니다.

 

setclassthpath.bat은 java class 와 libarary에 대한 class_path  설정을 합니다. 

jar 파일의 경로가 포함될수 있습니다.

 

bootstrap.jarTomcat 서버의 초기화와 시작을 담당합니다.

https://tomcat.apache.org/tomcat-8.5-doc/api/org/apache/catalina/startup/Bootstrap.html

 

Bootstrap (Apache Tomcat 8.5.98 API Documentation)

public final class Bootstrap extends Object Bootstrap loader for Catalina. This application constructs a class loader for use in loading the Catalina internal classes (by accumulating all of the JAR files found in the "server" directory under "catalina.hom

tomcat.apache.org

 

tomcat-juli.jar는 로깅시스템 처리하는데 사용됩니다.

bootstarp.jar와 함께 클래스 패스에 포함되어 로그 관리 기능을 제공합니다.

 

그렇다면 bootstrap.jar 이 server.xml을 읽어와야하는데요. 이부분을 한번 확인해보겠습니다.

 

https://tomcat.apache.org/download-90.cgi

 

Apache Tomcat® - Apache Tomcat 9 Software Downloads

Welcome to the Apache Tomcat® 9.x software download page. This page provides download links for obtaining the latest version of Tomcat 9.0.x software, as well as links to the archives of older releases. Unsure which version you need? Specification version

tomcat.apache.org

zip파일을 읽어와서 압축푼후 코드를 한번 보겠습니다.

 

bootstarp.jar 파일이 아닌 코드로 보면 

/java/org/apache/catalina/startip/Catalina.java 파일을 보면요.

 

conf/server.xml을 읽어옵니다. 

주석은 제거하고 

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

<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>

  <Service name="Catalina">

    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

    <Engine name="Catalina" defaultHost="localhost">

      <Realm className="org.apache.catalina.realm.LockOutRealm">
   
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>

      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

      </Host>
    </Engine>
  </Service>
</Server>

 

 xml 코드를 보시면 사용되는 port 번호 appbase webapps 파일 위치나 host 읽어올수 잇게 하는거죠.

 

정리하면 

 

startup.bat->catlina.bat->  (setenv.bat -> setclasspath.bat) 환경설정 -> (bootstrap.jar ( read file server.xml )  )앱서버 실행 -> tomcat-juli.jar 로깅 

 

이런식으로 이해하면 좋을것 같습니다. 잘못된부분 지적 부탁드리겠습니다.

 

그리고 조금 톰켓 부분을 수정하는 부분이 있으면 분석하면서 더 작성도 해보도록 하겠습니다.

 

참고:

 

https://tomcat.apache.org/tomcat-9.0-doc/introduction.html

 

Apache Tomcat 9 (9.0.85) - Introduction

Before you start using CATALINA_BASE, first consider and create the directory tree used by CATALINA_BASE. Note that if you do not create all the recommended directories, Tomcat creates the directories automatically. If it fails to create the necessary dire

tomcat.apache.org

 

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

Spring Data JPA - 핵심 개념  (0) 2024.02.03
Spring Data JPA에 대해서  (0) 2024.02.03
Gradle에서 compileOnly와 implementation 차이  (0) 2024.01.09
multiple gradle 빌드 시키기!  (0) 2024.01.08
gradle과 maven의 차이  (1) 2024.01.08

제목 그대로 gradle의 compileOnly, implementation의 차이에 대해서 과연 잘 알면서 썻는가? 이다.
 
개인적으로는 필요로 하면 찾아서 사용하다보니, 그렇게 까지는 관심있게 보지는 않았습니다.(반성..ㅜㅜ)
 
프로젝트를 빌드를 하는데 라이브러리가 중복이 되는 현상이 발생했었고, 이를 해결 하기위해서 이거 저것 찾아보다가  compileOnly, implementation의 차이에 대해서 정확하게 알면서 사용하고 있는가에 대해서도 반성하게 되었습니다.
 
결론 부터 말씀드리면 implementation 는 '컴파일 타임', '런타임'에만 모두 포함합니다.
반면 compileOnly는 '컴파일 타임'에만 필요하고, 런타임에는 필요하지 않습니다.
 
이해가 어려우니 예시를 보겠습니다.
ex)

 compileOnly 'org.projectlombok:lombok'
 implementation 'io.jsonwebtoken:jjwt:0.9.1'

 

jar 파일에서 라이브러리를 확인해보면 jwt-0.9.1 jar파일은 있습니다.

 
그렇다면 lombok은? jar파일에 존재하지 않습니다.
그 이유는 이미 lombok은 컴파일 타임에는 필요하지만 런타임에는 이미 그 기능인( 롬복 ) 기능을 수행한 상태임(이미 롬복이 실행이 끝낫다? ㅎㅎ )으로 필요하지 않아서 jar로 변환하지 않아도 됩니다.

기존에는 개인 프로젝트할때 귀찮아서 모듈들을 하나에 묶어서 개발을 했었는데요 . ㅎㅎ 
 
회사에서는 모듈이 기능 별로 나눠져서 묶여있는 형태로 되어 있었습니다.

그래서 개인적으로 프로젝트를 
admin api, custom api, batch api를 나눠서 함께 빌드 하는 gradle script를 간단히 작성해보겠습니다. 
회사에서  war로 빌드하여서 예시도 war로 빌드하도록 하겠습니다.

 
먼저 
mutiplePro
setting.gradle

rootProject.name = 'multiplePro'
include 'vproject_admin_api'
include 'vproject_custom_api'
include 'vproject_batch_api'

 
build.gradle

plugins {
    id 'java'
    id 'war'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    implementation group: 'log4j', name: 'log4j', version: '1.2.16'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}

task buildAdminProject {
    dependsOn ':vproject_admin_api:build'
    println "AdminProject builing success"
}

task buildCutomProject {
    dependsOn ':vproject_batch_api:build'
    println "CutomProject builing success"
}
task buildBatchProject {
    dependsOn ':vproject_custom_api:build'
    println "BatchProject builing success"
}
test {
    useJUnitPlatform()
}

결과화면 :

 

+ Recent posts