JAVA/spring

[1028 FORM 백기선 스프링프레임워크 핵심기술] SpEL, AOP,Null-safety

스프링목차

SpEL 스브링EL
객체 그래프를 조회, 조작하는 기능
Unified EL과 비슷하지만, 메소드 호출 지원, 문자열템플릿 기능도 제공. 
OGNL MVEL, JBOss EL 등 자바에서 사용할 수 있는 여러 EL 이 있지만 , SpEL은 모든 스프링 프로젝트 전반에 걸처 사용할 EL로 만듬.  스프링 3.0 부터. 
ExpressionParser parser = new SpelExpressionParser() 
StandardEvaluationContext context = new StandardEvaluationContext(bean) >> 함수. 가능. 
Expression expression = parser.parseExpression(“SpEL 표현식”)
String value = expression.getvalue(context, String.class)

#{“표현식"}  "#{1+1}" 
${“프로퍼티"}
docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions-language-ref

@Value 애노테이션
@ConditionalOnExpression 애노테이션
스프링 시큐리티
 - 메소드 시큐리티, @PreAuthorize, @PostAuthorize, @PreFilter, @PostFilter
  - XML 인터셉터 URL 설정
스프링 데이터  : @Query 애노테이션
Thymeleaf  : blog.outsider.ne.kr/997
docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions-language-ref
AOP Aspect-oriendted Programming  :  OOP 보완, 흩어진 Aspect를 모듈화 
스프링은 AspectJ 연동, 혹은 따로구현. 
OOP 에 나타난... 흩어진 관심(비슷한코드)사 : Crosscutting Concerns : 유지보수 어려움. 
ClassA {    1,     2,     3 }
ClassB {    1,     3,     3 }
ClassC {    1,     2}
>> AOP 적용
ClassA   , ClassB,  ClassC                                   
AspectX : A, B, C          1소스 부분
AspectY: A, C              2소스 부분
AspectZ: A, B              3소스부분
   PointCut           +    advice            = Aspect
  어디에 적용              해야할 일            하나의 모듈
Target 적용대상  ClassA   , ClassB,  ClassC
Join point 합류 지점 ex) 생성자 호출전, 호출때, 필드 호출전, 
그중에 더 자세한내용은 PointCut
AOP 적용방법 - 컴파일(java > .class)- 
- 로드타임 위빙(컴파일 후)-                                                        >> AspectJ  경우에 따라
- 런타임(빈을 만들때 A타입 프록시 빈을 만듬... 프록시 실행후 A실행)   >> 스프링 AOP 주로
빈만들때 약간의 성능 부하, 다양한 기능적용(AspectJ)
AOP 구현체  en.wikipedia.org/wiki/Aspect-oriented_programming
Java AOP 구현체 AspectJ  : 기능 다양
스프링 AOP  : 국한적. 
프록시 패턴 Client    임의 인터페이스
                      ↑
            프록시   →   임의 클래스
프록시 객체가 실제 사용할 클래스를 감싸서 프로그램실행 : 접근제어, 부가기능 추가. 
문제점
 매번 프록시 클래스를 작성해야 하는가?
 여러 클래스 여러 메소드에 적용하려면?
 객체들 관계도 복잡하고...
스프링AOP 프록시 기반 AOP 구현체
스프링 빈에만 AOP를 적용할 수 있다.
모든 AOP 기능을 제공하는 것이 목적이 아니라, 스프링 IoC와 연동하여 엔터프라이즈
애플리케이션에서 가장 흔한 문제에 대한 해결책을 제공하는 것이 목적.

스프링 IoC 컨테이너가 제공하는 기반 시설과 Dynamic 프록시를 사용하여 여러
복잡한 문제 해결.
동적 프록시: 동적으로 프록시 객체 생성하는 방법
- 자바가 제공하는 방법은 인터페이스 기반 프록시 생성.
- CGlib은 클래스 기반 프록시도 지원.
스프링 IoC: 기존 빈을 대체하는 동적 프록시 빈을 만들어 등록 시켜준다.
- 클라이언트 코드 변경 없음.
- AbstractAutoProxyCreator implements BeanPostProcessor
@Aspect 의존성 추가. spring-boot-starter-aop
@Component
@Aspect
public class PerfAspect{
     //@Around("execution( * com.example.demo.*.EventService.*(..))") //포인트컷 표현식.
     @Around("@annotation(PerfLogging)")
     public Object logPerf(ProceedingJoinPoint pip)throws Throwable{
         Object reVal = pip.proceed();
         return reVal;
     }
}
@Pointcut @Pointcut(표현식)
- execution
- @annotation
- bean
포인트컷 조합
-&&, ||, !
어드바이스 정의 @Before
@AfterReturning
@AfterThrowing
@Around
Null-safety 스프링 프레임워크 5에 추가된 Null 관련 애노테이션
@NonNull                                     >>매개변수 널허용안됨.
@Nullable
@NonNullApi (패키지 레벨 설정)
@NonNullFields (패키지 레벨 설정)
목적 : (툴의 지원을 받아) 컴파일 시점에 최대한 NullPointerException을 방지하는 것
 컴파일러 옵션.  configuration  스프링어노테이션 추가해야 쓸수 있음. 스프링데이터쪽에서 쓴다고함
패키지 레벨... NonNull.. 허용하는대만  Nullable 사용. 

 

@Retention(RetentionPolicy.CLASS)// 언제까지 유지할것인가.

docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-pointcuts

 

 

프록시 패턴구현_ 동적, 어노테이션

더보기
package com.example.demo.event;

import java.lang.annotation.*;
/**
 * 이 어노테이션은 성릉을 로깅해줍니다.. 
 */
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)// 언제까지 유지할것인가. 명시.. 기본값
public @interface PerfLogging {
}
package com.example.demo.event;

import org.springframework.stereotype.Service;

@Service
public class SimpleEventService implements EventService {
    @Override
    @PerfLogging
    public void createEvent() {
        System.out.println("Created an event");
    }

    @Override
    @PerfLogging
    public void publishEvent() {
        System.out.println("published an event");
    }

    @Override
    public void deleteEvent(){
        System.out.println("Delete an event");
    }
}
package com.example.demo.event;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class PerfAspect{

    //@Around("execution( * com.example.demo.*.EventService.*(..))")  //포인트컷 표현식.
    @Around("@annotation(PerfLogging)")
    public Object logPerf(ProceedingJoinPoint pip)throws Throwable{
        long begin = System.currentTimeMillis();
        Object reVal = pip.proceed();
        System.out.println(System.currentTimeMillis()-begin);
        return reVal;
    }
}

 

 

프록시 패턴구현 _ 기본이해 

더보기
package com.example.demo.event;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

@Primary
@Service
public class ProxySimpleEventService implements EventService{

    @Autowired
    SimpleEventService simpleEventService;

    @Override
    public void createEvent(){
        long begin = System.currentTimeMillis();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        simpleEventService.createEvent();
        System.out.println(System.currentTimeMillis()-begin);
    }

    @Override
    public void publishEvent(){
        long begin = System.currentTimeMillis();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        simpleEventService.publishEvent();
        System.out.println(System.currentTimeMillis()-begin);
    }

    @Override
    public void deleteEvent(){
        simpleEventService.deleteEvent();
    }
}
package com.example.demo.event;

public interface EventService{
    void createEvent();
    void publishEvent();
    void deleteEvent();
}
package com.example.demo.event;

import org.springframework.stereotype.Service;

@Service
public class SimpleEventService implements EventService{
    @Override
    public void createEvent(){
        System.out.println("Created an event");
    }

    @Override
    public void publishEvent(){
        System.out.println("published an event");
    }

    @Override
    public void deleteEvent(){
        System.out.println("Delete an event");
    }
}

 

 

package com.example.demo.event;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
public class AppRunner implements ApplicationRunner {

    EventService eventService;

    @Override
    public void run(ApplicationArguments args) throws Exception {

        eventService.createEvent();
        eventService.publishEvent();
        eventService.deleteEvent();

    }

    @Autowired
    public void setEventService(EventService eventService) {
        this.eventService = eventService;
    }
}

.

추가 스프링부트 웹 안쓸때

SpringApplication app = new SpringApplication(DemoApplication.class);
        app.setWebApplicationType(WebApplicationType.NONE);
        app.run(args);