spring
-
security
- Request > Filter > DispatcherServlet > Interceptor > Controller

- Request > Filter > DispatcherServlet > Interceptor > Controller
-
generic type erasure : 컴파일 타입에만 타입 제약 조건을 적용하고, 런타임 시 타입 정보를 삭제하는 프로세스
-
exception handling
-
transaction과 rollback과 retrayble
- @Transactional : 예외 발생 시 rollback 진행
- @ExceptionHandler 추가 : rollback 이후 ExceptionHandler 진행
- @Retry (AOP) : transaction-rollback 진행 후 retry 진행
- @Transactional : 예외 발생 시 rollback 진행
-
gradle
- gradle/gradle-wrapper.properties 파일 수정
- build.gradle의 repositories {maven {URL}}
- gettins.gradle 파일 수정
-
ssl 등록
- src/main/resource/{ssl파일} 등록
- application.yml 파일 등록
- server.ssl.enalbled: true
- server.ssl.key-store: classpath:
- server.ssl.key-store-password:
- server.ssl.key-store-type: PKCS12
- server.ssl.key-alias:
- server.port: 임의
spring 기술
- Ioc : Inversion of Control
- 스프링 컨테이너 활용 역전의 제어
- DI : Dependency Injection
- IoC를 위한 의존성 주입
- AOP : Aspect Oriented Programming
- 비즈니스 로직 또는 사용관점에 따른 코드 분리 가능
- PSA : Portable Service Abstraction
- 타 라이브러리/툴을 인터페이스로 제어하여 비즈니스로직 일관되게 사용가능
spring 구조
application.yml
- yml 파일 내에서 변수 가져와서 쓰기 또는 kube에서 설정한 환경변수 사용하기
data:
url-cleancode-batch: http://cleancode-batch:15670
containers:
- args:
env:
- name: CLEANCODE_URL
valueFrom:
configMapKeyRef:
key: url-cleancode-batch
name: environment
optional: false
cloud:
protocol: https
domain: ${cloud.protocol}://api.cleancode.kr
api:
v2:
cost_job_call: ${cloud.domain}/cost-analysis/data/sync
crawling
- selenium
- browser와 driver(126버전 상위는 chromeBrowser)를 활용한 clinet에서 크롤링 작업
- clinet 브라우저에서 tag찾기/ javascript작업(예: return localStorage.getItem(’’)) 활용
- session 상태 독립적
- Jsoup
- dom 구조를 분석 (csr과 같은 경우 분석이 어려움)
라이브러리 활용
- @Bean : 개발자가 개발 또는 @Override 와 같이 재정의 사용이 힘든 라이브러리를 bean에 등록하고 싶은 경우 사용
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
- @Component : 개발자가 개발 또는 직접 컨트롤 할 수 있는 클래스를 bean에 등록하고 싶은 경우
- @Configuration, @Controller, @Service, @Repository 어노테이션은 개발자가 개발하는 bean이므로 @Componenet 어노테이션을 포함함
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
Public @interface Component {
}
@Component
@RequiredArgsConstructor
publc class CustomAuthManager implements AuthenticationManager {
}
- @Service/ @Controller
- 레이어(역활)에 따라 @Component 구분
- @Repository
- db와 같은 영속성 프레임워크를 사용할 경우 영속성 예외를 자동으로 전환 (springframework.dao.DataAccessException 서브클래스로 자동 전환)
filter
- OnecePerRequestFilter : http request 한 번의 요청에 대해 한 번만 실행 (forwarding 으로 filter chain이 다시 동작할 때 반복 실행하지 않아도 되는 filter에 사용)
@Component @Configuration @RequriedArgsConstructor public class CleancodeAuthenticationFilter extends OncePerRequestFilter { public static final String AUTHORIZATION_HEADER = “Authorization”; public static final String BEARER_PREFIX = “Bearer “; private final AuthService authService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String jwt = resolveToken(request); if(request.getRequestURI().contains(”/public”)) { FilterCahin.doFilter(reqeust, response); } if(StringUtils.hashText(jwt)) { try { Authentication jwtAuthticationToken = new JwtAuthenticationToken(jwt); UserInfo user = authService.userList( request.getHeader(”Authorization”).substring(7).trim(); ) }catch (AuthenticationException authenticationException) { SecutiryContenxtHolder.clearContext(); }catch (CertificateException | ParseException e) { throw new RuntimeException(e); } } FilterChain.dofilter(request, response); } private String resolveToken(HttpServletRequest request) { String bearerToken = request.getHeader(AUTHORIZATION_HEADER); If(StringUtils.hashText(bearerToken) && bearerToken.startWith(BEARER_PREFIX)) { return bearerToken.substring(7); } return null; } }
security
- doFilterInternal : security로 모든 접속에 대한 aop 기능 진행
protected void doFilterInternal() {
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain
} throws ServletException, IOException {
String jwt = resolveToken(request);
if(request.getRequestURI().contains(”/public”)) {
filterChain.doFilter(request, response);
return;
}
..
if(StringUtils.hasText(jwt)) {
try {
Authentication jwtAuthenticationToken = new JwtAuthenticationToken(jwt);
} catch (AuthenticationException authException) {
SecurityContextHolder.clearContext();
} catch (CertificateException | ParseException e) {
throw new RuntimeException e;
}
}
filterChain.doFilter(request, response);
}
- SecurityFilterChan : delegationgFilterProxy에서 전달받아 security 에서 사용하는 필터체인
public securityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrfdisable; // 보안 관련 필터 등록설정
http.authorizeHttpRequests( // 권한 관련 필터 등록과 설정
auth -> auth
.requestMatchers(”/api/v2/**”).permitAll()
.requestMatchers(”/open-api/**”).permitAll()
//.addFilterBefore(jwtTokenFilter, AuthorizationFilter.class) // 커스텀 필터 등록
.anyRequest().authenticated()
);
http
.oauth2Login(oauth2 -> oauth2
.loginPage(”api/v2/tokenLogin”)
);
http
.exceptionHandling(exceptionHandlingConfigurer -> exceptionHandlingConfigurer
.accessDeniedHandler(jwtAccessDeniedHandler)
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
);
return http.build();
}
transactional
- @Transactional
- mongodb의 경우 replicaSet 환경구성
- mongoTransactionManager confg 구성
- @Configuration 설정 클래스 bean 등록@Configuration @EnableTransactionManagement public class MongoConfig extends AbstractMongClientConfiguration { @Bean Public MongoTransactionManager transactionManager(MongoDatabaseFactory mongoDatabaseFactory) { return new MongoTransactionManager(mongoDatabaseFactory); } }
- @EnableTransactionManagement : @Transactional을 찾아서 트랜잭션 범위 활성화
- MongoDatabaseFactory : 데이터베이스 논리적 연결
singleton
- synchronized 를 활용하여 다른 스레드들이 접근을 막고, 없을 경우 인스턴스 생성
- batchTimeUtil 두 번 확인하여 다른 스레드가 생성할 가능성 확인
public static BatchTimeUtil getInstance(BatchInfoMapper batchInfoMapper) {
if(batchTimeUtil == null) {
synchronized (BatchTimeUtil.class) {
if(batchTimeUtil == null) {
batchTimeUtil = new BatchTimeUtil(batchInfoMapper);
}
}
}
return batchTimeUtil;
}
api 호출
- restAPI : 동기식/ 비반응형/ 멀티쓰레드
public ResponseEntity<Object> getMongoManagementPost(String url, Object postParam) {
//serPassSSL();
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
Headers.set(”Content-Type”, “application/json”);
return restTemplate.exchange(url, HttpMethod.Post, new HttpEntity<>(postPrams, headers), Object.class);
}
- webClient : 비동기/반응형/ 싱글스레드
public Flux<T> getMongoManagementService(String url, object postPrams) {
return WebClient.create()
.get()
.uri(uri)
.retrieve()
.bodyToFlux(T.class);
}
- ssl pass 메서드
private void serPassSSL() {
try {
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {return null;}
public void checkClientTrusted(X509Certificate[] certs, String authType){}
public void checkServerTrusted(X509Certificate[] certs, String authType){}
}
};
SSLContext sc = SSLContext.getInstance(”SSL”);
sc.init(null, trustAllCerts, new java.security.SecureRamom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new RUntimeException(e.getMessage());
}
}
application 환경변수
- profile을 활용한 환경변수 관리
@Profile(”dev”)
@Compoenet
Public final class ApiHidden {
Public static final boolean hidden = true;
}
@Hidden
@PostMapping(”/board”)
@ApiOperation(value=“게시판“, notes=“게시판”, hidden=ApiHidden.hidden)
<Controller method example>
스레드-동시성-경쟁상태
- atomic type
- compare and swap 방식으로 해결 : 변수의 값을 변경하기 전에 기존에 가지고 있던 값이 예상 값과 같을 경우에 새로운 값으로 할당 (값을 변경하기 전에 한 번 더 확인)
boolean expected = true; AtomicBollean atomicBollean = new Atomicbollean(flase);
AtomicBoolean.compareAndSet(expected, true)
```