Springboot 의 비동기 요청 과 비동기 호출 (op 동적 생 성 에이전트 대상)

14155 단어
비동기 요청
특징: 시스템 서비스의 압력 을 줄 이 고 동시 다발 요 구 량 이 많은 경우 저 희 는 nginx 를 통 해 클 러 스 터 서비스의 각 노드 에 요청 을 부하 하여 요청 압력 을 분담 할 것 입 니 다. 물론 메시지 큐 를 통 해 요청 한 버퍼 도 할 수 있 습 니 다.
비동기 호출
일반적으로 개발 과정 에서 실제 업무 와 무관 하고 긴밀 성 이 없 는 방법 을 만 날 수 있다.예 를 들 어 로그 정 보 를 기록 하 는 등 업무.이때 정상 적 인 것 은 새로운 스 레 드 를 열 어 업무 처 리 를 하고 메 인 스 레 드 가 다른 업 무 를 수행 하도록 하 는 것 이다.
사용 방식
시작 클래스 에 @ EnableAsync 를 추가 하여 비동기 호출 @ Async 주 해 를 적용 해 야 합 니 다. 비동기 실행 이 필요 한 방법 에 이 주 해 를 추가 하면 @ Async ("threadPool"), threadPool 은 사용자 정의 스 레 드 풀 입 니 다.
주의 사항
기본 적 인 상황 에서 TaskExecutor 를 설정 하지 않 았 을 때 기본 값 은 Simple AsyncTaskExecutor 라 는 스 레 드 풀 을 사용 합 니 다. 그러나 이 스 레 드 는 진정한 의미 의 스 레 드 풀 이 아 닙 니 다. 스 레 드 가 다시 사용 되 지 않 기 때문에 호출 할 때마다 새로운 스 레 드 를 만 듭 니 다 (jvm 은 스 레 드 를 만 들 고 라인 을 없 앨 때마다 자원 을 특별히 소모 합 니 다).콘 솔 로그 출력 을 통 해 매번 출력 스 레 드 이름 이 증가 하고 있 음 을 알 수 있 습 니 다.그래서 우 리 는 스 레 드 탱크 를 정의 하 는 것 이 좋 습 니 다.호출 된 비동기 방법 은 같은 종류의 방법 (같은 종류의 내부 클래스 포함) 을 만 들 수 없습니다. 쉽게 말 하면 Spring 은 스 캔 을 시작 할 때 프 록 시 클래스 를 만 들 고 같은 종류의 프 록 시 클래스 를 호출 할 때 그 자체 의 프 록 시 클래스 를 호출 하기 때문에 일반적인 호출 과 같 습 니 다.다른 주석, 예 를 들 어 @ Cache 등 도 마찬가지 입 니 다. 말하자면 Spring 의 대리 체제 가 만 든 것 입 니 다.따라서 개발 에 있어 서 비동기 서 비 스 를 따로 하나의 종 류 를 추출 하여 관리 하 는 것 이 좋 습 니 다 (이 종류 에 @ component 를 추가 하 는 것 을 기억 하 세 요).다음은 중점적으로 말씀 드 리 겠 습 니 다.
어떤 경우 @ Async 비동기 방법 이 효력 을 잃 을 수 있 습 니까?
a. 같은 종류의 베 팅 을 호출 할 때 @ Async 비동기 방법 이 있 습 니 다. spring 에서 @ Async 와 @ Transactional, cache 등 주 해 는 본질 적 으로 동적 대 리 를 사용 합 니 다. 사실 Spring 용 기 는 초기 화 할 때 Spring 용기 가 AOP 주 해 를 포함 한 클래스 대상 을 대리 대상 으로 '교체' 합 니 다 (간단하게 이해). 그러면 주해 가 효력 을 잃 는 원인 이 뚜렷 합 니 다.대리 대상 이 아 닌 대상 자 체 를 호출 하 는 것 이기 때문이다. Spring 용 기 를 거치 지 않 았 기 때문에 해결 방법 도 이 를 따라 해결 된다.b. 정적 (static) 방법 c. 호출 (private) 사유 화 방법
지난 문제 해결 중 a 방식
비동기 적 으로 실행 할 방법 을 단독으로 하나의 클래스 로 추출 합 니 다. 원 리 는 비동기 적 으로 실행 하 는 방법 을 단독으로 하나의 클래스 로 추출 할 때 이 종 류 는 반드시 Spring 에 의 해 관리 되 고 다른 Spring 구성 요소 가 호출 되 어야 할 때 반드시 주입 되 는 것 입 니 다. 이때 실제로 주입 되 는 것 은 대리 류 입 니 다.사실 우리 의 주입 대상 은 모두 Spring 용기 에서 현재 Spring 구성 요소 에 구성원 변 수 를 할당 하 는 것 입 니 다. 어떤 종 류 는 AOP 주 해 를 사 용 했 기 때문에 실제 Spring 용기 에 존재 하 는 것 은 대리 대상 입 니 다.그러면 우 리 는 문맥 을 통 해 자신의 대리 대상 이 비동기 적 인 방법 을 호출 할 수 있다.
@Controller
@RequestMapping("/app")
public class EmailController {

    //  ApplicationContext       ,     ,           
    @Autowired
    private ApplicationContext applicationContext;

    @RequestMapping(value = "/email/asyncCall", method = GET)
    @ResponseBody
    public Map<String, Object> asyncCall () {
        Map<String, Object> resMap = new HashMap<String, Object>();
        try{
            //                  
            //this.testAsyncTask();
            //                    
            EmailController emailController = (EmailController)applicationContext.getBean(EmailController.class);
            emailController.testAsyncTask();
            resMap.put("code",200);
        }catch (Exception e) {
            resMap.put("code",400);
            logger.error("error!",e);
        }
        return resMap;
    }

    //     public,   static  
    @Async
    public void testAsyncTask() throws InterruptedException {
        Thread.sleep(10000);
        System.out.println("        !");
    }

}

cglib 대 리 를 열 고 Spring 대리 류 를 수 동 으로 가 져 와 같은 비동기 방법 을 사용 합 니 다.
우선, 시작 클래스 에 @ EnableAspectJAutoProxy (exposeProxy = true) 주 해 를 추가 합 니 다.코드 구현, 다음 과 같 음:
@Service
@Transactional(value = "transactionManager", readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
public class EmailService {

    @Autowired
    private ApplicationContext applicationContext;

    @Async
    public void testSyncTask() throws InterruptedException {
        Thread.sleep(10000);
        System.out.println("        !");
    }


    public void asyncCallTwo() throws InterruptedException {
        //this.testSyncTask();
//        EmailService emailService = (EmailService)applicationContext.getBean(EmailService.class);
//        emailService.testSyncTask();
        boolean isAop = AopUtils.isAopProxy(EmailController.class);//       ;
        boolean isCglib = AopUtils.isCglibProxy(EmailController.class);  //   CGLIB       ;
        boolean isJdk = AopUtils.isJdkDynamicProxy(EmailController.class);  //   JDK           ;
        //      !!!
        EmailService emailService = (EmailService)applicationContext.getBean(EmailService.class);
        EmailService proxy = (EmailService) AopContext.currentProxy();
        System.out.println(emailService == proxy ? true : false);
        proxy.testSyncTask();
        System.out.println("end!!!");
    }
}

좋은 웹페이지 즐겨찾기